fix(workflows): preserve punctuation in filesystem source paths (#521)

* fix(workflows): preserve punctuation in filesystem source paths

Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>

* fix(workflows): share scheme URL pattern in path normalization

---------

Signed-off-by: RudyCelekli <47457359+rudycelekli@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
Rudy Mizrahi Celekli 2026-10-05 03:01:12 -04:00 committed by GitHub
parent 056c123759
commit 5b28a8b331
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 149 additions and 2 deletions

View File

@ -136,6 +136,86 @@ describe("historical source to bundle comparison", () => {
});
});
describe("source to bundle path syntax", () => {
it.each(["src/modified#part.ts", "src/modified?part.ts"])(
"preserves literal filesystem punctuation in %s",
(path) => {
const node = moduleNode("punctuated", { path });
const graph = createJavaScriptApplicationGraph({
schema: "JavaScriptApplicationGraph",
root_node_ids: [node.node_id],
nodes: [node],
edges: [],
coverage: {
status: "complete",
truncated: false,
omitted_count: 0,
limits: [],
},
limitations: [],
});
const result = compareSourceToBundle({
reference: historicalGraph("complete", [path]),
application: {
evidenceId: EVIDENCE_ID,
rootArtifactSha256: HASH.artifact,
graph,
},
});
expect(item(result, path)).toMatchObject({
status: "unknown",
current_node_ids: [node.node_id],
candidates: [
expect.objectContaining({
signals: expect.arrayContaining([
expect.objectContaining({ kind: "current-path-exact" }),
]),
}),
],
});
},
);
it.each([
"https://example.test/src/modified.ts?revision=2#section",
"webpack://fixture/./src/modified.ts?revision=2#section",
])("still strips URL query and fragment from %s", (path) => {
const node = moduleNode("url", { path });
const graph = createJavaScriptApplicationGraph({
schema: "JavaScriptApplicationGraph",
root_node_ids: [node.node_id],
nodes: [node],
edges: [],
coverage: {
status: "complete",
truncated: false,
omitted_count: 0,
limits: [],
},
limitations: [],
});
const result = compareSourceToBundle({
reference: historicalGraph("complete", ["src/modified.ts"]),
application: {
evidenceId: EVIDENCE_ID,
rootArtifactSha256: HASH.artifact,
graph,
},
});
expect(item(result, "src/modified.ts")).toMatchObject({
status: "unknown",
current_node_ids: [node.node_id],
candidates: [
expect.objectContaining({
signals: expect.arrayContaining([
expect.objectContaining({ kind: "current-path-suffix" }),
]),
}),
],
});
});
});
describe("source to bundle complete metadata", () => {
it("accepts long source metadata and all reported limitations", () => {
const result = compareSourceToBundle({

View File

@ -268,9 +268,16 @@ const addPath = (
if (value !== null) paths.push({ kind, value });
};
/** Matches a `scheme://...` URL prefix; bare filesystem paths keep `?`/`#`. */
const SCHEME_URL = /^[a-z][a-z0-9+.-]*:\/\//iu;
/** Matches a `scheme://...` URL prefix with any run of slashes, for stripping. */
const SCHEME_URL_PREFIX = /^[a-z][a-z0-9+.-]*:\/\/+/iu;
const normalizeCurrentPath = (raw: string): string | null => {
const withoutQuery = raw.split(/[?#]/u, 1)[0] ?? "";
const withoutScheme = withoutQuery.replace(/^[a-z][a-z0-9+.-]*:\/\/+/iu, "");
const withoutQuery = SCHEME_URL.test(raw)
? (raw.split(/[?#]/u, 1)[0] ?? "")
: raw;
const withoutScheme = withoutQuery.replace(SCHEME_URL_PREFIX, "");
const parts = withoutScheme
.replaceAll("\\", "/")
.split("/")

View File

@ -0,0 +1,60 @@
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { analyzeJavaScriptApplication } from "../../../src/application/JavaScriptApplicationService.js";
import { parseApplicationGraphEvidence } from "../../../src/application/JavaScriptApplicationEvidenceGraph.js";
import { importReferenceSource } from "../../../src/application/ReferenceSourceImport.js";
import { compareSourceToBundle } from "../../../src/domain/sourceToBundleComparison.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
it("keeps literal hash characters in historical/current filesystem paths", async () => {
const root = await createTestTempDirectory("rea-source-path-");
const previous = join(root, "previous");
const current = join(root, "current");
await Promise.all([mkdir(previous), mkdir(current)]);
await Promise.all([
writeFile(join(previous, "worker#main.js"), "export const value = 1;"),
writeFile(join(current, "worker#main.js"), "export const value = 2;"),
]);
const reference = await importReferenceSource({
root: previous,
caller: "source-to-bundle-path-test",
policy: { secretPatterns: [] },
});
if (!reference.ok) throw new Error(reference.error.message);
const analyzed = await analyzeJavaScriptApplication({ input_path: current });
if (!analyzed.ok) throw analyzed.error;
const application = parseApplicationGraphEvidence(analyzed.value);
const comparison = compareSourceToBundle({
reference: reference.value,
application: {
evidenceId: application.evidence.evidence_id,
rootArtifactSha256: application.rootArtifactSha256,
graph: application.graph,
},
});
expect(reference.value.entries).toContainEqual(
expect.objectContaining({
kind: "file",
path: "worker#main.js",
content_state: "hashed",
}),
);
expect(comparison.items).toContainEqual(
expect.objectContaining({
source_path: "worker#main.js",
candidates: expect.arrayContaining([
expect.objectContaining({
signals: expect.arrayContaining([
expect.objectContaining({
kind: "current-path-exact",
source_value: "worker#main.js",
}),
]),
}),
]),
}),
);
});