Files
OmniRoute/tests/unit/upstream-ca-test-route-3488.test.ts
Diego Rodrigues de Sa e Souza c315a2394c Release v3.8.21 (#3593)
* chore(release): open v3.8.21 development cycle

* fix: pass through valid max_tokens-truncated responses instead of fake 502 (#3572) (#3595)

* fix: /v1/completions returns legacy text-completion format, not chat (#3571) (#3596)

* fix: z.ai/GLM coding plan no longer shows Monthly 0% when no monthly cap (#3580) (#3597)

* docs: mark DISCOVERY_TOOL_DESIGN endpoints as Phase-2 not-yet-implemented (#3498) (#3599)

* fix(agent-bridge): add validate-only upstream-ca/test route (#3488) (#3600)

* fix(gamification): add level/badges/badges-earned profile routes (#3484)

* security(oauth): migrate 5 public client_ids to resolvePublicCred (#3493)

* fix(mcp): ship MCP server source closure in npm files + coverage gate (#3578)

* fix: add reasoning token buffer for combo routing (fixes #3587) (#3588)

Integrated into release/v3.8.21

* Refactor: Extract chatCore phases into modular files (#3598)

Integrated into release/v3.8.21 — chatCore phase modularization. Adjusted: re-derive idempotencyKey for the save path after the check moved into the module (co-authored). Thanks @oyi77!

* docs(changelog): credit #3598 (chatCore modularization) + #3588 (combo reasoning buffer)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(api): implement GET /api/guardrails + POST /api/guardrails/test, drop shadow/guardrails doc-fiction (#3496) (#3602)

Integrated into release/v3.8.21 — implements GET /api/guardrails + POST /api/guardrails/test, removes shadow/guardrails doc-fiction. TDD-validated (5/5) + check-docs-symbols/typecheck/eslint green.

* fix(gemini): isolate textual reasoning wrappers (#3605)

Split-out PR C from #3584. Isolates textual reasoning wrappers (<think>/<thinking>/<thought>/<internal_thought>, including malformed/open tags) into reasoning_content across both the non-streaming sanitizer and the Gemini streaming translator, with split-chunk buffering. Additive to the existing textual tool-call pipeline; does not touch the #3569 native functionResponse path. Integrated into release/v3.8.21. Thanks @dhaern!

* fix(antigravity): normalize Gemini 3.5 Flash tier IDs (#3603)

Split-out PR A from #3584. Normalizes the Antigravity/agy Gemini 3.5 Flash tier IDs to clean public names (gemini-3.5-flash-low/medium/high), maps them to the live upstream IDs at the executor boundary, and removes Antigravity from the global model resolver so the executor owns wire normalization. Maintainer follow-up: kept gemini-3.5-flash-preview as a hidden backward-compat alias routing to the High tier (so saved combos/configs keep working). Live-validated the tier set via the agy CLI catalog. Integrated into release/v3.8.21. Thanks @dhaern!

* fix(agent-bridge): surface real MITM startup-failure cause, not always port 443 (#3606) (#3608)

Integrated into release/v3.8.21 (#3606)

* fix(oauth): surface real Kiro import-token failure cause, not a bare 500 (#3589) (#3609)

Integrated into release/v3.8.21 (#3589)

* docs(opencode-provider): soft-deprecate in favor of @omniroute/opencode-plugin (#3419) (#3613)

Integrated into release/v3.8.21 (#3419)

* fix(usage): normalize Antigravity and agy provider quotas (#3604)

Split-out PR B from #3584. Normalizes Antigravity/agy provider quotas: prefers retrieveUserQuota for live consumption, falls back to fetchAvailableModels and local usage_history, sanitizes cached Provider Limits so retired upstream IDs are not re-exposed, and schedules a deduplicated post-usage refresh. Maintainer follow-up: decoupled the post-usage refresh via a lightweight usageEvents bus (usageHistory no longer dynamic-imports providerLimits) so it does not pull the executors/translator graph into the typecheck-core surface — typecheck:core stays at 0. Integrated into release/v3.8.21. Thanks @dhaern!

* feat(cli): add autostart on/off/toggle shorthand for headless serve mode (#3331) (#3614)

Integrated into release/v3.8.21 (#3331)

* docs(changelog): credit #3603 (Flash tier IDs) + #3604 (provider quotas) + #3605 (reasoning wrappers)

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix(review): resolve findings from /review-reviews battery (v3.8.21 hardening) (#3618)

Pre-release hardening from the /review-reviews battery — 15 findings resolved (L1-L13,L15) + L14 live-verified WONTFIX, convergence re-review clean. lint/typecheck:core/test:vitest(146)/build green; zero new test:unit failures vs baseline 797de433f.

* chore(release): v3.8.21 CHANGELOG + i18n + env-doc sync

---------

Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Raxxoor <manker_lol@hotmail.com>
2026-06-11 04:01:24 -03:00

117 lines
4.8 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// Point the data dir at a throwaway location BEFORE importing the route so we can assert
// the validate-only route never writes the persisted CA-path file. resolveMitmDataDir()
// reads DATA_DIR at call time, so this also governs the route under test.
const DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ca-datadir-"));
process.env.DATA_DIR = DATA_DIR;
// The persisted path used by the real (persisting) POST /upstream-ca route.
const PERSISTED_CA_PATH_FILE = path.join(DATA_DIR, "mitm", "upstream-ca.path");
const { POST } = await import("../../src/app/api/tools/agent-bridge/upstream-ca/test/route.ts");
// #3488 — UpstreamCaField's "Test" button POSTed to /api/tools/agent-bridge/upstream-ca/test,
// which did not exist (404). The new validate-only route checks the CA file exists and is a
// parseable PEM certificate WITHOUT persisting/activating it.
// A throwaway self-signed cert (CN=OmniRoute Test CA), valid to 2036.
const TEST_CA_PEM = `-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIUISgNKO/v/z0FdUIPoCD4dwgKbacwDQYJKoZIhvcNAQEL
BQAwHDEaMBgGA1UEAwwRT21uaVJvdXRlIFRlc3QgQ0EwHhcNMjYwNjEwMjExNDMx
WhcNMzYwNjA3MjExNDMxWjAcMRowGAYDVQQDDBFPbW5pUm91dGUgVGVzdCBDQTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkubKCA7sgOph0nsKhQZNoH
UaQo+mrodWJ+23yVnxPygBQQay6okO1w5U6yxweinyCC0jB87Y386q30cqYK6NCf
HbAgkNRelhxeoU71DztIjIaKZCTlra5CCjVxVzvIOu4PoP8UgoLy/jOLM15XiM5B
entgjw62qXGRGak2Thiac+dHRzKJAIPxRDnWDrgQFsduNtSb1sGbivjUjLLEabm0
gokYlJpNCYJvS31qvL37aeV8igjt8hsReVEb5qm5RiiAepM9B3gvKvn0fsKvxT2a
rmqgySF+o2aTi+PW3+ZySoWoUL6b7GSA/CpF6Mc3u2qM/DvU4Kr0K8Y5EE+PsYUC
AwEAAaNTMFEwHQYDVR0OBBYEFD/qt9vsjOHNvlfT6Z4j9myR4GJJMB8GA1UdIwQY
MBaAFD/qt9vsjOHNvlfT6Z4j9myR4GJJMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggEBAH0WP40mF66cqUxQjamHS2BScRkn5E+SvwoZD12ZvQO/kgj/
wbWu5mZOf5cpuqHrOmfOC+6itIkZb7v6d0CRM19xcoAg1mVWFFSk0iroFCw0qltN
kB5WPvKHI6JRkr7HdUTD1qW9ljveMPfZ/Fm9ZM6QhCOLifzNTP2GMTVyIMAvig6B
TgmL/sn4dw4C2UTMQioMMXHSeJ90OD4Pv3mqX16JKrRSICoTExBoEIF23kWWJL6m
RL5Jiv1pdbFujHL8l9KPI2xmsWtkKutxOL2O5zpdUxP4noNVInDqEmbriK6CKY4y
hWHoQhtd4zf9H6+NIi38SPTCAmCjgU7iVq6mWoE=
-----END CERTIFICATE-----
`;
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-ca-test-"));
const validCaPath = path.join(dir, "valid-ca.pem");
const nonPemPath = path.join(dir, "not-a-cert.txt");
fs.writeFileSync(validCaPath, TEST_CA_PEM);
fs.writeFileSync(nonPemPath, "this is not a certificate");
test.after(() => {
fs.rmSync(dir, { recursive: true, force: true });
fs.rmSync(DATA_DIR, { recursive: true, force: true });
});
function postJson(body: unknown): Request {
return new Request("http://localhost/api/tools/agent-bridge/upstream-ca/test", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
}
test("#3488 valid PEM cert → 200 ok with subject", async () => {
const res = await POST(postJson({ path: validCaPath }));
assert.equal(res.status, 200);
const json = await res.json();
assert.equal(json.ok, true);
assert.match(json.subject, /OmniRoute Test CA/);
});
test("#3488 does NOT persist the CA path (validate-only)", async () => {
// Real side-effect guard (#3821-review LEDGER-11): the persisting POST /upstream-ca
// route writes <dataDir>/mitm/upstream-ca.path. After a successful /test call that file
// must NOT exist — proving the dry-run never persisted/activated the CA.
assert.ok(
!fs.existsSync(PERSISTED_CA_PATH_FILE),
"precondition: persisted CA-path file should not exist before the test"
);
const res = await POST(postJson({ path: validCaPath }));
assert.equal(res.status, 200);
const json = await res.json();
assert.equal(json.ok, true);
assert.ok(
!fs.existsSync(PERSISTED_CA_PATH_FILE),
"validate-only /test route must not write the persisted upstream-ca.path file"
);
// And it must not advertise activation/persistence in its response shape.
assert.equal(json.persisted, undefined);
assert.equal(json.activated, undefined);
});
test("#3488 non-existent path → 400", async () => {
const res = await POST(postJson({ path: path.join(dir, "nope.pem") }));
assert.equal(res.status, 400);
});
test("#3488 file that is not a PEM cert → 400", async () => {
const res = await POST(postJson({ path: nonPemPath }));
assert.equal(res.status, 400);
});
test("#3488 invalid body (missing path) → 400", async () => {
const res = await POST(postJson({}));
assert.equal(res.status, 400);
});
test("#3488 invalid JSON body → 400", async () => {
const req = new Request("http://localhost/api/tools/agent-bridge/upstream-ca/test", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: "{not json",
});
const res = await POST(req);
assert.equal(res.status, 400);
});