Skip to content

Commit 0608338

Browse files
test: fix CI portability assertions
1 parent 92a6bdd commit 0608338

10 files changed

Lines changed: 72 additions & 32 deletions

tests/cli/init-command.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { resolve } from "node:path";
12
import { describe, expect, it } from "vitest";
23
import { createCli, type CliDeps } from "../../src/cli";
34
import type { CodeGateConfig } from "../../src/config";
@@ -57,12 +58,14 @@ function makeDeps(overrides: Partial<CliDeps>): CliDeps {
5758

5859
describe("init command", () => {
5960
it("writes default config to ~/.codegate/config.json", async () => {
61+
const home = "/tmp/codegate-home";
6062
let exitCode = -1;
6163
let writtenPath = "";
6264
let content = "";
6365
const cli = createCli(
6466
"0.2.2",
6567
makeDeps({
68+
homeDir: () => home,
6669
writeFile: (path, value) => {
6770
writtenPath = path;
6871
content = value;
@@ -74,7 +77,7 @@ describe("init command", () => {
7477
);
7578

7679
await cli.parseAsync(["node", "codegate", "init"]);
77-
expect(writtenPath).toBe("/tmp/codegate-home/.codegate/config.json");
80+
expect(writtenPath).toBe(resolve(home, ".codegate", "config.json"));
7881
expect(content).toContain('"severity_threshold"');
7982
expect(content).toContain('"scan_state_path"');
8083
expect(exitCode).toBe(0);

tests/cli/remediation-flags.test.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createCli, type CliDeps } from "../../src/cli";
33
import type { CodeGateConfig } from "../../src/config";
44
import type { Finding } from "../../src/types/finding";
55
import type { CodeGateReport } from "../../src/types/report";
6+
import { normalizeLines } from "../helpers/path";
67

78
const BASE_CONFIG: CodeGateConfig = {
89
severity_threshold: "high",
@@ -178,17 +179,18 @@ describe("task 23 remediation flags", () => {
178179
});
179180

180181
await cli.parseAsync(["node", "codegate", "scan", ".", "--remediate"]);
182+
const normalized = normalizeLines(printed);
181183
expect(runRemediation).toHaveBeenCalledTimes(1);
182-
expect(printed.some((line) => line.includes("Remediation summary"))).toBe(true);
183-
expect(printed.some((line) => line.includes("Planned changes: 2"))).toBe(true);
184-
expect(printed.some((line) => line.includes("Applied changes: 2"))).toBe(true);
184+
expect(normalized.some((line) => line.includes("Remediation summary"))).toBe(true);
185+
expect(normalized.some((line) => line.includes("Planned changes: 2"))).toBe(true);
186+
expect(normalized.some((line) => line.includes("Applied changes: 2"))).toBe(true);
185187
expect(
186-
printed.some((line) => line.includes(".codegate-backup/2026-03-01T12-00-00-aaaaaa")),
188+
normalized.some((line) => line.includes(".codegate-backup/2026-03-01T12-00-00-aaaaaa")),
187189
).toBe(true);
188-
expect(printed.some((line) => line.includes("codegate undo"))).toBe(true);
189-
expect(printed.some((line) => line.includes("remove_field"))).toBe(true);
190+
expect(normalized.some((line) => line.includes("codegate undo"))).toBe(true);
191+
expect(normalized.some((line) => line.includes("remove_field"))).toBe(true);
190192
expect(
191-
printed.some((line) => line.includes("ENV_OVERRIDE-.mcp.json-env.OPENAI_BASE_URL")),
193+
normalized.some((line) => line.includes("ENV_OVERRIDE-.mcp.json-env.OPENAI_BASE_URL")),
192194
).toBe(true);
193195
});
194196

tests/commands/scan-command-helpers.test.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { resolve } from "node:path";
12
import { describe, expect, it } from "vitest";
23
import {
34
noEligibleDeepResourceNotes,
@@ -7,6 +8,7 @@ import {
78
} from "../../src/commands/scan-command/helpers";
89
import type { ScanCommandOptions } from "../../src/commands/scan-command";
910
import type { CodeGateReport } from "../../src/types/report";
11+
import { normalizeLines } from "../helpers/path";
1012

1113
function emptyReport(): CodeGateReport {
1214
return {
@@ -65,8 +67,9 @@ describe("scan command helpers", () => {
6567
});
6668

6769
it("formats remediation summary lines with backup and action details", () => {
70+
const scanTarget = "/tmp/codegate-demo";
6871
const result = remediationSummaryLines({
69-
scanTarget: "/tmp/codegate-demo",
72+
scanTarget,
7073
options: { remediate: true } satisfies ScanCommandOptions,
7174
before: {
7275
...emptyReport(),
@@ -95,13 +98,18 @@ describe("scan command helpers", () => {
9598
],
9699
},
97100
});
101+
const normalized = normalizeLines(result);
98102

99-
expect(result).toContain("Remediation summary:");
100-
expect(result).toContain("Mode: remediate");
101-
expect(result).toContain("Findings before remediation: 3");
102-
expect(result).toContain("Findings after remediation: 1");
103-
expect(result).toContain("Backup session: /tmp/codegate-demo/.codegate-backup/session-123");
104-
expect(result).toContain("- remove_field -> /tmp/codegate-demo/.mcp.json (F-1)");
103+
expect(normalized).toContain("Remediation summary:");
104+
expect(normalized).toContain("Mode: remediate");
105+
expect(normalized).toContain("Findings before remediation: 3");
106+
expect(normalized).toContain("Findings after remediation: 1");
107+
expect(normalized).toContain(
108+
`Backup session: ${resolve(scanTarget, ".codegate-backup", "session-123").replaceAll("\\", "/")}`,
109+
);
110+
expect(normalized).toContain(
111+
`- remove_field -> ${resolve(scanTarget, ".mcp.json").replaceAll("\\", "/")} (F-1)`,
112+
);
105113
});
106114

107115
it("returns the stock no-resource deep scan notes", () => {

tests/fixtures/fixtures.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ describe("task 06 fixture corpus", () => {
1919
it("contains clean project fixtures", () => {
2020
const cleanRoot = resolve(root, "clean-projects");
2121
expect(existsSync(cleanRoot)).toBe(true);
22-
expect(readdirSync(cleanRoot).length).toBeGreaterThanOrEqual(2);
22+
const projects = readdirSync(cleanRoot);
23+
expect(projects.length).toBeGreaterThanOrEqual(1);
24+
expect(projects).toContain("clean-claude");
2325
});
2426

2527
it("contains malformed parsing fixtures", () => {

tests/helpers/path.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { resolve } from "node:path";
2+
3+
export function normalizeSlashes(value: string): string {
4+
return value.replaceAll("\\", "/");
5+
}
6+
7+
export function resolveForHost(...paths: string[]): string {
8+
return normalizeSlashes(resolve(...paths));
9+
}
10+
11+
export function normalizeLines(lines: string[]): string[] {
12+
return lines.map(normalizeSlashes);
13+
}

tests/layer1/artifact-candidate-discovery.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
createScanDiscoveryContext,
1010
} from "../../src/scan";
1111
import { resolveScanTarget } from "../../src/scan-target";
12+
import { normalizeSlashes } from "../helpers/path";
1213

1314
const BASE_CONFIG: CodeGateConfig = {
1415
severity_threshold: "high",
@@ -59,7 +60,7 @@ describe("artifact candidate discovery", () => {
5960
report.findings.some(
6061
(finding) =>
6162
finding.rule_id === "rule-file-remote-shell" &&
62-
finding.file_path === "skills/security-review/SKILL.md",
63+
normalizeSlashes(finding.file_path) === "skills/security-review/SKILL.md",
6364
),
6465
).toBe(true);
6566
});
@@ -111,7 +112,7 @@ describe("artifact candidate discovery", () => {
111112
report.findings.some(
112113
(finding) =>
113114
finding.rule_id === "plugin-manifest-insecure-source-url" &&
114-
finding.file_path === "manifests/plugins.json",
115+
normalizeSlashes(finding.file_path) === "manifests/plugins.json",
115116
),
116117
).toBe(true);
117118
});
@@ -151,7 +152,7 @@ describe("artifact candidate discovery", () => {
151152
report.findings.some(
152153
(finding) =>
153154
finding.rule_id === "rule-file-remote-shell" &&
154-
finding.file_path === "skills/security-review/nested/payload.txt",
155+
normalizeSlashes(finding.file_path) === "skills/security-review/nested/payload.txt",
155156
),
156157
).toBe(true);
157158
});

tests/layer1/file-walker.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
33
import { join } from "node:path";
44
import { afterEach, describe, expect, it } from "vitest";
55
import { walkProjectTree } from "../../src/layer1-discovery/file-walker";
6+
import { normalizeSlashes } from "../helpers/path";
67

78
const tempDirs: string[] = [];
89

@@ -29,9 +30,10 @@ describe("task 09 file walker", () => {
2930
writeFileSync(join(root, "README.md"), "ok");
3031

3132
const result = walkProjectTree(root);
32-
expect(result.files.some((file) => file.endsWith("README.md"))).toBe(true);
33-
expect(result.files.some((file) => file.includes("node_modules"))).toBe(false);
34-
expect(result.files.some((file) => file.includes(".git/hooks/pre-commit"))).toBe(true);
33+
const files = result.files.map(normalizeSlashes);
34+
expect(files.some((file) => file.endsWith("README.md"))).toBe(true);
35+
expect(files.some((file) => file.includes("node_modules"))).toBe(false);
36+
expect(files.some((file) => file.includes(".git/hooks/pre-commit"))).toBe(true);
3537
});
3638

3739
it("detects symlink escape outside project root", () => {

tests/layer1/tool-detector.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { join } from "node:path";
12
import { describe, expect, it } from "vitest";
23
import {
34
detectTools,
@@ -55,12 +56,11 @@ describe("task 10 tool detector", () => {
5556
});
5657

5758
it("detects GitHub Copilot extension installation", () => {
59+
const extensionsDir = join("/Users/tester", ".vscode", "extensions");
5860
const detections = detectTools(
5961
makeDeps({
6062
listDirectory: (path) =>
61-
path === "/Users/tester/.vscode/extensions"
62-
? ["github.copilot-1.2.3", "some.other-ext-0.1.0"]
63-
: [],
63+
path === extensionsDir ? ["github.copilot-1.2.3", "some.other-ext-0.1.0"] : [],
6464
}),
6565
);
6666
const copilot = byName(detections, "github-copilot");

tests/reporter/terminal.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { resolve } from "node:path";
12
import { describe, expect, it } from "vitest";
23
import { renderTerminalReport } from "../../src/reporter/terminal";
34
import type { CodeGateReport } from "../../src/types/report";
5+
import { normalizeSlashes } from "../helpers/path";
46

57
describe("task 15 terminal reporter", () => {
68
it("renders summary and findings in plain text", () => {
@@ -41,9 +43,12 @@ describe("task 15 terminal reporter", () => {
4143
};
4244

4345
const output = renderTerminalReport(report);
46+
const normalizedOutput = normalizeSlashes(output);
4447
expect(output).toContain("CodeGate v0.1.0");
4548
expect(output).toContain("CRITICAL: 1");
46-
expect(output).toContain("/tmp/project/.claude/settings.json");
49+
expect(normalizedOutput).toContain(
50+
normalizeSlashes(resolve("/tmp/project", ".claude/settings.json")),
51+
);
4752
expect(output).toContain("Evidence:");
4853
expect(output).toContain('2 | "ANTHROPIC_BASE_URL": "http://evil.example"');
4954
});

tests/tui/render.test.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { resolve } from "node:path";
12
import { describe, expect, it } from "vitest";
23
import { render } from "ink-testing-library";
34
import { CodeGateTuiApp } from "../../src/tui/app";
45
import type { CodeGateReport } from "../../src/types/report";
6+
import { normalizeSlashes } from "../helpers/path";
57

68
const REPORT: CodeGateReport = {
79
version: "0.1.0",
@@ -56,12 +58,14 @@ const SAFE_REPORT: CodeGateReport = {
5658
describe("task 18 tui shell rendering", () => {
5759
it("renders dashboard view with scan summary", () => {
5860
const app = render(<CodeGateTuiApp view="dashboard" report={REPORT} />);
59-
expect(app.lastFrame()).toContain("CodeGate v0.1.0");
60-
expect(app.lastFrame()).toContain("Installed tools");
61-
expect(app.lastFrame()).toContain("Findings");
62-
expect(app.lastFrame()).toContain("Evidence:");
63-
expect(app.lastFrame()).toContain("/tmp/project/.mcp.json");
64-
expect(app.lastFrame()).toContain('3 | "bad": {');
61+
const frame = app.lastFrame();
62+
const normalizedFrame = normalizeSlashes(frame);
63+
expect(frame).toContain("CodeGate v0.1.0");
64+
expect(frame).toContain("Installed tools");
65+
expect(frame).toContain("Findings");
66+
expect(frame).toContain("Evidence:");
67+
expect(normalizedFrame).toContain(normalizeSlashes(resolve("/tmp/project", ".mcp.json")));
68+
expect(frame).toContain('3 | "bad": {');
6569
});
6670

6771
it("renders progress view while scanning", () => {

0 commit comments

Comments
 (0)