Audit evidence bundle
An audit evidence bundle is a generated package that ties each compliance control to the artifact proving it holds (logs, config, chain anchors) cited against the exact clause it satisfies. Caisson's version is a signed, deterministic ZIP: byte-stable manifest, fail-closed on any missing evidence, readiness derived from the evidence itself, never asserted.
In code
// PHASE 1 — flag-never-guess. Scan EVERY control for unresolved evidence before assembling
// anything; refuse the whole pack if any is found. No filesystem touch here → no partial pack.
const unresolved: Array<{
controlId: string;
collectorId: string;
reason: string | undefined;
}> = [];
for (const control of input.controls) {
for (const result of control.evidence) {
if (result.status === "unresolved") {
unresolved.push({
controlId: control.controlId,
collectorId: result.item.collectorId,
reason: result.reason,
});
}
}
}
if (unresolved.length > 0) {
const sortedUnresolved = [...unresolved].sort(
(a, b) =>
cmp(a.controlId, b.controlId) || cmp(a.collectorId, b.collectorId),
);
const report = parseEvidencePackBlocked({
formatVersion: EVIDENCE_PACK_FORMAT_VERSION,
tenantId: input.tenantId,
framework: input.framework,
blocked: true,
unresolved: sortedUnresolved,
});
throw new EvidencePackBlockedError(report);
}How it holds
Fail-closed, not fail-open
generateEvidencePack() scans every control for an unresolved collector result before assembling anything. If even one exists, it throws EvidencePackBlockedError with a structured report of exactly what's missing, no partial or best-effort pack is ever produced.
Readiness is derived, never asserted
A control's readiness ("ready"/"gap") is computed from its evidence items (gap iff any item is flagged) both when the generator builds it and again when pack-format's Zod schema re-validates it. The caller cannot inject a readiness value that disagrees with the evidence.
Byte-stable and signable
The wall clock is injected only onto the outer envelope (generatedAt) and never enters the canonical body. Controls are id-sorted, evidence is collector-id-sorted, and the ZIP writer uses fixed 1980-epoch mtimes and a fixed deflate level, so identical evidence always canonicalizes and archives to the identical SHA-256, independent of who ran it or when.
Bound to the audit chain, not a standalone claim
Every pack pins a chainAnchor {length, tipHash} from the WORM audit chain, and its posture copy is regex-checked to reject the words "compliant"/"certified", the bundle states control-evidence readiness only, never an audit opinion.