mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 17:59:08 +00:00
fix(audit): keep an unresolved Electron host's fuses unknown
fuseCheck decided from whatever outcomes the images reported, so a host with no fuse answer read not_observed as soon as any other image in the directory reported safe fuses. Pass the images named as the host into the report and leave a check unknown when one of them has no answer for it. Other images stay free to have no fuses, because helpers in a real Electron install have none.
This commit is contained in:
3 files changed
+61
-1
No files matched your search
@@ -242,6 +242,7 @@ export class ReleaseExposureService {
|
||||
electron_family: family.family,
|
||||
electron_family_reason: family.reason,
|
||||
electron_executable_included: prepared.electronExecutableIncluded,
|
||||
electron_host_paths: prepared.electronHostPaths,
|
||||
fuse_images: fuseImages,
|
||||
go_images: goImages,
|
||||
rust_images: rustImages,
|
||||
@@ -671,6 +672,7 @@ const limitNativeSample = (
|
||||
): {
|
||||
readonly scan: ReleaseExposureScan;
|
||||
readonly electronExecutableIncluded: boolean;
|
||||
readonly electronHostPaths: readonly string[];
|
||||
} => {
|
||||
const ranked = electronExecutableRank(scan.native_images, basisPaths);
|
||||
const preferred = scan.native_images
|
||||
@@ -700,6 +702,11 @@ const limitNativeSample = (
|
||||
preferred.length <= MAX_RELEASE_EXPOSURE_NATIVE_IMAGES);
|
||||
return {
|
||||
electronExecutableIncluded,
|
||||
electronHostPaths: kept.flatMap((image) =>
|
||||
(ranked.get(image.path) ?? ANY_SIBLING_RANK) < ANY_SIBLING_RANK
|
||||
? [image.path]
|
||||
: [],
|
||||
),
|
||||
scan: {
|
||||
...scan,
|
||||
native_images: kept,
|
||||
|
||||
@@ -710,3 +710,46 @@ describe("go.build_paths locations", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("electron host fuses beside other images", () => {
|
||||
const safeImage = {
|
||||
kind: "report" as const,
|
||||
role: "native-image" as const,
|
||||
path: "/work/app/helper",
|
||||
implications: [
|
||||
{ subject: "electron_run_as_node", outcome: "not_honored" },
|
||||
{ subject: "node_cli_inspect_arguments", outcome: "not_honored" },
|
||||
{ subject: "embedded_asar_integrity_validation", outcome: "enforced" },
|
||||
{ subject: "only_load_app_from_asar", outcome: "restricted_to_app_asar" },
|
||||
],
|
||||
};
|
||||
const hostWithoutFuses = {
|
||||
kind: "report" as const,
|
||||
role: "native-image" as const,
|
||||
path: "/work/app/app",
|
||||
implications: [],
|
||||
};
|
||||
const report = (electron_host_paths?: readonly string[]) =>
|
||||
reportFor(
|
||||
scan(),
|
||||
owners({
|
||||
electron_family: "electron",
|
||||
electron_executable_included: true,
|
||||
...(electron_host_paths === undefined ? {} : { electron_host_paths }),
|
||||
fuse_images: [hostWithoutFuses, safeImage],
|
||||
}),
|
||||
);
|
||||
|
||||
it("leaves an unresolved host unknown whatever another image reports", () => {
|
||||
expect(statusOf(report(["/work/app/app"]), "electron.run_as_node")).toBe(
|
||||
"unknown",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not let a fuseless helper unsettle the host's safe answer", () => {
|
||||
expect(statusOf(report(["/work/app/helper"]), "electron.run_as_node")).toBe(
|
||||
"not_observed",
|
||||
);
|
||||
expect(statusOf(report(), "electron.run_as_node")).toBe("not_observed");
|
||||
});
|
||||
});
|
||||
@@ -421,6 +421,8 @@ export interface ReleaseExposureOwnerFacts {
|
||||
| "not_a_directory";
|
||||
readonly electron_family_reason?: string | null;
|
||||
readonly electron_executable_included?: boolean;
|
||||
/** Images named as the Electron host. Others may be helpers with no fuses. */
|
||||
readonly electron_host_paths?: readonly string[];
|
||||
readonly fuse_images: readonly FuseImageFact[];
|
||||
readonly go_images: readonly MetadataImageFact[];
|
||||
readonly rust_images: readonly MetadataImageFact[];
|
||||
@@ -578,13 +580,21 @@ const fuseCheck = (
|
||||
: [],
|
||||
);
|
||||
const failed = images.some((image) => image.kind === "failed");
|
||||
const hostUnresolved = images.some(
|
||||
(image) =>
|
||||
image.kind === "report" &&
|
||||
image.path !== undefined &&
|
||||
owners.electron_host_paths?.includes(image.path) === true &&
|
||||
!(image.implications ?? []).some((item) => item.subject === spec.subject),
|
||||
);
|
||||
const partialFuseSample =
|
||||
nativeImagesMayBeUnread(scan) &&
|
||||
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";
|
||||
else if (outcomes.includes("unknown") || failed) status = "unknown";
|
||||
else if (outcomes.includes("unknown") || failed || hostUnresolved)
|
||||
status = "unknown";
|
||||
else if (outcomes.length > 0 && outcomes.every((item) => item === spec.safe))
|
||||
status = partialFuseSample ? "unknown" : "not_observed";
|
||||
else if (owners.electron_family === "not_a_directory")
|
||||
|
||||
Reference in new issue
Block a user