fix(javascript): preserve POSIX runtime path case on Windows (#2422)

Use POSIX path semantics for recorded POSIX roots when reconciling runtime Evidence on Windows. Preserve Windows mapping behavior and cover implicit and explicit file roots through the reconciliation service.

Assisted-by: OpenAI GPT-6 <noreply@openai.com>

Co-authored-by: Aurantium-47 <280805072+Aurantium-47@users.noreply.github.com>
This commit is contained in:
Aurantium 2026-10-12 23:46:28 -07:00 committed by GitHub
parent 12303812a8
commit 1a1b67c888
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 70 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { posix, relative, win32 } from "node:path";
import { posix, win32 } from "node:path";
import type { ApplicationNode } from "./javascriptApplicationGraphSchemas.js";
import type { JavaScriptApplicationGraph } from "./javascriptApplicationGraph.js";
@ -216,7 +216,7 @@ const pathBelowRoot = (root: string, value: string): string | null => {
const remainder =
rootStyle === "windows"
? win32.relative(root, value)
: relative(root, value);
: posix.relative(root, value);
const portableRemainder = remainder.replaceAll("\\", "/");
if (
remainder === "" ||

View File

@ -21,6 +21,7 @@ import {
type ApplicationVersionComparisonResult,
} from "../../../src/domain/javascript/javascriptApplicationVersionComparisonSchemas.js";
import { javascriptRuntimeReconciliationResultSchema } from "../../../src/domain/javascript/javascriptRuntimeReconciliationSchemas.js";
import { electronPageInspectionSchema } from "../../../src/domain/javascript/electronObservation.js";
import { compareJavaScriptApplicationVersions } from "../../../src/domain/javascript/javascriptApplicationVersionComparison.js";
import { createJavaScriptApplicationGraph } from "../../../src/domain/javascript/javascriptApplicationGraph.js";
import { traceApplicationFeature } from "../../../src/domain/javascript/javascriptFeatureTrace.js";
@ -444,6 +445,73 @@ describe("JavaScript application workflow error diagnostics", () => {
});
describe("JavaScript runtime reconciliation local paths", () => {
it.each([
{
name: "case-sensitive POSIX input root",
root: null,
path: "/applications/Example.app/Contents/Resources/app/renderer.js",
status: "unknown",
},
{
name: "case-sensitive POSIX mapping root",
root: "/runtime/App",
path: "/runtime/app/renderer.js",
status: "unknown",
},
{
name: "matching POSIX mapping root",
root: "/runtime/App",
path: "/runtime/App/renderer.js",
status: "matched",
},
{
name: "case-insensitive Windows mapping root",
root: String.raw`C:\runtime\App`,
path: String.raw`c:\runtime\app\renderer.js`,
status: "matched",
},
])("uses $name on every host", ({ root, path, status }) => {
const base = JAVASCRIPT_RUNTIME_RECONCILIATION_EXAMPLE;
const original = base.runtime_observations[0]!;
const inspection = electronPageInspectionSchema.parse(
original.normalized_result,
);
const runtime = createEvidence(undefined, original.provider, {
predicateType: original.predicate_type,
operation: original.operation,
parameters: { ...original.parameters, include_script_sources: false },
result: {
...inspection,
scripts: {
...inspection.scripts,
items: inspection.scripts.items.map((script) => ({
...script,
file_path: path,
source: { included: false, reason: "not-requested" },
})),
},
},
confidence: original.confidence,
authority: original.authority,
});
const reconciled = reconcileJavaScriptRuntimeEvidence({
static_layers: base.static_layers.map((layer) => ({
...layer,
runtime_mappings: root === null ? [] : [{ kind: "file-root", root }],
})),
runtime_observations: [runtime],
});
if (!reconciled.ok) throw reconciled.error;
const result = javascriptRuntimeReconciliationResultSchema.parse(
reconciled.value.normalized_result,
);
expect(
result.reconciliations.find(
({ entity_kind }) => entity_kind === "script",
),
).toMatchObject({ status });
});
it("resolves relative file mapping roots before deriving result Evidence", () => {
const absoluteRoot = resolve(process.cwd(), "runtime-cache-fixture");
const relativeRoot = relative(process.cwd(), absoluteRoot);