diff --git a/sdk/typescript/src/targets.ts b/sdk/typescript/src/targets.ts index 0cd5820..8f6812d 100644 --- a/sdk/typescript/src/targets.ts +++ b/sdk/typescript/src/targets.ts @@ -371,7 +371,7 @@ async function gitOutput( env: command.environment, }, ); - return stdout.trim(); + return stdout.replace(/\r?\n$/u, ""); } async function outermostGitMarkerRoot( diff --git a/sdk/typescript/tests-ts/targets.test.ts b/sdk/typescript/tests-ts/targets.test.ts index f8894cd..c621876 100644 --- a/sdk/typescript/tests-ts/targets.test.ts +++ b/sdk/typescript/tests-ts/targets.test.ts @@ -21,6 +21,7 @@ import { repositoryRevision, type ScanTarget, } from "../src/index.js"; +import { enclosingGitWorktreeRoot } from "../src/targets.js"; // @ts-expect-error DiffTarget is intentionally nominal; use its constructor helpers. const structurallyInvalidTarget: ScanTarget = { @@ -40,12 +41,12 @@ afterEach(async () => { ); }); -async function repository(): Promise { +async function repository(name = "repo"): Promise { const root = await realpath( await mkdtemp(join(tmpdir(), "codex-security-targets-")), ); temporaryDirectories.push(root); - const repo = join(root, "repo"); + const repo = join(root, name); await mkdir(join(repo, "src"), { recursive: true }); await writeFile(join(repo, "src", "app.ts"), "export const ok = true;\n"); git(repo, "init", "-b", "main"); @@ -123,6 +124,17 @@ describe("scan target normalization", () => { }); }); + test.skipIf(process.platform === "win32")( + "preserves trailing whitespace in Git worktree paths", + async () => { + const repo = await repository("repo "); + expect(await enclosingGitWorktreeRoot(repo)).toBe(await realpath(repo)); + await expect( + normalizeTarget(repo, DiffTarget.refs({ base: "HEAD" })), + ).resolves.toMatchObject({ kind: "refs" }); + }, + ); + test("rejects empty and escaping paths", async () => { const repo = await repository(); await expect(normalizeTarget(repo, [""])).rejects.toThrow("empty path");