diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bba532ec2..c3efd81b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ _Living section — bullets land here as PRs merge into `release/v3.8.47` (paral ### 🐛 Bug Fixes +- **fix(build):** Turbopack production build emitted an "Overly broad patterns can lead to build performance issues" warning per entry point importing `src/lib/agentSkills/generator.ts` (603 warnings reported on v3.8.46, up from 379 on v3.8.45) ([#6582](https://github.com/diegosouzapw/OmniRoute/issues/6582)) — `generator.ts`'s `outputBase` is built as `path.isAbsolute(outputDir) ? outputDir : path.join(process.cwd(), outputDir)`, where `outputDir` is a runtime function parameter, not a compile-time literal, so Turbopack's build-time file-tracing analyzer can't statically narrow the several dynamic `readdirSync`/`rmSync`/`readFileSync`/`writeFileSync` call sites a few lines below and falls back to a project-wide glob; #6366's commit message claimed to "anchor the base path with a literal" but the shipped code never did. Since this fs access is legitimate and bounded (`skills//SKILL.md`, ~48 known IDs), `next.config.mjs`'s `turbopack.ignoreIssue` (Next.js 16.2+) now suppresses this specific, known-benign diagnostic, mirroring the existing `webpack.ignoreWarnings`/`isNextIntlExtractorDynamicImportWarning` precedent already in the same file for the webpack path. Regression guard: `tests/unit/next-config.test.ts` (asserts the `turbopack.ignoreIssue` rule shape targeting `src/lib/agentSkills/**`). - **fix(cli):** per-agent AgentBridge DNS toggle was broken for 8 of the 9 supported agents, and a failed MITM startup step could orphan the spawned proxy child — `addDNSEntry`/`removeDNSEntry` (`src/mitm/dns/dnsConfig.ts`) always resolved the legacy Antigravity default hosts regardless of which agent's toggle was flipped, so enabling DNS for Cursor/Codex/Claude Code/etc. silently added only `daily-cloudcode-pa.googleapis.com` while the DB recorded `dns_enabled=true` for the selected agent. Both functions now accept an optional `agentId` and resolve hosts via `ALL_TARGETS`; `POST /api/tools/agent-bridge/agents/[id]/dns` passes the route's `id` through and now returns 404 for an id that doesn't match a known target instead of silently falling back. Separately, `startMitmInternal()` (`src/mitm/manager.ts`) now wraps `generateCert()` (log + rethrow), the `provisionDnsEntries()` call, and the PID-file write in try/catch so a mid-startup failure can't orphan the already-spawned MITM child process. On Windows, `addDNSEntries`/`removeDNSEntries` also batch every missing/present entry into a single elevated PowerShell invocation instead of one UAC prompt per host line. Regression guard: `tests/unit/dns-config-generic.test.ts` (agent-specific resolution + batching), `tests/unit/agent-bridge-dns-route-validation.test.ts` (404 for unknown agent id). ([#6338](https://github.com/diegosouzapw/OmniRoute/pull/6338) — thanks @hamsa0x7) - **fix(guardrails):** Vision Bridge's individual-model auto-reroute (route an image-bearing request straight to a vision-capable model instead of describe-then-forward) could bypass a policy-restricted API key's model allowlist/budget ([#6640](https://github.com/diegosouzapw/OmniRoute/pull/6640)) — `VisionBridgeGuardrail.preCall()` (`src/lib/guardrails/visionBridge.ts`) swaps `body.model` to the best available vision-capable model, but that swap happens in the guardrail pipeline AFTER `chat.ts` already called `enforceApiKeyPolicy()` against the ORIGINAL model, so a key scoped to a narrow `allowedModels` list could still execute against an unvetted (and possibly costlier) vision model the reroute picked. `chat.ts` now re-validates any guardrail-driven model change against the same per-key allowlist (`isModelAllowedForKey`) before honoring it, falling back to the original already-approved model when the reroute target is not allowed. The reroute path also now honors an explicit `settings.visionBridgeModel` operator override (previously ignored, unlike the combo/describe path a few lines below it, which already respects it via `getVisionBridgeConfig`). Regression guard: `tests/unit/guardrails/visionBridge.test.ts` (22 tests). (thanks @herjarsa) - **fix(auth):** an API key restricted via `allowedModels`/`allowedCombos` could bypass that restriction entirely over the Codex Responses-over-WebSocket bridge ([#6564](https://github.com/diegosouzapw/OmniRoute/issues/6564)) — `prepare()` in `src/app/api/internal/codex-responses-ws/route.ts` authenticated the WS bridge's API key (`authenticate()`/`authorizeWebSocketHandshake()`) and honored `allowedConnections`, but never called `enforceApiKeyPolicy()`, the same model/combo policy gate the HTTP `/v1/responses` path enforces via `handleChat()` — so a key scoped to e.g. `combo/model-1.0` could still reach a direct Codex model like `gpt-5.5` through this transport, as long as an eligible Codex OAuth connection existed. The bridge's WS auth token arrives via query params (`api_key`/`token`/`access_token`), not a normal `Authorization` header, so a new `enforceCodexWsApiKeyPolicy()` builds an equivalent `Request` carrying an explicit `Authorization: Bearer ` header and calls `enforceApiKeyPolicy()` against the CLIENT-requested model, before any Codex-specific model remapping or credential selection. Regression guard: `tests/unit/codex-ws-policy-enforcement-6564.test.ts` (a model-restricted key is rejected 403 before reaching credential selection; a combo-restricted key is rejected 403 requesting a disallowed combo; a key that DOES allow the requested model still proceeds past policy). diff --git a/next.config.mjs b/next.config.mjs index 5f1d884f74..ac7197503c 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -116,6 +116,24 @@ const nextConfig = { ...mitmManagerAliasFor(process.env), ...minimalBuildAliases, }, + // src/lib/agentSkills/generator.ts builds its fs base path from a runtime + // `outputDir` parameter (`path.join(process.cwd(), outputDir)`), which is + // NOT a compile-time literal, so Turbopack's build-time file-tracing + // analyzer can't statically narrow the several dynamic readdirSync/rmSync/ + // readFileSync/writeFileSync call sites a few lines below and falls back + // to an "Overly broad patterns... matches N files" warning — once per + // Next.js entry point that imports the module (/api/agent-skills/generate, + // /api/cli-tools/pi-settings). The fs access is legitimate and bounded + // (skills//SKILL.md, ~48 known IDs), so this is a known-benign, + // expected diagnostic — suppress it here rather than fight the analyzer, + // mirroring the isNextIntlExtractorDynamicImportWarning precedent below + // for the webpack path. (#6582) + ignoreIssue: [ + { + path: "**/src/lib/agentSkills/**", + description: /Overly broad patterns can lead to build performance issues/, + }, + ], }, output: "standalone", compress: true, diff --git a/tests/unit/next-config.test.ts b/tests/unit/next-config.test.ts index e3bd946643..29821fa4ec 100644 --- a/tests/unit/next-config.test.ts +++ b/tests/unit/next-config.test.ts @@ -271,6 +271,23 @@ test("next-intl webpack hook preserves caller config and filters known extractor ); }); +test("turbopack.ignoreIssue suppresses the agentSkills over-bundling warning (#6582)", async () => { + // src/lib/agentSkills/generator.ts joins process.cwd() with a runtime + // `outputDir` parameter — not a compile-time literal — so Turbopack's + // file-tracing analyzer can't narrow it and emits an "Overly broad + // patterns..." warning per entry point importing the module. The fs access + // is legitimate and bounded, so it's suppressed via turbopack.ignoreIssue + // rather than fought. This guards the config shape so the suppression rule + // isn't silently dropped in a future edit. + const { default: nextConfig } = await loadNextConfig("ignore-issue"); + const rules = nextConfig.turbopack?.ignoreIssue; + + assert.ok(Array.isArray(rules), "expected turbopack.ignoreIssue to be an array"); + const agentSkillsRule = rules.find((rule) => String(rule.path).includes("agentSkills")); + assert.ok(agentSkillsRule, "expected an ignoreIssue rule targeting src/lib/agentSkills/**"); + assert.match(String(agentSkillsRule.description), /Overly broad patterns/); +}); + test("optimizePackageImports excludes the internal @omniroute/open-sse workspace (build-OOM guard)", async () => { // Regression guard: adding the internal `@omniroute/open-sse` workspace to // optimizePackageImports makes Next.js resolve its entire barrel at build