Files
OmniRoute/tests/unit/proxy-subscriptions-route-validation.test.ts
diegosouzapw e5eefca23b chore(release): v3.8.49 — clear the release-PR CI in one pass
Every finding from the first full ci.yml run on the release PR, fixed or justified
together so a single re-push clears the board.

Lint / check:route-validation:t06 — three routes read request.json() with no visible
Zod validation. The two proxy-subscriptions routes validated with a hand-rolled
parsePayload(); they now use real Zod schemas (src/lib/proxySubscription/schema.ts)
reproducing the same acceptance rules, error strings and status codes. chat/completions
is the proxy's hottest path and parses the body ONCE on purpose (#4380 OOM crash-loop),
so it now safeParses the ALREADY-PARSED object against a deliberately permissive
structural schema — proven not to change behavior: absent model and model:null still
pass through, role "developer" still reaches 200, a ~300 KB payload is accepted, and
the body is still read exactly once. 25 new tests.

i18n UI value drift — 13 English strings rewritten during the cycle left stale
translations in up to 41 locales (317 pairs). Eleven are genuine rewrites and now carry
the pipeline's __MISSING__:<english> marker so the runtime serves corrected English until
translation catches up; vi forbids that marker by test, so it got a real translation.

PR Test Policy — 33 files flagged. Each was verified against the SOURCE, not the diff:
26 assert reductions are legitimate (mostly the #7866 Qwen OAuth provider removal and the
#8013 Antigravity refactor deleting the surface under test) and are allowlisted with the
PR and the evidence; 5 deleted files have verified replacements. One was NOT legitimate:
#7528's GraphQL->WebSocket migration dropped four muse-spark continuation scenarios whose
logic is still live — connection isolation, cache eviction after a failed turn (the commit
itself says "was missing"), parallel-chat cache collision, and the empty-content guard.
All four are restored against the new transport and each was verified to fail when the
corresponding production mechanism is broken.

Quality Ratchet / openapiCoverage — 36.6% against a baseline of 38: the cycle added routes
faster than the spec. Eight real endpoints are now documented from their route.ts
(usage cache-health and model-latency-stats, the two OIDC endpoints, and the five
proxy-subscriptions paths), bringing it to 38.1%.

Quality Gates (Extended) / zizmor — the runner measures 190 where the devbox measures 189
on the same commit, a delta already recorded in this baseline's history. Baselined to the
runner's number.

Also: the driverFactory better-sqlite3 guard moved from a mid-body t.skip() to a declared
{ skip: <condition> } test option. Same behavior for the optional native dependency, but
the skip now shows up in the report and is distinguishable from a test.skip() that silences
a test outright. Verified under both runners: 15/15 on Node, 14/14 on Bun.

SonarCloud Code Analysis stays red and is not a blocker: sonar.qualitygate.wait=false since
#7038 makes the job informative, the built-in gate cannot be swapped on the FREE plan, and
main has no branch protection.
2026-07-28 18:37:37 -03:00

346 lines
14 KiB
TypeScript

/**
* Regression guard for the T06 route-validation gate on the proxy-subscriptions
* management routes.
*
* `POST /api/v1/management/proxy-subscriptions` and
* `PATCH /api/v1/management/proxy-subscriptions/:id` used to hand-roll their body
* parsing (a local `parsePayload()` / inline field-by-field checks) instead of a
* Zod schema, which `scripts/check/check-route-validation.mjs` flags as an
* unvalidated `request.json()` usage. The fix swaps both routes to
* `proxySubscriptionCreateSchema` / `proxySubscriptionUpdateSchema`
* (`src/lib/proxySubscription/schema.ts`) applied via `.safeParse()`.
*
* These tests pin the EXACT pre-existing acceptance/rejection rules, error
* messages, and `{ error: string }` envelope shape — the schema swap must be a
* pure refactor, not a behavior change.
*
* DB/auth setup mirrors tests/unit/api-malformed-json-400.test.ts: a temp
* DATA_DIR with no configured password means requireManagementAuth() is a
* no-op, so the handlers run unauthenticated.
*/
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-proxy-sub-route-"));
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
const ORIGINAL_API_KEY_SECRET = process.env.API_KEY_SECRET;
const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD;
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET ?? "proxy-sub-route-test-secret";
delete process.env.INITIAL_PASSWORD; // ensure auth is NOT required
const core = await import("../../src/lib/db/core.ts");
const collectionRoute = await import(
"../../src/app/api/v1/management/proxy-subscriptions/route.ts"
);
const itemRoute = await import(
"../../src/app/api/v1/management/proxy-subscriptions/[id]/route.ts"
);
function jsonRequest(url: string, body: unknown, method = "POST"): Request {
return new Request(url, {
method,
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
}
function malformedJsonRequest(url: string, method = "POST"): Request {
return new Request(url, {
method,
headers: { "content-type": "application/json" },
body: "not-json",
});
}
async function createValidSubscription(name: string) {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name,
url: `https://example.com/${name}`,
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201, "fixture creation must succeed");
return (await res.json()) as { id: string };
}
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = ORIGINAL_DATA_DIR;
if (ORIGINAL_API_KEY_SECRET === undefined) delete process.env.API_KEY_SECRET;
else process.env.API_KEY_SECRET = ORIGINAL_API_KEY_SECRET;
if (ORIGINAL_INITIAL_PASSWORD === undefined) delete process.env.INITIAL_PASSWORD;
else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD;
});
// ═════════════════════════════════════════════════════════════════════════════
// POST /api/v1/management/proxy-subscriptions
// ═════════════════════════════════════════════════════════════════════════════
test("POST proxy-subscriptions — valid body still creates (201), unregressed happy path", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "my-sub",
url: "https://example.com/sub.txt",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201);
const body = (await res.json()) as { name?: string; url?: string; mode?: string };
assert.equal(body.name, "my-sub");
assert.equal(body.url, "https://example.com/sub.txt");
assert.equal(body.mode, "global", "mode defaults to 'global' when omitted");
});
test("POST proxy-subscriptions — trims name/url and coerces unknown mode to 'global'", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: " padded-name ",
url: " https://example.com/padded ",
mode: "not-a-real-mode",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201);
const body = (await res.json()) as { name?: string; url?: string; mode?: string };
assert.equal(body.name, "padded-name");
assert.equal(body.url, "https://example.com/padded");
assert.equal(body.mode, "global");
});
test("POST proxy-subscriptions — malformed JSON body returns 400 with the original message", async () => {
const req = malformedJsonRequest("http://localhost/api/v1/management/proxy-subscriptions");
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "Invalid JSON body");
});
test("POST proxy-subscriptions — valid-JSON non-object (string) body returns 400 'Invalid JSON body'", async () => {
// A bare JSON array is still `typeof === "object"` in JS (matching the original
// `typeof body !== "object"` guard), so it falls through to the missing-name
// check instead — see the array-body test below for that path. A primitive
// (string/number/boolean) is the one JSON shape that actually trips this guard.
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", "just-a-string");
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "Invalid JSON body");
});
test("POST proxy-subscriptions — a JSON array body is an 'object' in JS, so it hits 'name is required' (not 'Invalid JSON body')", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", [1, 2, 3]);
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "name is required");
});
test("POST proxy-subscriptions — missing name returns 400 'name is required'", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
url: "https://example.com/sub.txt",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "name is required");
});
test("POST proxy-subscriptions — blank name (whitespace only) returns 400 'name is required'", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: " ",
url: "https://example.com/sub.txt",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "name is required");
});
test("POST proxy-subscriptions — missing url returns 400 'url is required' (checked after name)", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "my-sub",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "url is required");
});
test("POST proxy-subscriptions — mode 'rule' without ruleProviders returns 400", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "my-sub",
url: "https://example.com/sub.txt",
mode: "rule",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "ruleProviders is required when mode is 'rule'");
});
test("POST proxy-subscriptions — mode 'rule' with an empty ruleProviders array returns 400", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "my-sub",
url: "https://example.com/sub.txt",
mode: "rule",
ruleProviders: [],
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "ruleProviders is required when mode is 'rule'");
});
test("POST proxy-subscriptions — mode 'rule' with ruleProviders succeeds (201)", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "rule-sub",
url: "https://example.com/rule-sub.txt",
mode: "rule",
ruleProviders: ["openai", 42, "anthropic"],
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201);
const body = (await res.json()) as { mode?: string; ruleProviders?: string[] };
assert.equal(body.mode, "rule");
assert.deepEqual(
body.ruleProviders,
["openai", "anthropic"],
"non-string ruleProviders entries are filtered out, matching the original parser"
);
});
test("POST proxy-subscriptions — invalid updateIntervalMinutes silently falls back to 60", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "interval-sub",
url: "https://example.com/interval-sub.txt",
updateIntervalMinutes: "not-a-number",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201);
const body = (await res.json()) as { updateIntervalMinutes?: number };
assert.equal(body.updateIntervalMinutes, 60);
});
test("POST proxy-subscriptions — enabled must be exactly `true`, not truthy", async () => {
const req = jsonRequest("http://localhost/api/v1/management/proxy-subscriptions", {
name: "enabled-sub",
url: "https://example.com/enabled-sub.txt",
enabled: "yes",
});
const res = await collectionRoute.POST(req);
assert.equal(res.status, 201);
const body = (await res.json()) as { enabled?: boolean };
assert.equal(body.enabled, false);
});
// ═════════════════════════════════════════════════════════════════════════════
// PATCH /api/v1/management/proxy-subscriptions/:id
// ═════════════════════════════════════════════════════════════════════════════
test("PATCH proxy-subscriptions/:id — valid partial body updates (200), unregressed happy path", async () => {
const fixture = await createValidSubscription("patch-target");
const req = jsonRequest(
`http://localhost/api/v1/management/proxy-subscriptions/${fixture.id}`,
{ name: "renamed" },
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) });
assert.equal(res.status, 200);
const body = (await res.json()) as { name?: string };
assert.equal(body.name, "renamed");
});
test("PATCH proxy-subscriptions/:id — wrong-typed fields are ignored, not rejected", async () => {
const fixture = await createValidSubscription("patch-wrongtype");
const req = jsonRequest(
`http://localhost/api/v1/management/proxy-subscriptions/${fixture.id}`,
{ name: "kept", updateIntervalMinutes: "not-a-number", enabled: "yes" },
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) });
assert.equal(res.status, 200, "unknown-typed fields must be silently dropped, not a 400");
const body = (await res.json()) as {
name?: string;
updateIntervalMinutes?: number;
enabled?: boolean;
};
assert.equal(body.name, "kept");
assert.equal(body.updateIntervalMinutes, 60, "untouched — non-number was ignored, not coerced");
assert.equal(body.enabled, false, "untouched — non-boolean was ignored");
});
test("PATCH proxy-subscriptions/:id — malformed JSON body returns 400 'Invalid JSON body'", async () => {
const fixture = await createValidSubscription("patch-malformed");
const req = malformedJsonRequest(
`http://localhost/api/v1/management/proxy-subscriptions/${fixture.id}`,
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) });
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "Invalid JSON body");
});
test("PATCH proxy-subscriptions/:id — valid-JSON non-object body returns 400 'Invalid JSON body'", async () => {
const fixture = await createValidSubscription("patch-nonobject");
const req = jsonRequest(
`http://localhost/api/v1/management/proxy-subscriptions/${fixture.id}`,
"just-a-string",
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) });
assert.equal(res.status, 400);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "Invalid JSON body");
});
test("PATCH proxy-subscriptions/:id — a JSON array body is an 'object' in JS, so it's a no-op update (200), not 400", async () => {
const fixture = await createValidSubscription("patch-arraybody");
const req = jsonRequest(
`http://localhost/api/v1/management/proxy-subscriptions/${fixture.id}`,
[1, 2, 3],
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: fixture.id }) });
assert.equal(res.status, 200, "matches the original inline parser: no typed field matches, no error");
const body = (await res.json()) as { name?: string };
assert.equal(body.name, "patch-arraybody", "name is unchanged — the array had no usable fields");
});
test("PATCH proxy-subscriptions/:id — unknown id still 404s past body validation", async () => {
const req = jsonRequest(
"http://localhost/api/v1/management/proxy-subscriptions/does-not-exist",
{ name: "whatever" },
"PATCH"
);
const res = await itemRoute.PATCH(req, { params: Promise.resolve({ id: "does-not-exist" }) });
assert.equal(res.status, 404);
const body = (await res.json()) as { error?: string };
assert.equal(body.error, "Subscription not found");
});