fix(release-exposure): keep fuses unknown on incomplete inventory

A directory inventory that stops at an acquisition limit never reports
the images it did not reach, so the native image sample has no omission
and safe fuses on an included helper settled to not_observed even though
scan coverage was unknown.

Treat unknown coverage like a truncated sample until the Electron
executable is accounted for. A selected native file is that executable,
so it keeps its decided fuse result.
This commit is contained in:
Matt Van Horn committed 2026-11-01 15:26:48 -08:00
1 parent 957f25dc7e
commit ec3d2ed66c
5 files changed
+114 -31

No files matched your search

+1 -1
View File
@@ -58,7 +58,7 @@ A `.map` too large to parse is a linker map when its header cannot begin a JSON
## Status
`exposed` means the check's condition was observed. `not_observed` means that condition was absent in a completed scan. `not_applicable` means the check does not apply to this artifact, for example Electron fuses on an app bundle with no Electron Framework, or on a directory whose native images were all read and hold no fuse sentinel. `unknown` means the check could not be decided, including a directory with no ASAR layout where those reads are missing or incomplete (an `asar: false` Electron build has no ASAR to find), a missing fuse sentinel on an Electron target, a universal binary with a slice that has no sentinel or an undecided fuse, a file that changed after inventory, Electron fuses on a selected ASAR (which does not include the executable that holds them), a PE inside a package that was too large to read, Go or Rust metadata on a native image stored inside a package, and Go or Rust metadata that was not present. Absence of that metadata is not proof the binary is something else. `not_assessed` means this audit did not run the check.
`exposed` means the check's condition was observed. `not_observed` means that condition was absent in a completed scan. `not_applicable` means the check does not apply to this artifact, for example Electron fuses on an app bundle with no Electron Framework, or on a directory whose native images were all read and hold no fuse sentinel. `unknown` means the check could not be decided, including a directory with no ASAR layout where those reads are missing or incomplete (an `asar: false` Electron build has no ASAR to find), safe fuses from an incomplete inventory that has not accounted for the Electron executable, a missing fuse sentinel on an Electron target, a universal binary with a slice that has no sentinel or an undecided fuse, a file that changed after inventory, Electron fuses on a selected ASAR (which does not include the executable that holds them), a PE inside a package that was too large to read, Go or Rust metadata on a native image stored inside a package, and Go or Rust metadata that was not present. Absence of that metadata is not proof the binary is something else. `not_assessed` means this audit did not run the check.
Cancellation during a Go, Rust, fuse, or desktop read returns a typed cancellation error. Its partial observation holds the report with completed facts, and checks whose readers did not run are `unknown`. Cancellation during the member scan itself returns no partial report.
@@ -745,24 +745,36 @@ describe("ReleaseExposureService fuse sampling", () => {
});
});
const directoryScan = (paths: readonly string[]) => {
const images = paths.map((path) => ({ path, format: "elf" as const }));
return scan({
target: {
selected_path: "/work/app",
kind: "directory",
format: "directory",
sha256: null,
},
subject: { path: "/work/app", sha256: SHA, format: "directory" },
native_images: images,
fuse_candidates: images.map((image) => ({
path: image.path,
role: "native-image" as const,
})),
});
};
const runAsNode = async (
service: ReleaseExposureService,
path = "/work/app",
) => {
const result = await service.inspect({ path });
if (!result.ok) throw result.error;
return releaseExposureReportSchema
.parse(result.value.normalized_result)
.checks.find((check) => check.id === "electron.run_as_node");
};
describe("ReleaseExposureService Electron applicability", () => {
const directoryScan = (paths: readonly string[]) => {
const images = paths.map((path) => ({ path, format: "elf" as const }));
return scan({
target: {
selected_path: "/work/app",
kind: "directory",
format: "directory",
sha256: null,
},
subject: { path: "/work/app", sha256: SHA, format: "directory" },
native_images: images,
fuse_candidates: images.map((image) => ({
path: image.path,
role: "native-image" as const,
})),
});
};
const appScan = scan({
target: {
selected_path: "/work/App.app",
@@ -783,16 +795,6 @@ describe("ReleaseExposureService Electron applicability", () => {
},
],
});
const runAsNode = async (
service: ReleaseExposureService,
path = "/work/app",
) => {
const result = await service.inspect({ path });
if (!result.ok) throw result.error;
return releaseExposureReportSchema
.parse(result.value.normalized_result)
.checks.find((check) => check.id === "electron.run_as_node");
};
const noSentinel = ok(evidence(fuseReport([slice(0, { sentinels: 0 })])));
const unreadable = err(new AnalysisInputError("inspect_electron_fuses"));
@@ -806,6 +808,49 @@ describe("ReleaseExposureService Electron applicability", () => {
expect((await runAsNode(service))?.status).toBe("not_observed");
});
it("keeps safe fuses unknown when inventory may have missed the executable", async () => {
const { service, electronFuses } = owners({
...directoryScan(["/work/app/helper"]),
coverage: "unknown",
});
electronFuses.inspect.mockResolvedValue(
ok(evidence(fuseReport([slice(0)]))),
);
expect((await runAsNode(service))?.status).toBe("unknown");
});
it("keeps safe fuses decided when inventory stopped after the hinted executable", async () => {
const { service, desktop, electronFuses } = owners({
...directoryScan(["/work/app/MyApp.exe"]),
coverage: "unknown",
});
desktop.inspect.mockResolvedValue(ok(evidence(electronDesktopReport())));
electronFuses.inspect.mockResolvedValue(
ok(evidence(fuseReport([slice(0)]))),
);
expect((await runAsNode(service))?.status).toBe("not_observed");
});
it("keeps safe fuses decided on a selected executable with unknown inventory", async () => {
const { service, electronFuses } = owners(
scan({
target: {
selected_path: "/work/app",
kind: "executable",
format: "elf",
sha256: SHA,
},
native_images: [{ path: "/work/app", format: "elf" }],
fuse_candidates: [{ path: "/work/app", role: "native-image" }],
coverage: "unknown",
}),
);
electronFuses.inspect.mockResolvedValue(
ok(evidence(fuseReport([slice(0)]))),
);
expect((await runAsNode(service))?.status).toBe("not_observed");
});
it("does not hide a failed fuse read behind a missing ASAR hint", async () => {
const { service, electronFuses } = owners(
directoryScan(["/work/app/electron"]),
@@ -662,7 +662,11 @@ const limitNativeSample = (
const electronExecutableIncluded =
scan.target.kind === "app" ||
scan.fuse_candidates.some((candidate) => candidate.role === "app-bundle") ||
kept.some((image) => preferredPaths.has(image.path));
kept.some(
(image) =>
preferredPaths.has(image.path) ||
image.path === scan.target.selected_path,
);
return {
electronExecutableIncluded,
scan: {
+31
View File
@@ -370,6 +370,37 @@ describe("release exposure fuse sampling", () => {
);
expect(statusOf(included, "electron.run_as_node")).toBe("not_observed");
});
it("does not treat incomplete inventory as an absent fuse", () => {
const fuseFacts = {
electron_family: "electron" as const,
fuse_images: [
{
kind: "report" as const,
role: "native-image" as const,
implications: [
{ subject: "electron_run_as_node", outcome: "not_honored" },
],
},
],
};
const incomplete = scan({ coverage: "unknown" });
expect(
statusOf(
reportFor(incomplete, owners(fuseFacts)),
"electron.run_as_node",
),
).toBe("unknown");
expect(
statusOf(
reportFor(
incomplete,
owners({ ...fuseFacts, electron_executable_included: true }),
),
"electron.run_as_node",
),
).toBe("not_observed");
});
});
describe("release exposure package checks", () => {
+5 -2
View File
@@ -562,10 +562,13 @@ const fuseCheck = (
: [],
);
const failed = images.some((image) => image.kind === "failed");
const partialFuseSample =
const unreadImagePossible =
scan.coverage === "unknown" ||
scan.omitted.some(
(item) => item.subject === "native images" && item.count > 0,
) && owners.electron_executable_included !== true;
);
const partialFuseSample =
unreadImagePossible && owners.electron_executable_included !== true;
let status: Status;
if (outcomes.includes(spec.exposed)) status = "exposed";
else if (owners.electron_family === "not_electron") status = "not_applicable";