fix(reconstruction): authenticate obligation proof boundaries

This commit is contained in:
morluto 2026-07-24 14:13:36 +00:00
parent eeb4349f1f
commit 7b1e3bda00
3 changed files with 212 additions and 37 deletions

View File

@ -4,6 +4,50 @@ import type { ReconstructionObligation } from "../domain/reconstructionObligatio
type ProofAuthority = ReconstructionObligation["required_fixture_authority"];
type OriginalAuthority =
ReconstructionObligation["required_original_authority"];
type ProofEvidenceShape = readonly [predicate: string, operation: string];
const proofEvidenceShapes: Readonly<
Record<ProofAuthority, readonly ProofEvidenceShape[]>
> = {
unit: [["rea.fixture-verification/v1", "run_fixture_verifier"]],
integration: [["rea.fixture-verification/v1", "run_fixture_verifier"]],
protocol: [["rea.protocol-observation/v1", "observe_protocol"]],
renderer: [
["rea.browser-scenario-capture/v1", "capture_browser_scenario"],
["rea.electron-page-inspection/v1", "inspect_electron_page"],
],
"packaged-process": [
["rea.process-capture/v4", "capture_process_scenario"],
[
"rea.reconstruction-readiness-fixture/v1",
"run_reconstruction_readiness_fixture",
],
],
"native-abi": [
["rea.managed-native-verification/v1", "verify_managed_native_boundaries"],
],
"live-observation": [
["javascript-controlled-replay-observation", "run_controlled_replay"],
["rea.browser-scenario-capture/v1", "capture_browser_scenario"],
["rea.electron-page-inspection/v1", "inspect_electron_page"],
["rea.javascript-runtime-observation/v1", "observe_javascript_runtime"],
["rea.runtime-characterization/v1", "execute_node_characterization"],
],
external: [["rea.protocol-observation/v1", "observe_protocol"]],
};
const proofEvidenceAuthorities: Readonly<
Record<ProofAuthority, readonly Evidence["authority"][]>
> = {
unit: ["shipped-artifact", "controlled-replay"],
integration: ["controlled-replay"],
protocol: ["controlled-replay", "external-service"],
renderer: ["controlled-replay", "external-service"],
"packaged-process": ["controlled-replay"],
"native-abi": ["shipped-artifact", "controlled-replay"],
"live-observation": ["controlled-replay", "external-service"],
external: ["external-service"],
};
/** Return whether an actual reconstruction proof is comparable to a requirement. */
export const proofAuthoritySatisfies = (
@ -46,9 +90,11 @@ export const evidenceAuthoritySupportsProof = (
authority: ProofAuthority,
): boolean =>
evidence.confidence === "observed" &&
(authority === "external"
? evidence.authority === "external-service"
: ["shipped-artifact", "controlled-replay"].includes(evidence.authority));
proofEvidenceAuthorities[authority].includes(evidence.authority) &&
proofEvidenceShapes[authority].some(
([predicate, operation]) =>
evidence.predicate_type === predicate && evidence.operation === operation,
);
/** Check that Evidence observes the original at the required boundary. */
export const evidenceSupportsOriginalAuthority = (

View File

@ -454,35 +454,31 @@ const applyDependencyDiagnostics = (
obligations: readonly ReconstructionObligation[],
context: EvaluationContext,
): ReconstructionObligation[] => {
const statuses = new Map(
obligations.map((obligation) => [
obligation.obligation_id,
obligation.status,
]),
);
return obligations.map((obligation) => {
const diagnostics = [...obligation.diagnostics];
for (const dependencyId of obligation.dependency_obligation_ids) {
if (!context.candidates.has(dependencyId))
addDiagnostic(
diagnostics,
"dependency-missing",
`Dependency obligation is missing: ${dependencyId}.`,
);
else if (statuses.get(dependencyId) !== "verified")
addDiagnostic(
diagnostics,
"dependency-open",
`Dependency obligation is not verified: ${dependencyId}.`,
);
}
const normalized = uniqueDiagnostics(diagnostics);
return {
...obligation,
status: dependencyStatus(obligation.status, normalized),
diagnostics: normalized,
};
});
let evaluated = [...obligations];
for (let pass = 0; pass < obligations.length; pass += 1) {
const statuses = new Map(
evaluated.map(({ obligation_id: id, status }) => [id, status]),
);
let changed = false;
evaluated = evaluated.map((obligation) => {
const diagnostics = [...obligation.diagnostics];
for (const dependencyId of obligation.dependency_obligation_ids) {
const missing = !context.candidates.has(dependencyId);
if (missing || statuses.get(dependencyId) !== "verified")
addDiagnostic(
diagnostics,
missing ? "dependency-missing" : "dependency-open",
`Dependency obligation is ${missing ? "missing" : "not verified"}: ${dependencyId}.`,
);
}
const normalized = uniqueDiagnostics(diagnostics);
const status = dependencyStatus(obligation.status, normalized);
changed ||= status !== obligation.status;
return { ...obligation, status, diagnostics: normalized };
});
if (!changed) break;
}
return evaluated;
};
const obligationStatus = (

View File

@ -256,13 +256,12 @@ describe("reconstruction obligation ledger", () => {
it("closes only when every required case and verifier has comparable authority", () => {
const capture = processEvidence();
const proof = proofEvidence("packaged");
const initial = build(request([capture, proof]));
const initial = build(request([capture]));
const obligation = initial.obligations[0];
if (obligation === undefined)
throw new Error("Expected process obligation");
const result = build(
request([capture, proof], {
request([capture], {
manifest: {
schema_version: 1,
bindings: [
@ -279,7 +278,7 @@ describe("reconstruction obligation ledger", () => {
fixture_id: `packaged.${caseKind}`,
case_kind: caseKind,
authority: "packaged-process",
evidence_ids: [proof.evidence_id],
evidence_ids: [capture.evidence_id],
})),
verifier: {
verifier_id: "verifier.packaged",
@ -287,7 +286,7 @@ describe("reconstruction obligation ledger", () => {
command: "npm run verify:package -- process",
authority: "packaged-process",
status: "pass",
result_evidence_id: proof.evidence_id,
result_evidence_id: capture.evidence_id,
enumerated_obligation_ids: [obligation.obligation_id],
nondeterminism: {
mode: "partial-order",
@ -310,6 +309,140 @@ describe("reconstruction obligation ledger", () => {
expect(result.summary.required_open).toBe(0);
});
it("does not authenticate packaged-process proof with generic replay evidence", () => {
const capture = processEvidence();
const proof = proofEvidence("generic-packaged");
const initial = build(request([capture, proof]));
const obligation = initial.obligations[0];
if (obligation === undefined)
throw new Error("Expected process obligation");
const result = build(
request([capture, proof], {
manifest: {
schema_version: 1,
bindings: [
{
obligation_id: obligation.obligation_id,
owner: {
module_path: "src/processOwner.ts",
symbol: "runProcess",
owner_sha256: "5".repeat(64),
},
parser_type: null,
original_cases: originalCases(obligation, capture.evidence_id),
fixtures: obligation.required_case_kinds.map((caseKind) => ({
fixture_id: `packaged.${caseKind}`,
case_kind: caseKind,
authority: "packaged-process",
evidence_ids: [proof.evidence_id],
})),
verifier: {
verifier_id: "verifier.packaged",
claim_id: "claim.process",
command: "npm run verify:package -- process",
authority: "packaged-process",
status: "pass",
result_evidence_id: proof.evidence_id,
enumerated_obligation_ids: [obligation.obligation_id],
nondeterminism: {
mode: "partial-order",
specification: "Fixture scheduling is partially ordered.",
},
},
},
],
contradictions: [],
},
}),
);
expect(result.obligations[0]?.diagnostics.map(({ code }) => code)).toEqual(
expect.arrayContaining([
"weak-fixture-authority",
"weak-verifier-authority",
]),
);
});
it("propagates an open dependency through the full obligation chain", () => {
const evidence = createEvidence(
undefined,
{ id: "fixture-chain", name: "Fixture chain", version: "1" },
{
predicateType: "rea.fixture-verification/v1",
operation: "run_fixture_verifier",
parameters: {},
result: { passed: true },
confidence: "observed",
authority: "shipped-artifact",
},
);
const ids = ["obl.chain.a", "obl.chain.b", "obl.chain.c"] as const;
const reviewed = ids.map((id, index) => ({
...reviewedObligation(id, evidence.evidence_id),
dependency_obligation_ids:
index === 0 ? [ids[1]] : index === 1 ? [ids[2]] : ["obl.chain.missing"],
}));
const bindings = reviewed.map((obligation) => ({
obligation_id: obligation.obligation_id,
owner: {
module_path: `src/${obligation.obligation_id}.ts`,
symbol: "verify",
owner_sha256: "6".repeat(64),
},
parser_type: null,
original_cases: [
{
kind: "positive" as const,
evidence_id: evidence.evidence_id,
location: "/fixture/positive",
},
],
fixtures: [
{
fixture_id: `fixture.${obligation.obligation_id}`,
case_kind: "positive" as const,
authority: "unit" as const,
evidence_ids: [evidence.evidence_id],
},
],
verifier: {
verifier_id: `verifier.${obligation.obligation_id}`,
claim_id: `claim.${obligation.obligation_id}`,
command: "npm test -- fixture-chain",
authority: "unit" as const,
status: "pass" as const,
result_evidence_id: evidence.evidence_id,
enumerated_obligation_ids: [obligation.obligation_id],
nondeterminism: {
mode: "total-order" as const,
specification: "Fixture execution is ordered.",
},
},
}));
const result = build(
request([evidence], {
reviewed_obligations: reviewed,
manifest: { schema_version: 1, bindings, contradictions: [] },
}),
);
expect(result.obligations.map(({ status }) => status)).toEqual([
"blocked",
"blocked",
"blocked",
]);
expect(
result.obligations.map(({ diagnostics }) =>
diagnostics.map(({ code }) => code),
),
).toEqual([
["dependency-open"],
["dependency-open"],
["dependency-missing"],
]);
});
it("fails closed on parser gaps, ambiguous ownership, and contradiction", () => {
const original = createEvidence(
undefined,