61 lines
2.3 KiB
JavaScript
61 lines
2.3 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { readFile } from 'node:fs/promises';
|
|
import test from 'node:test';
|
|
|
|
const TARGETS = [
|
|
'tools/matrix-presence-harness/run.sh',
|
|
'tools/e2e-install-test.sh',
|
|
'tools/install.sh',
|
|
'scripts/agent/session-start.sh',
|
|
'scripts/analysis/reflect-board-history.sh',
|
|
'scripts/analysis/reflect-git-history.sh',
|
|
'packages/mosaic/framework/templates/repo/scripts/agent/session-start.sh',
|
|
'packages/mosaic/framework/tools/authentik/user-create.sh',
|
|
'packages/mosaic/framework/tools/git/mutate-push-guard.sh',
|
|
'packages/mosaic/framework/tools/orchestrator/session-resume.sh',
|
|
'packages/mosaic/framework/tools/prdy/prdy-status.sh',
|
|
'packages/mosaic/framework/tools/qa/reflect-stop-hook.sh',
|
|
'packages/mosaic/framework/tools/qa/typecheck-hook.sh',
|
|
'packages/mosaic/framework/tools/tmux/send-message.sh',
|
|
'packages/mosaic/framework/tools/wake/detector.sh',
|
|
'packages/mosaic/framework/tools/wake/digest.sh',
|
|
'packages/mosaic/framework/tools/wake/reconcile.sh',
|
|
];
|
|
|
|
// These statuses are explicitly non-load-bearing or unreachable at designed input.
|
|
// They remain inventoried until the final #1099 tranche records every verdict.
|
|
const ACCEPTED = [
|
|
['tools/install.sh', 'mosaic-bak-', '|| true'],
|
|
['tools/install.sh', 'mosaicstack-mosaic-*.tgz', 'head -1'],
|
|
['tools/install.sh', 'mosaicstack-gateway-*.tgz', 'head -1'],
|
|
['scripts/agent/session-start.sh', 'docs/scratchpads/*.md', '|| true'],
|
|
[
|
|
'packages/mosaic/framework/templates/repo/scripts/agent/session-start.sh',
|
|
'docs/scratchpads/*.md',
|
|
'|| true',
|
|
],
|
|
];
|
|
|
|
const earlyExit =
|
|
/(?<!\|)\|(?!\|)[^;\n]*(?:grep\b[^;\n]*(?:-[A-Za-z]*q|--quiet|-m\s*1)|head\b(?:\s|$))/;
|
|
|
|
test('load-bearing pipefail paths do not pipe into early-exiting consumers', async () => {
|
|
const found = [];
|
|
for (const file of TARGETS) {
|
|
const source = (await readFile(new URL(`../${file}`, import.meta.url), 'utf8')).replace(
|
|
/\\\n\s*/g,
|
|
' ',
|
|
);
|
|
for (const rawLine of source.split('\n')) {
|
|
const line = rawLine.trim();
|
|
if (!earlyExit.test(line)) continue;
|
|
const accepted = ACCEPTED.some(
|
|
([acceptedFile, ...fragments]) =>
|
|
acceptedFile === file && fragments.every((item) => line.includes(item)),
|
|
);
|
|
if (!accepted) found.push(`${file}:${line}`);
|
|
}
|
|
}
|
|
assert.deepEqual(found, []);
|
|
});
|