fix(#91): make fidelity evidence states reproducible

This commit is contained in:
2026-07-29 23:11:37 -04:00
parent 7434621024
commit cefdac7006
4 changed files with 86 additions and 9 deletions

View File

@@ -21,10 +21,17 @@ try {
for (const file of required) await readFile(join(evidence, file))
git('cat-file', '-e', `HEAD:${signoff}`)
const text = await readFile(signoff, 'utf8')
const commit = git('rev-parse', 'HEAD')
const candidate = text.match(/^- Candidate commit: ([0-9a-f]{40})$/mi)?.[1]
if (!candidate) throw new Error(`${signoff} must contain a full candidate commit SHA`)
git('cat-file', '-e', `${candidate}^{commit}`)
const signoffCommit = git('log', '-1', '--format=%H', 'HEAD', '--', signoff)
try {
git('merge-base', '--is-ancestor', candidate, signoffCommit)
} catch {
throw new Error(`${signoff} must be committed after candidate ${candidate}`)
}
const fields = [
['Version', version],
['Candidate commit', commit],
['Reviewed by', '.+'],
['Reviewed on', '\\d{4}-\\d{2}-\\d{2}'],
['Decision', 'approved'],
@@ -34,7 +41,7 @@ try {
throw new Error(`${signoff} must contain "- ${name}: ${value}"`)
}
}
console.log(`Release-fidelity evidence and committed owner approval verified for ${version}.`)
console.log(`Release-fidelity evidence and committed owner approval verified for ${version} at ${candidate}.`)
} catch (error) {
console.error(`Release-fidelity gate blocked: ${error.message}`)
process.exitCode = 1

View File

@@ -0,0 +1,38 @@
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import test from 'node:test'
const verifier = resolve('scripts/release-fidelity/verify.mjs')
function git(directory, ...args) {
return execFileSync('git', args, { cwd: directory, encoding: 'utf8' }).trim()
}
test('accepts a committed sign-off for an ancestor candidate', async () => {
const root = await mkdtemp(join(tmpdir(), 'boxbox-fidelity-verify-'))
git(root, 'init')
git(root, 'config', 'user.email', 'test@example.com')
git(root, 'config', 'user.name', 'Test')
await writeFile(join(root, 'candidate.txt'), 'candidate')
git(root, 'add', 'candidate.txt')
git(root, 'commit', '-m', 'candidate')
const candidate = git(root, 'rev-parse', 'HEAD')
await mkdir(join(root, 'docs/release/owner-reviews'), { recursive: true })
await writeFile(join(root, 'docs/release/owner-reviews/v-test.md'), `- Version: v-test\n- Candidate commit: ${candidate}\n- Reviewed by: Owner\n- Reviewed on: 2026-07-30\n- Decision: approved\n`)
git(root, 'add', 'docs/release/owner-reviews/v-test.md')
git(root, 'commit', '-m', 'owner sign-off')
const evidence = join(root, 'evidence')
await mkdir(evidence)
await writeFile(join(evidence, 'index.html'), '')
await writeFile(join(evidence, 'summary.md'), '')
const output = execFileSync(process.execPath, [verifier, '--version', 'v-test', '--evidence', evidence], {
cwd: root,
encoding: 'utf8',
})
assert.match(output, new RegExp(candidate))
})