fix(verification): the done line and the release check take only full commit ids

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-26 13:33:51 +01:00
commit e279f12131
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 73 additions and 8 deletions

View file

@ -91,3 +91,32 @@ test('done line: --check finds the line for that step only', () => {
assert.equal(run(['--check', '--step', '4', '--report', report]).status, 1);
} finally { rmSync(dir, { recursive: true, force: true }); }
});
// ---- M11 sibling: only a full 40- or 64-hex commit id ----
test('[M11] sibling: the done line accepts a 64-hex commit id', () => {
// A SHA-256 repository writes a 64-hex HEAD into the line; --check must read it.
const dir = mkdtempSync(join(tmpdir(), 'done-line-sha256-'));
const report = join(dir, 'step-3.report.md');
const sha = '0123abcd'.padEnd(64, 'e');
try {
writeFileSync(report, `# Step 3 report\nDONE step 3: \`node --test tests/ok.test.mjs\` exit 0 at ${sha} 2026-10-06T12:00:00.000Z\n`);
const plain = run(['--check', '--step', '3', '--report', report]);
assert.equal(plain.status, 0, `a 64-hex line is a done line: ${plain.stdout}${plain.stderr}`);
const bound = run(['--check', '--step', '3', '--report', report, '--commit', sha]);
assert.equal(bound.status, 0, `the line at that 64-hex commit: ${bound.stdout}${bound.stderr}`);
} finally { rmSync(dir, { recursive: true, force: true }); }
});
test('[M11] sibling: the done line refuses a 7-hex id given with --commit, naming 40 or 64 hex', () => {
// A short id can also be a branch name (DJ3); a line typed at a short id
// must not pass the check bound to that short id.
const dir = mkdtempSync(join(tmpdir(), 'done-line-short-'));
const report = join(dir, 'step-3.report.md');
try {
writeFileSync(report, '# Step 3 report\nDONE step 3: `node --test tests/ok.test.mjs` exit 0 at deadbee 2026-10-06T12:00:00.000Z\n');
const r = run(['--check', '--step', '3', '--report', report, '--commit', 'deadbee']);
assert.equal(r.status, 2, `a 7-hex --commit could not be checked (exit 2, never green): ${r.stdout}${r.stderr}`);
assert.match(r.stdout + r.stderr, /40 or 64 hex/, `the refusal names 40 or 64 hex: ${r.stdout}${r.stderr}`);
} finally { rmSync(dir, { recursive: true, force: true }); }
});

View file

@ -536,3 +536,21 @@ test('release-check r9 / bdd46799 — one review.md reached through a symlinked
assert.equal(r.status, 0, r.stdout + r.stderr);
} finally { rmSync(link, { force: true }); fx.cleanup(); }
});
// ==== fix round 4.5b: only a full 40- or 64-hex commit id (M11 sibling) ======
test('[M11] sibling: the release check refuses a 64-hex branch name in a SHA-1 repository with the reason "(a full 40- or 64-hex commit id)"', () => {
// In a SHA-1 repository a 64-hex name is no object id; git resolves it as a
// ref name to wherever the branch points, so coverage would pass a review
// of whatever the branch is moved to.
const name = 'c0ffee'.padEnd(64, '0');
const fx = fixture({ reviewSha: name });
try {
git(fx.repo, 'branch', name, 'HEAD~1');
const r = run(fx, ['--json']);
assert.equal(r.status, 1, r.stdout + r.stderr);
const coverage = JSON.parse(r.stdout).checks.find((c) => c.id === 'coverage');
assert.equal(coverage.status, 'fail', JSON.stringify(coverage));
assert.ok(coverage.detail.includes('(a full 40- or 64-hex commit id)'), `the reason names a full commit id: ${coverage.detail}`);
} finally { fx.cleanup(); }
});