mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
* 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>
117 lines
4.8 KiB
TypeScript
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);
|
|
});
|