fix(audit): keep a .map unsettled once a declaration was discarded

This commit is contained in:
Matt Van Horn committed 2026-11-03 10:07:39 -08:00
1 parent da5ecd81bd
commit 02cd0e9360
2 files changed
+35 -2

No files matched your search

@@ -3223,6 +3223,27 @@ describe("ReleaseExposureReader map target allowance", () => {
expect(scanned.source_maps.embedded).toBe(0);
expect(sourceMapSourcesStatus(scanned)).toBe("unknown");
});
it("does not read a .map past the target allowance as a linker map", async () => {
const root = await createTestTempDirectory("rea-release-exposure-maps-");
const folder = join(
root,
...Array.from({ length: 4 }, () => "d".repeat(200)),
);
await mkdir(folder, { recursive: true });
const declarations = Array.from(
{ length: Math.ceil(MAX_RELEASE_EXPOSURE_MAP_TARGET_BYTES / 800) + 1 },
(_, index) => `//# sourceMappingURL=m${String(index)}`,
);
await writeFile(
join(folder, "a.js"),
`${declarations.join("\n")}\n//# sourceMappingURL=z.map\n`,
);
await writeFile(join(folder, "z.map"), "not a map\n");
const scanned = await inspect(root);
expect(scanned.debug_companions.paths).toEqual([]);
expect(scanned.source_maps.skipped).toBeGreaterThan(0);
});
});
describe("ReleaseExposureReader HTML script references", () => {
+14 -2
View File
@@ -772,6 +772,11 @@ interface ScanState {
/** Bytes of resolved path offered to `scriptTargets`, kept or refused. */
scriptTargetBytes: number;
mapTargetBytes: number;
/**
* A declared map target was refused by the allowance. A later `.map` may be
* that target, so it can no longer settle as a linker map.
*/
mapTargetsDiscarded: boolean;
/** Members already examined as a script. */
examinedScripts: Set<string>;
visitText: ReleaseExposureTextVisitor;
@@ -817,6 +822,7 @@ const createState = (visitText: ReleaseExposureTextVisitor): ScanState => ({
scriptTargets: new Set(),
scriptTargetBytes: 0,
mapTargetBytes: 0,
mapTargetsDiscarded: false,
examinedScripts: new Set(),
visitText,
});
@@ -1526,9 +1532,10 @@ const noteMapTarget = (state: ScanState, location: string): void => {
return;
}
state.mapTargetBytes += Buffer.byteLength(target);
if (state.mapTargetBytes > MAX_RELEASE_EXPOSURE_MAP_TARGET_BYTES)
if (state.mapTargetBytes > MAX_RELEASE_EXPOSURE_MAP_TARGET_BYTES) {
state.skippedMaps += 1;
else state.mapTargets.add(target);
state.mapTargetsDiscarded = true;
} else state.mapTargets.add(target);
};
/**
@@ -1540,6 +1547,11 @@ const memberLocationKey = (location: string): string =>
logicalPathNfc(resolve(location));
const noteLinkerMapGuess = (state: ScanState, location: string): void => {
// Once a declaration was discarded, this map may be its target.
if (state.mapTargetsDiscarded) {
state.skippedMaps += 1;
return;
}
const key = memberLocationKey(location);
const paths = state.linkerMapGuesses.get(key) ?? new Set();
state.linkerMapGuesses.set(key, paths.add(location));