fix(process): preserve partial evidence and verify detached cleanup (#1011)

* test(ci): allow transport delivery in source identity regression

* fix(process): preserve partial evidence and verify detached cleanup

* fix(process): scope Linux token sweeps by stable process identity

* fix(process): retain environment permission failure codes

* fix(process): wait for signaled processes before verifying cleanup

* fix(process): verify sampled detached groups during cleanup

* fix(electron): preserve prelaunch identities through cleanup

* fix(process): retry growing Darwin process table snapshots

* fix(process): retain compatibility with saved v3 capture evidence

* fix(process): migrate saved v3 captures during reconstruction verification

* fix(process): preserve cancellation during Darwin helper compilation

* fix(process): propagate cancellation through ownership baselines

* perf(javascript): cache canonical export comparison sort keys

* fix(process): cancel provider ownership preparation before spawn

* fix(process): isolate native compiler waiter cancellation
This commit is contained in:
morluto
2026-10-08 04:46:46 +08:00
committed by GitHub
parent 63ba7424c0
commit 63cf28fd8f
51 changed files with 5506 additions and 316 deletions
@@ -2,6 +2,14 @@ import { describe, expect, it } from "vitest";
import { createEvidence } from "../domain/evidence.js";
import { createEvidenceBundle } from "../domain/evidenceBundle.js";
import { emptyUnverifiedProcessCapture } from "../domain/process/processCapture.fixture.js";
import { parseProcessCapture } from "../domain/process/processCapture.js";
import {
digestProcessCommitment,
parseProcessScenario,
processComparisonContract,
processScenarioCommitment,
} from "../domain/process/processScenario.js";
import {
APPLICATION_GRAPH_DIGESTS,
artifactEvidence,
@@ -14,6 +22,7 @@ import {
} from "../domain/javascript/javascriptApplicationGraph.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
import { createProcessCaptureEvidence } from "./process/ProcessEvidence.js";
import { deriveReconstructionObligationCandidates } from "./ReconstructionObligationCandidates.js";
const applicationWithUnknowns = (keys: readonly string[]) => {
@@ -124,4 +133,41 @@ describe("reconstruction obligation candidates", () => {
),
).toBe(false);
});
it("does not bind an unknown process image to a packaged artifact obligation", () => {
const scenario = parseProcessScenario({
executable: "/path/whose-launch-identity-is-unknown",
});
const base = emptyUnverifiedProcessCapture();
const scenarioProjection = processScenarioCommitment(scenario);
const comparisonContract = processComparisonContract(scenario);
const capture = parseProcessCapture({
...base,
normalization: scenario.normalization,
manifest: {
...base.manifest,
scenario: scenarioProjection,
comparison_contract: comparisonContract,
full_scenario_sha256: digestProcessCommitment(scenarioProjection),
comparison_contract_sha256: digestProcessCommitment(comparisonContract),
selected_executable_sha256: null,
executable_sha256: null,
executable_identity: {
state: "unknown",
reason: "Selected executable could not be inspected.",
},
normalization_sha256: digestProcessCommitment(scenario.normalization),
},
});
const evidence = createProcessCaptureEvidence(scenario, capture);
const generated = deriveReconstructionObligationCandidates(
createEvidenceBundle([evidence]),
[],
);
expect(generated.candidates).toEqual([]);
expect(generated.limitations).toContain(
`Process capture ${evidence.evidence_id} has no validated executable artifact identity; packaged-process lifecycle obligation was not bound to an artifact.`,
);
});
});
@@ -176,6 +176,12 @@ const deriveProcessCandidate = (
]
: []),
];
if (capture.manifest.executable_sha256 === null) {
limitations.add(
`Process capture ${evidence.evidence_id} has no validated executable artifact identity; packaged-process lifecycle obligation was not bound to an artifact.`,
);
return;
}
addCandidate(candidates, {
obligation_id: obligationId(
`process:${capture.manifest.executable_sha256}:${capture.manifest.full_scenario_sha256}`,