fix(release-exposure): match data: source map scheme case-insensitively

URL schemes are case-insensitive, so an inline declaration such as
//# sourceMappingURL=DATA:application/json;base64,... was routed to the
local-reference path, which ignores scheme URLs. Its embedded sources were
silently dropped and source_map_sources reported not_observed.
This commit is contained in:
Matt Van Horn committed 2026-11-01 10:33:55 -08:00
1 parent 5cbed6a184
commit 67c49e9cec
2 files changed
+23 -15

No files matched your search

+21 -14
View File
@@ -199,20 +199,27 @@ describe("ReleaseExposureReader review regressions", () => {
expect((await inspect(path)).source_maps.skipped).toBe(1);
});
it("inspects embedded sources in inline JavaScript maps", async () => {
const root = await createTestTempDirectory("rea-release-exposure-inline-");
const source = `const value = 1;\n//# sourceMappingURL=data:application/json;base64,${embeddedSourceMap().toString("base64")}`;
await writeFile(join(root, "app.js"), source);
const scanned = await inspect(root);
expect(scanned.source_maps).toMatchObject({ embedded: 1, skipped: 0 });
expect(scanned.source_maps.embedded_paths).toEqual([join(root, "app.js")]);
await writeFile(
join(root, "app.asar"),
asarArchive([{ name: "app.js", bytes: Buffer.from(source) }]),
);
const packaged = await inspect(join(root, "app.asar"));
expect(packaged.source_maps).toMatchObject({ embedded: 1, skipped: 0 });
});
it.each(["data", "DATA"])(
"inspects embedded sources in inline JavaScript maps with a %s: scheme",
async (scheme) => {
const root = await createTestTempDirectory(
"rea-release-exposure-inline-",
);
const source = `const value = 1;\n//# sourceMappingURL=${scheme}:application/json;base64,${embeddedSourceMap().toString("base64")}`;
await writeFile(join(root, "app.js"), source);
const scanned = await inspect(root);
expect(scanned.source_maps).toMatchObject({ embedded: 1, skipped: 0 });
expect(scanned.source_maps.embedded_paths).toEqual([
join(root, "app.js"),
]);
await writeFile(
join(root, "app.asar"),
asarArchive([{ name: "app.js", bytes: Buffer.from(source) }]),
);
const packaged = await inspect(join(root, "app.asar"));
expect(packaged.source_maps).toMatchObject({ embedded: 1, skipped: 0 });
},
);
it.each([80, 200, 520, 550])(
"preserves CodeView parsing truncated at %s bytes as unresolved",
+2 -1
View File
@@ -1021,7 +1021,8 @@ const examineInlineMaps = (
const directives = createJavaScriptAnalysisAccumulator(source.length);
addSourceMapDirectives(source, parsed.comments ?? [], directives);
for (const { declared_url: url } of directives.sourceMaps) {
if (!url.startsWith("data:")) {
// URL schemes are case-insensitive (RFC 3986 section 3.1).
if (!/^data:/iu.test(url)) {
noteLocalMapReference(state, member, url);
continue;
}