mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-18 04:42:30 +03:00
PR E of the #13679 insecure-defaults umbrella (items #6, #7; item #8 analyzed as by-design, no change). The published Docker image and fly.toml shipped without REQUIRE_API_KEY set, so a bare `docker run` (README/QUICK-START one-liners, no --env-file) or a `fly deploy` combined "keyless" with "world-reachable" for the anonymous /v1 LLM proxy. docker-compose.yml already mitigates this via loopback-only binding (#12568) and correctly keeps following the operator's own .env, so it is untouched. The npm/CLI local-first REQUIRE_API_KEY=false default in featureFlagDefinitions.ts is also untouched per the owner's decision. /api/free-tier/summary ships an unconditional Access-Control-Allow-Origin: "*" and always included the operator's own local usedThisMonth/remaining usage regardless of auth — a low-severity info leak to any reachable origin. Both fields are now withheld from unauthenticated callers while the intentionally public catalog data stays served to everyone. The gemini-SSE (openai-to-gemini-sse.ts) sub-finding needed no code change: /v1beta/models/*:streamGenerateContent is already classified CLIENT_API and fronted by clientApiPolicy through src/proxy.ts before the translator ever runs, and its CORS-header echo was already hardened fail-closed by #12573. REQUIRE_API_KEY=true (this PR's container/Fly default) closes the dependency that finding cited. Added a locking regression test confirming this chain. Regression tests: - tests/unit/issue-13679-container-posture-require-api-key.test.ts - tests/unit/issue-13679-free-tier-summary-usage-leak.test.ts - tests/unit/issue-13679-gemini-sse-requires-api-key.test.ts (confirmation) Refs #13679
61 lines
2.7 KiB
TypeScript
61 lines
2.7 KiB
TypeScript
/**
|
|
* Issue #13679 (PR E, item #6) — published container/Fly deployment posture.
|
|
*
|
|
* A default `docker run … diegosouzapw/omniroute` (README/QUICK-START one-liners,
|
|
* which do NOT pass `--env-file .env`) and the shipped `fly.toml` both publish
|
|
* the app on a public interface (Fly always; a bare `docker run -p 20128:20128`
|
|
* binds 0.0.0.0 on the host) while `REQUIRE_API_KEY` defaulted to unset/false —
|
|
* combining "world-reachable" with "keyless" for the anonymous `/v1` LLM proxy.
|
|
*
|
|
* `docker-compose.yml` already mitigates this for the compose path (loopback
|
|
* bind by default, #12568) and intentionally still follows the operator's own
|
|
* `.env` (own `REQUIRE_API_KEY` choice) — this test does NOT touch that file.
|
|
*
|
|
* The npm/CLI local-dev default in `src/shared/constants/featureFlagDefinitions.ts`
|
|
* (`REQUIRE_API_KEY` defaultValue `"false"`) is explicitly OUT of scope and must
|
|
* stay unchanged — see AGENTS.md Hard Rule #20 precedent and the owner decision
|
|
* on #13679 PR E.
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const ROOT = path.resolve(import.meta.dirname, "../..");
|
|
|
|
function read(relPath: string): string {
|
|
return readFileSync(path.join(ROOT, relPath), "utf-8");
|
|
}
|
|
|
|
test("Dockerfile ships REQUIRE_API_KEY=true by default for the published image", () => {
|
|
const dockerfile = read("Dockerfile");
|
|
assert.match(
|
|
dockerfile,
|
|
/^ENV REQUIRE_API_KEY=true$/m,
|
|
"the published Dockerfile must default to REQUIRE_API_KEY=true so `docker run` without " +
|
|
"an --env-file does not ship keyless AND world-reachable at once — override with " +
|
|
"`-e REQUIRE_API_KEY=false` for an intentionally keyless deployment"
|
|
);
|
|
});
|
|
|
|
test("fly.toml ships REQUIRE_API_KEY=true in [env] for the always-public Fly path", () => {
|
|
const flyToml = read("fly.toml");
|
|
assert.match(
|
|
flyToml,
|
|
/^\s*REQUIRE_API_KEY\s*=\s*"true"\s*$/m,
|
|
"fly.toml's [env] block must set REQUIRE_API_KEY=true — a Fly deployment is reachable " +
|
|
"over the public internet by design (force_https + Fly's edge proxy), unlike the " +
|
|
"docker-compose path which binds loopback-only by default (#12568)"
|
|
);
|
|
});
|
|
|
|
test("the npm/CLI local-first REQUIRE_API_KEY default is untouched (#13679 PR E constraint)", () => {
|
|
const definitions = read("src/shared/constants/featureFlagDefinitions.ts");
|
|
assert.match(
|
|
definitions,
|
|
/key:\s*"REQUIRE_API_KEY"[\s\S]{0,200}?defaultValue:\s*"false"/,
|
|
"the local-first npm/CLI default must stay REQUIRE_API_KEY=false — only the shipped " +
|
|
"container/Fly deployment manifests change posture, per the #13679 owner decision"
|
|
);
|
|
});
|