feat(javascript): record Electron integrity mismatches

This commit is contained in:
morluto committed 2026-10-10 02:49:46 +08:00
1 parent f0dc233d64
commit 7915ee5178
21 files changed
+429 -35

No files matched your search

@@ -90,4 +90,5 @@ const parameters = (
input: AnalyzeJavaScriptApplicationInput,
): EvidenceObservation["parameters"] => ({
format: input.format,
integrity_policy: input.integrity_policy,
});
@@ -60,6 +60,7 @@ export const analyzeJavaScriptApplicationValidated = async (
{
input_path: input.input_path,
format: input.format,
integrity_policy: input.integrity_policy,
},
options.signal,
options.progress,
@@ -140,6 +140,13 @@ const graphCoverage = (context: JavaScriptArtifactGraphContext) => {
null,
);
if (unknownGap) return partialApplicationCoverage([], null);
if (context.snapshot.integrity_contradictions.length > 0) {
const nestedArchiveWasOpaque =
context.snapshot.integrity_contradictions.some(({ logical_path }) =>
logical_path.toLowerCase().endsWith(".asar"),
);
return partialApplicationCoverage([], nestedArchiveWasOpaque ? null : 0);
}
return completeApplicationCoverage();
};
@@ -178,6 +185,10 @@ const graphLimitations = (
);
return [
...context.analysis.limitations,
...context.snapshot.integrity_contradictions.map(
({ logical_path: path }) =>
`Artifact integrity metadata contradicts observed bytes at ${path}; the observed bytes are untrusted.`,
),
...selfReferenceOmissions(
relationshipOmissions.selfImports,
["import specifier", "import specifiers"],
@@ -11,6 +11,7 @@ import { createJavaScriptArtifactReader as createReader } from "../../artifacts/
import type { JavaScriptApplicationGraph } from "../../domain/javascript/javascriptApplicationGraph.js";
import type { JavaScriptSemanticGraph } from "../../domain/javascript/javascriptSemanticGraph.js";
import type { ElectronBoundarySummary } from "../../domain/javascript/javascriptApplicationAnalysis.js";
import type { ArtifactInventorySnapshot } from "../../domain/artifactInventorySnapshot.js";
import { analyzeAndProjectJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
import { readJavaScriptArtifactFiles } from "../../artifacts/javascript/JavaScriptArtifactFiles.js";
import { buildImmutableJavaScriptArtifactGraphSteps } from "./JavaScriptArtifactGraphBuilder.js";
@@ -34,6 +35,7 @@ export interface JavaScriptArtifactReconstructionResult {
readonly root_artifact_sha256: string;
readonly inventory_manifest_id: string;
readonly inventory_graph_sha256: string;
readonly integrity_contradictions: ArtifactInventorySnapshot["integrity_contradictions"];
readonly graph: JavaScriptApplicationGraph;
readonly semantic_graph: JavaScriptSemanticGraph;
readonly electron_summary: ElectronBoundarySummary;
@@ -66,7 +68,10 @@ export const reconstructJavaScriptArtifact = async (
abortIfNeeded(signal);
const path = await resolveSelectedInput(input.input_path);
const format = await resolveFormat(path, input);
const snapshot = await scanCanonicalArtifactInventory(path, { signal });
const snapshot = await scanCanonicalArtifactInventory(path, {
signal,
integrity: { mode: input.integrity_policy },
});
if (snapshot.manifest.root_format !== format)
throw new ArtifactReaderFailure(
"format",
@@ -141,6 +146,7 @@ export const reconstructJavaScriptArtifact = async (
root_artifact_sha256: snapshot.manifest.root_sha256,
inventory_manifest_id: snapshot.manifest.manifest_id,
inventory_graph_sha256: snapshot.manifest.graph_sha256,
integrity_contradictions: snapshot.integrity_contradictions,
graph,
semantic_graph: semanticGraph,
electron_summary: summarizeElectronBoundaries(analysis),
@@ -4,6 +4,7 @@ import { z } from "zod";
export const javascriptArtifactReconstructionInputSchema = z.strictObject({
input_path: z.string().min(1),
format: z.enum(["auto", "asar", "directory"]).default("auto"),
integrity_policy: z.enum(["fail", "record-and-continue"]).default("fail"),
});
/** Parsed local reconstruction request. */