* test(#3990): the RED/GREEN/REFACTOR cycle is stated once, embedded conditionally * fix(#3990): state the cycle once — pointers in consumers, conditional tdd.md embeds Emitted-Drift-Ack-Growth: execute-phase.md — #3990 conditions the tdd.md embed on the dispatch being TDD * chore(#3990): changeset for the single-statement TDD cycle * chore(#3990): backfill changeset pr number * fix(#4228): linear cycle check — the lazy-span regex pinned a Windows core for the whole job cap * test(#3990): allowlist pin tracks the rebased line * fix(tests): npm-integrity gate names an empty audit output explicitly — empty stdout crashed the parse as a bare SyntaxError * fix: name an empty npm-audit stdout explicitly — it crashed the parse as a bare SyntaxError Observed on CI (several branches, all lanes): spawnSync npm ETIMEDOUT with empty stdout; the empty string survived the recovery path and surfaced as 'SyntaxError: Unexpected end of JSON input', hiding the captured error. The recovery path now requires non-empty stdout, and an empty result throws with the captured stdout/stderr/message so the actual error is on the record. Root cause of the ETIMEDOUT itself is NOT diagnosed here — this change only stops masking it. --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -105,15 +105,32 @@ function runPackageLockAudit(cwd) {
|
||||
break;
|
||||
} catch (e) {
|
||||
// `npm audit` exits non-zero when advisories are present; the JSON is
|
||||
// still on stdout in that case. Recover and let the caller classify.
|
||||
if (e && typeof e.stdout !== 'undefined' && e.stdout !== undefined && e.stdout !== null) {
|
||||
out = Buffer.isBuffer(e.stdout) ? e.stdout.toString('utf-8') : String(e.stdout);
|
||||
// still on stdout in that case. Recover and let the caller classify —
|
||||
// but only when stdout actually CARRIES the JSON: an audit that was
|
||||
// killed or aborted can exit non-zero with EMPTY stdout, and accepting
|
||||
// the empty string here surfaces as a bare `SyntaxError: Unexpected
|
||||
// end of JSON input` at the parse below, hiding the captured error
|
||||
// (observed on CI 2026-09-03, both lanes; cause undetermined).
|
||||
const recovered = e && typeof e.stdout !== 'undefined' && e.stdout !== null
|
||||
? (Buffer.isBuffer(e.stdout) ? e.stdout.toString('utf-8') : String(e.stdout))
|
||||
: '';
|
||||
if (recovered.trim()) {
|
||||
out = recovered;
|
||||
lastErr = null;
|
||||
break;
|
||||
}
|
||||
lastErr = e;
|
||||
}
|
||||
}
|
||||
if (!out || !out.trim()) {
|
||||
const detail = lastErr
|
||||
? [lastErr.stdout, lastErr.stderr, String(lastErr.message)].filter(Boolean).join('\n').slice(0, 500)
|
||||
: '(no error captured)';
|
||||
throw new Error(
|
||||
`npm audit --json produced no output in ${cwd}. ` +
|
||||
`Detail from the failed invocation:\n${detail}`
|
||||
);
|
||||
}
|
||||
if (lastErr) throw lastErr;
|
||||
const parsed = JSON.parse(out);
|
||||
if (parsed && parsed.metadata && parsed.metadata.vulnerabilities) {
|
||||
|
||||
Reference in New Issue
Block a user