Files
OmniRoute/tests/unit/route-guard-forge-jcode-settings-local-only.test.ts

49 lines
2.3 KiB
TypeScript

/**
* Security regression: /api/cli-tools/forge-settings and /api/cli-tools/jcode-settings
* must be classified as LOCAL_ONLY so loopback enforcement runs unconditionally before
* any auth check.
*
* GET calls getCliRuntimeStatus(TOOL_ID) (src/app/api/cli-tools/forge-settings/route.ts,
* src/app/api/cli-tools/jcode-settings/route.ts), which spawns a child process to locate
* and healthcheck the CLI binary (src/shared/services/cliRuntime.ts:332). That is the same
* transitive-spawn surface that got /api/cli-tools/grok-build-settings and
* /api/skills/collect/ classified.
*
* Classifying it LOCAL_ONLY closes the remote-RCE vector: a leaked JWT over a
* Cloudflared/Ngrok tunnel cannot trigger process spawning.
* Hard Rules #15 + #17. See docs/security/ROUTE_GUARD_TIERS.md. Issue #7263.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { isLocalOnlyPath } from "../../src/server/authz/routeGuard.ts";
test("/api/cli-tools/forge-settings is LOCAL_ONLY (spawns via getCliRuntimeStatus)", () => {
assert.equal(isLocalOnlyPath("/api/cli-tools/forge-settings"), true);
});
test("/api/cli-tools/forge-settings with trailing slash is LOCAL_ONLY", () => {
assert.equal(isLocalOnlyPath("/api/cli-tools/forge-settings/"), true);
});
test("/api/cli-tools/jcode-settings is LOCAL_ONLY (spawns via getCliRuntimeStatus)", () => {
assert.equal(isLocalOnlyPath("/api/cli-tools/jcode-settings"), true);
});
test("/api/cli-tools/jcode-settings with trailing slash is LOCAL_ONLY", () => {
assert.equal(isLocalOnlyPath("/api/cli-tools/jcode-settings/"), true);
});
test("sibling cli-tools spawn-capable settings routes stay LOCAL_ONLY", () => {
// Guards against a refactor dropping the established precedent this entry follows.
assert.equal(isLocalOnlyPath("/api/cli-tools/omp-settings"), true);
assert.equal(isLocalOnlyPath("/api/cli-tools/letta-settings"), true);
assert.equal(isLocalOnlyPath("/api/cli-tools/grok-build-settings"), true);
});
test("non-spawning cli-tools routes are NOT over-gated by this entry", () => {
// The new prefixes must not accidentally widen to the whole /api/cli-tools/ subtree,
// which remote dashboards legitimately use.
assert.equal(isLocalOnlyPath("/api/cli-tools/all-statuses"), false);
assert.equal(isLocalOnlyPath("/api/cli-tools/keys"), false);
});