mirror of
https://github.com/morluto/rea.git
synced 2026-11-03 13:26:10 +00:00
* test: strengthen and prune audited test coverage * test: require delivered DeepSeek skill instructions * test: keep schema fixture types private * test: verify Gemini receives skill instructions * test: bind Qwen skill evidence to its tool result * test: report NativeAOT verifier checks precisely * fix: verify Ghidra cleanup paths reliably * fix: verify Command Code skill activation * test: tighten cleanup and fixture checks * test: verify packet capture evidence is recorded * fix: report HTTP3 capture provenance accurately * test: preserve resource coverage through MCP * test: prune repeated assertions and retain cancellation identity * fix: validate client verifier fixture paths * test: skip Copilot verifier cases on Windows * test: keep verifier setup target relative
180 lines
5.6 KiB
JavaScript
180 lines
5.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { realpath } from "node:fs/promises";
|
|
import { parseArgs } from "node:util";
|
|
|
|
import { readStableArtifact } from "../../../dist/artifacts/readStableArtifact.js";
|
|
import { ArtifactReaderFailure } from "../../../dist/artifacts/ArtifactReader.js";
|
|
import { ArtifactResourceScope } from "../../../dist/artifacts/ArtifactResourceScope.js";
|
|
import {
|
|
ArtifactFileCleanupFailure,
|
|
artifactFileCompletion,
|
|
artifactFilePrimaryFacts,
|
|
} from "../../../dist/artifacts/ArtifactFileOperation.js";
|
|
|
|
import { reconcileJavaScriptRuntimeEvidence } from "../../../dist/application/javascript/JavaScriptRuntimeReconciliationService.js";
|
|
import { analyzeJavaScriptApplicationWithOwnedScope } from "../../lib/javascript-application-analysis.mjs";
|
|
import {
|
|
completeVerifierRun,
|
|
createVerifierRun,
|
|
} from "../../lib/verifier-run.mjs";
|
|
|
|
const verifierRun = createVerifierRun();
|
|
|
|
const options = parseArgs({
|
|
options: {
|
|
application: { type: "string" },
|
|
cache: { type: "string", multiple: true, default: [] },
|
|
assets: { type: "string", multiple: true, default: [] },
|
|
"runtime-evidence": { type: "string", multiple: true, default: [] },
|
|
mapping: { type: "string", multiple: true, default: [] },
|
|
},
|
|
strict: true,
|
|
allowPositionals: false,
|
|
}).values;
|
|
|
|
if (options.application === undefined)
|
|
throw new Error("--application must name an operator-provided app/ASAR path");
|
|
if (options["runtime-evidence"].length === 0)
|
|
throw new Error(
|
|
"At least one --runtime-evidence path from inspect_web_page or inspect_electron_page is required",
|
|
);
|
|
|
|
const requestedLayers = [
|
|
{ role: "application", path: options.application },
|
|
...options.cache.map((path) => ({ role: "cache", path })),
|
|
...options.assets.map((path) => ({ role: "assets", path })),
|
|
];
|
|
const staticLayers = [];
|
|
for (const layer of requestedLayers) {
|
|
const analyzed = await analyzeJavaScriptApplicationWithOwnedScope({
|
|
input_path: layer.path,
|
|
format: "auto",
|
|
});
|
|
staticLayers.push({
|
|
role: layer.role,
|
|
analysis: analyzed,
|
|
runtime_mappings: [],
|
|
});
|
|
}
|
|
for (const encoded of options.mapping) {
|
|
const mapping = parseMapping(encoded, staticLayers.length);
|
|
staticLayers[mapping.layer].runtime_mappings.push(mapping.value);
|
|
}
|
|
const runtimeObservations = [];
|
|
for (const path of options["runtime-evidence"]) {
|
|
const observations = await readEvidenceFile(path);
|
|
for (const observation of observations) runtimeObservations.push(observation);
|
|
}
|
|
const reconciled = reconcileJavaScriptRuntimeEvidence({
|
|
static_layers: staticLayers,
|
|
runtime_observations: runtimeObservations,
|
|
});
|
|
if (!reconciled.ok) throw reconciled.error;
|
|
const result = reconciled.value.evidence.normalized_result;
|
|
|
|
process.stdout.write(
|
|
`${JSON.stringify({
|
|
verifier_run: await completeVerifierRun(verifierRun),
|
|
reconciliation_id: result.reconciliation_id,
|
|
evidence_id: reconciled.value.evidence.evidence_id,
|
|
graph_id: result.graph.graph_id,
|
|
layers: result.static_layers.map((layer) => ({
|
|
role: layer.role,
|
|
evidence_id: layer.evidence_id,
|
|
graph_id: layer.graph_id,
|
|
root_artifact_sha256: layer.root_artifact_sha256,
|
|
input_path: layer.input_path,
|
|
})),
|
|
runtime_captures: result.runtime_captures.map((capture) => ({
|
|
evidence_id: capture.evidence_id,
|
|
capture_sha256: capture.capture_sha256,
|
|
target_location: capture.target_location,
|
|
})),
|
|
summary: result.summary,
|
|
coverage: result.coverage,
|
|
unmatched_reasons: counted(
|
|
result.reconciliations
|
|
.filter(({ status }) => status !== "matched")
|
|
.map(({ reason }) => reason),
|
|
),
|
|
static_load_states: counted(
|
|
result.static_load_states.map(({ status }) => status),
|
|
),
|
|
verified: true,
|
|
})}\n`,
|
|
);
|
|
|
|
async function readEvidenceFile(path) {
|
|
const scope = new ArtifactResourceScope();
|
|
let outcome;
|
|
try {
|
|
outcome = {
|
|
ok: true,
|
|
value: await readStableArtifact(
|
|
await realpath(path),
|
|
64 * 1024 * 1024,
|
|
undefined,
|
|
undefined,
|
|
scope,
|
|
),
|
|
};
|
|
} catch (cause) {
|
|
outcome = { ok: false, cause };
|
|
}
|
|
try {
|
|
await scope.close();
|
|
} catch (cleanupCause) {
|
|
if (!outcome.ok)
|
|
throw new AggregateError(
|
|
[outcome.cause, cleanupCause],
|
|
"Verifier cleanup failed",
|
|
{ cause: outcome.cause },
|
|
);
|
|
throw cleanupCause;
|
|
}
|
|
if (!outcome.ok && outcome.cause instanceof ArtifactFileCleanupFailure) {
|
|
const completion = artifactFileCompletion(outcome.cause);
|
|
outcome =
|
|
completion === undefined
|
|
? { ok: false, cause: artifactFilePrimaryFacts(outcome.cause).cause }
|
|
: { ok: true, value: completion.value };
|
|
}
|
|
if (!outcome.ok) {
|
|
const cause = outcome.cause;
|
|
if (cause instanceof ArtifactReaderFailure && cause.reason === "limit")
|
|
throw new Error(`Runtime Evidence exceeds 64 MiB: ${path}`, { cause });
|
|
throw cause;
|
|
}
|
|
const value = JSON.parse(outcome.value.bytes.toString("utf8"));
|
|
return Array.isArray(value) ? value : [value];
|
|
}
|
|
|
|
function parseMapping(encoded, layerCount) {
|
|
const parsed = JSON.parse(encoded);
|
|
if (
|
|
typeof parsed !== "object" ||
|
|
parsed === null ||
|
|
!Number.isInteger(parsed.layer) ||
|
|
parsed.layer < 0 ||
|
|
parsed.layer >= layerCount ||
|
|
(parsed.kind !== "file-root" && parsed.kind !== "url-prefix")
|
|
)
|
|
throw new Error(
|
|
"--mapping must be JSON with a valid layer index and file-root or url-prefix kind",
|
|
);
|
|
const { layer, ...value } = parsed;
|
|
return { layer, value };
|
|
}
|
|
|
|
function counted(values) {
|
|
return Object.fromEntries(
|
|
[...new Set(values)]
|
|
.sort()
|
|
.map((value) => [
|
|
value,
|
|
values.filter((candidate) => candidate === value).length,
|
|
]),
|
|
);
|
|
}
|