fix: use path.sep for cross-platform path traversal guards and test assertions

Path traversal guards used hardcoded "/" separator which fails on Windows
where resolve() produces backslash paths. Test assertions also used
forward-slash path fragments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson 2026-03-22 09:39:21 -06:00
parent 97241ea19c
commit 17a2f55edb
3 changed files with 5 additions and 5 deletions

View file

@ -14,7 +14,7 @@
*/
import { readFileSync, existsSync } from "node:fs";
import { join, resolve } from "node:path";
import { join, resolve, sep } from "node:path";
import type { StepDefinition } from "./definition-loader.js";
import { readFrozenDefinition } from "./custom-workflow-engine.js";
@ -65,7 +65,7 @@ export function injectContext(
for (const relPath of refStep.produces) {
const absPath = resolve(runDir, relPath);
// Path traversal guard: ensure resolved path stays within runDir
if (!absPath.startsWith(resolve(runDir) + "/") && absPath !== resolve(runDir)) {
if (!absPath.startsWith(resolve(runDir) + sep) && absPath !== resolve(runDir)) {
console.warn(
`context-injector: artifact path "${relPath}" resolves outside runDir — skipping`,
);

View file

@ -18,7 +18,7 @@
*/
import { readFileSync, existsSync, statSync } from "node:fs";
import { join, resolve } from "node:path";
import { join, resolve, sep } from "node:path";
import { spawnSync } from "node:child_process";
import type { StepDefinition, VerifyPolicy } from "./definition-loader.js";
import { readFrozenDefinition } from "./custom-workflow-engine.js";
@ -105,7 +105,7 @@ function handleContentHeuristic(
for (const relPath of produces) {
const absPath = resolve(runDir, relPath);
// Path traversal guard
if (!absPath.startsWith(resolve(runDir) + "/") && absPath !== resolve(runDir)) {
if (!absPath.startsWith(resolve(runDir) + sep) && absPath !== resolve(runDir)) {
return "pause";
}

View file

@ -114,7 +114,7 @@ describe("createRun", () => {
assert.ok(!existsSync(join(runDir, "PARAMS.json")), "PARAMS.json should not exist without overrides");
// Run directory path matches convention
assert.ok(runDir.includes(".gsd/workflow-runs/test-workflow/"), "path should follow convention");
assert.ok(runDir.includes(join(".gsd", "workflow-runs", "test-workflow")), "path should follow convention");
});
it("writes PARAMS.json and substituted prompts when overrides provided", () => {