54 lines
3.7 KiB
JavaScript
54 lines
3.7 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { createHash } from 'node:crypto'
|
|
import { auditEvidence, checkLegacyConsistency } from './acceptance-evidence-audit.mjs'
|
|
|
|
function fixture(change = {}) {
|
|
const report = { level: 'http', domain: 'carrier-schedule', revision: 'build-1',
|
|
runId: 'run-1', success: true, steps: [{ name: 'hold-preserves-normal-node',
|
|
requirementId: 'C66', passed: true, requestId: 'request-1', marker: 'run-1' }], ...change }
|
|
const bytes = Buffer.from(JSON.stringify(report))
|
|
return { manifest: { version: 1, scope: 'carrier-exceptions', revision: 'build-1', requirements: [{
|
|
id: 'C66', domain: 'carrier-schedule', level: 'http', checks: ['hold-preserves-normal-node'],
|
|
evidence: { path: 'report.json', sha256: createHash('sha256').update(bytes).digest('hex') },
|
|
}] }, load: () => bytes }
|
|
}
|
|
test('exact required check, runtime identity, domain, level and revision pass together', () => {
|
|
const f = fixture(); assert.equal(auditEvidence(f.manifest, f.load).completionClaim, true)
|
|
})
|
|
for (const [label, change, reason] of [
|
|
['unit test is not HTTP acceptance', { level: 'unit' }, 'EVIDENCE_LEVEL_MISMATCH'],
|
|
['customs exception is not carrier exception', { domain: 'customs' }, 'BUSINESS_DOMAIN_MISMATCH'],
|
|
['old deployment is not current deployment', { revision: 'old' }, 'REVISION_MISMATCH'],
|
|
['explicit incomplete claim wins over success', { completionClaim: false }, 'REPORT_NOT_COMPLETE'],
|
|
['nonzero failures block', { summary: { failed: 1 } }, 'REPORT_NOT_COMPLETE'],
|
|
['partial evidence cannot claim full scope', { completionClaim: true, summary: { allConditionsComplete: true, checkedScopeEvidence: 65, requirements: 77 } }, 'CONTRADICTORY_REPORT'],
|
|
['coverage blocker is never green', { coverageGaps: [{ blocking: true }] }, 'BLOCKING_GAP'],
|
|
['skipped module is not complete', { summary: { skippedModules: 1 } }, 'REPORT_NOT_COMPLETE'],
|
|
['request ID cannot be absent', { steps: [{ name: 'hold-preserves-normal-node', requirementId: 'C66', passed: true }] }, 'MISSING_RUNTIME_IDENTITY:hold-preserves-normal-node'],
|
|
['unrelated green step is not matching evidence', { steps: [{ name: 'other', passed: true }] }, 'CHECK_NOT_PROVEN:hold-preserves-normal-node'],
|
|
]) test(label, () => {
|
|
const f = fixture(change), result = auditEvidence(f.manifest, f.load)
|
|
assert.equal(result.completionClaim, false)
|
|
assert.ok(result.results[0].reasons.includes(reason))
|
|
})
|
|
test('hash mismatch and nonexistent artifact fail closed', () => {
|
|
const f = fixture(); f.manifest.requirements[0].evidence.sha256 = '0'.repeat(64)
|
|
assert.ok(auditEvidence(f.manifest, f.load).results[0].reasons.includes('HASH_MISMATCH'))
|
|
assert.equal(auditEvidence(f.manifest, () => { throw new Error('missing') }).completionClaim, false)
|
|
})
|
|
test('missing and duplicated requirements cannot silently reduce the scope', () => {
|
|
const f = fixture(); f.manifest.requirements.push(f.manifest.requirements[0])
|
|
assert.throws(() => auditEvidence(f.manifest, f.load))
|
|
f.manifest.requirements = []; assert.throws(() => auditEvidence(f.manifest, f.load))
|
|
})
|
|
test('duplicate matching steps cannot masquerade as one unambiguous proof', () => {
|
|
const f = fixture(), r = JSON.parse(f.load()); r.steps.push(r.steps[0])
|
|
const changed = fixture({ steps: r.steps }); assert.equal(auditEvidence(changed.manifest, changed.load).completionClaim, false)
|
|
})
|
|
test('September r7 contradiction is rejected without rewriting original evidence', () => {
|
|
assert.deepEqual(checkLegacyConsistency({ completionClaim: false, summary: {
|
|
allConditionsComplete: true, checkedScopeEvidence: 65, requirements: 77,
|
|
} }).reasons, ['CONTRADICTORY_COMPLETION', 'INCOMPLETE_CHECKED_SCOPE'])
|
|
})
|