fix(guardrails): restore injection-guard logging on middleware-only r… - #12117
Merged
diegosouzapw merged 1 commit intoAug 30, 2026
Conversation
…outes PR diegosouzapw#11936 removed the console fallback from the prompt-injection guard to deduplicate log output, but the dedupe premise only holds for chat-family routes, where guardrailRegistry.runPreCallHooks re-evaluates the request with the pino logger. The 13 middleware-only routes (/v1/embeddings, /v1/images/*, /v1/audio/speech, /v1/moderations, /v1/rerank, /v1/ocr, /v1/search, /v1/segment, /v1/classify, /v1/videos/generations, /v1/music/generations) call createInjectionGuard() with no logger, so a blocked (400) or flagged injection attempt left zero server-side trace. The fix distinguishes an omitted logger (console fallback restored, so middleware-only routes log again) from an explicit logger: null (silence, now opted into by the five double-evaluated chat-family callsites), preserving the diegosouzapw#11936 dedupe. Validated by: node --import tsx/esm --test tests/unit/injection-guard-nonchat-route-logging.test.ts (3 subtests fail before the fix, 5/5 pass after).
5 tasks
diegosouzapw
merged commit Aug 30, 2026
1b2c6f4
into
diegosouzapw:release/v3.8.51
8 of 16 checks passed
diegosouzapw
added a commit
that referenced
this pull request
Aug 30, 2026
…align 7 tests to merged contracts No new ESLint warnings: the exact CI command (lint:json --max-warnings 0) reports 278 problems on the tip — 226 from eslint-plugin-react-hooks 7 compiler rules (set-state-in-effect 167, immutability 36, refs/static-components/purity/ preserve-manual-memoization) that were masked until the lockfile change of dfc84ba invalidated the ESLint cache, plus 46 no-explicit-any in tests/unit/call-log-cap.test.ts (#12026). Velocity phase: frozen with `eslint --suppress-all` (+668 suppressions); the 5 now-unused `eslint-disable react-hooks/immutability` directives and one unused import removed. Verified: lint:json --max-warnings 0 → 0 problems. Tests aligned to contracts merged this afternoon (all reproduced red on the pure tip): - providers-constants-split: 235 → 236 (Perplexity Agent, #12103) - sse-auth: a forced pin outside allowedConnections now yields no credential instead of silently falling back (#12080) - with-chat-admission-10786: withInjectionGuard(postHandler, { logger: null }) (#12117) - hard-session-lease-bypass-inventory: classify src/app/api/oauth/codex/import/route.ts (#12116) - usage-service-hardening: OpenCode Go official usage API shape (#12124) - i18n placeholder parity: apiManager.restrictedToConnections rewritten as a plain ICU plural (`{count, plural, one {# connection} other {# connections}}`) in en, vi, pt-BR and the 40 __MISSING__ mirrors — the parity extractor counts every `{word}` including the old literal `{s}` Refs #12103, #12080, #12117, #12116, #12124, #12026
diegosouzapw
added a commit
that referenced
this pull request
Aug 30, 2026
…e/v3.8.51 (round 5: provider count 352, TS2554/TS2677) (#12144) * fix(ci): clear the base-reds the 2026-08-30 afternoon merge batch left on release/v3.8.51 (round 5) - docs-counts / check-docs-counts-sync test: #12103 (Perplexity Agent) made it 352 providers; README, AGENTS.md, llm.txt (+42 i18n mirrors), package.json description and the 4 README diagrams still said 351. - api-route-typecheck: #11971 passes a third `{ featureEnabled }` argument to appendNoThinkingVariants() that the helper never accepted (TS2554 — and the flag silently did nothing); the helper now honours it. src/lib/skills/interception.ts narrowed a mapped object with a `Record<string, string>` predicate (TS2677) — predicate typed with the actual element shape. Gates: check:docs-counts OK (test 28/28), check:docs-sync PASS, check:api-typecheck OK (289 frozen). Refs #12103, #11971 * docs(env): document RATE_LIMIT_EXECUTION_MAX_WAIT_MS (#12027 added it to .env.example only) * fix(ci): round 5b — freeze the react-hooks compiler-rule violations, align 7 tests to merged contracts No new ESLint warnings: the exact CI command (lint:json --max-warnings 0) reports 278 problems on the tip — 226 from eslint-plugin-react-hooks 7 compiler rules (set-state-in-effect 167, immutability 36, refs/static-components/purity/ preserve-manual-memoization) that were masked until the lockfile change of dfc84ba invalidated the ESLint cache, plus 46 no-explicit-any in tests/unit/call-log-cap.test.ts (#12026). Velocity phase: frozen with `eslint --suppress-all` (+668 suppressions); the 5 now-unused `eslint-disable react-hooks/immutability` directives and one unused import removed. Verified: lint:json --max-warnings 0 → 0 problems. Tests aligned to contracts merged this afternoon (all reproduced red on the pure tip): - providers-constants-split: 235 → 236 (Perplexity Agent, #12103) - sse-auth: a forced pin outside allowedConnections now yields no credential instead of silently falling back (#12080) - with-chat-admission-10786: withInjectionGuard(postHandler, { logger: null }) (#12117) - hard-session-lease-bypass-inventory: classify src/app/api/oauth/codex/import/route.ts (#12116) - usage-service-hardening: OpenCode Go official usage API shape (#12124) - i18n placeholder parity: apiManager.restrictedToConnections rewritten as a plain ICU plural (`{count, plural, one {# connection} other {# connections}}`) in en, vi, pt-BR and the 40 __MISSING__ mirrors — the parity extractor counts every `{word}` including the old literal `{s}` Refs #12103, #12080, #12117, #12116, #12124, #12026 * fix(ci): run the ESLint warnings job on the box with an 8 GB heap; reserved-prefix set 398 → 400 The cold full lint with the react-hooks 7 compiler rules is killed on the 7 GB hosted runner with no message (status null → exit 1, JSON never written) — it only looked green while the ESLint cache was warm. tests/unit/provider-node-reserved-prefix.test.ts aligned to the two prefixes the afternoon batch registered (#12103). * test(ci): document the lint-guard runner exception; #9147 event-loop gap 400 → 800 ms quality-rail-gate-membership pinned lint-guard to ubuntu-latest; the cold full lint is OOM-killed there, so the job now runs on omni-light with an 8 GB heap — the test keeps fast-gates pinned and asserts the documented exception. With the catalog at 352 providers the hosted shards measure 410–633 ms gaps on 9147-catalog-eventloop-yield (3 runs); 800 ms still fails a true pin. Re-tighten with the v4.0 catalog split. * chore(quality): summarize the ESLint report on failure — a red lint:json printed nothing --format json --output-file swallows every problem; a red 'No new ESLint warnings' job gave zero output (three blind debugging rounds in #12144), and a killed process (OOM, status null) was equally silent. On any non-zero exit the runner now prints the problem count and the first 60 'file:line rule — message' lines from the report. * chore(lint): freeze react-hooks/immutability for the 5 UI test harnesses in the suppressions file The rule fires for these files in CI but not locally (compiler analysis divergence), so the inline eslint-disable directives read as 'unused directive' warnings locally. A suppressions entry is symmetric: suppressed where the rule fires, tolerated as unpruned (--pass-on-unpruned-suppressions) where it does not. Found via the new lint:json failure summary.
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…outes (diegosouzapw#12117) Restaura o log do injection-guard nas 13 rotas não-chat (embeddings, images, audio, moderations, etc.) — a correção de log duplicado anterior (diegosouzapw#11936) silenciou completamente o único emissor de log dessas rotas, deixando tentativas de injeção sem rastro nenhum em modo warn, e sem log mesmo quando bloqueadas em modo block. Achado de segurança real (Finding 2 do diegosouzapw#12113). Teste próprio (141 linhas). Validado no worktree combinado. Obrigado!
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…e/v3.8.51 (round 5: provider count 352, TS2554/TS2677) (diegosouzapw#12144) * fix(ci): clear the base-reds the 2026-08-30 afternoon merge batch left on release/v3.8.51 (round 5) - docs-counts / check-docs-counts-sync test: diegosouzapw#12103 (Perplexity Agent) made it 352 providers; README, AGENTS.md, llm.txt (+42 i18n mirrors), package.json description and the 4 README diagrams still said 351. - api-route-typecheck: diegosouzapw#11971 passes a third `{ featureEnabled }` argument to appendNoThinkingVariants() that the helper never accepted (TS2554 — and the flag silently did nothing); the helper now honours it. src/lib/skills/interception.ts narrowed a mapped object with a `Record<string, string>` predicate (TS2677) — predicate typed with the actual element shape. Gates: check:docs-counts OK (test 28/28), check:docs-sync PASS, check:api-typecheck OK (289 frozen). Refs diegosouzapw#12103, diegosouzapw#11971 * docs(env): document RATE_LIMIT_EXECUTION_MAX_WAIT_MS (diegosouzapw#12027 added it to .env.example only) * fix(ci): round 5b — freeze the react-hooks compiler-rule violations, align 7 tests to merged contracts No new ESLint warnings: the exact CI command (lint:json --max-warnings 0) reports 278 problems on the tip — 226 from eslint-plugin-react-hooks 7 compiler rules (set-state-in-effect 167, immutability 36, refs/static-components/purity/ preserve-manual-memoization) that were masked until the lockfile change of 9d8554f invalidated the ESLint cache, plus 46 no-explicit-any in tests/unit/call-log-cap.test.ts (diegosouzapw#12026). Velocity phase: frozen with `eslint --suppress-all` (+668 suppressions); the 5 now-unused `eslint-disable react-hooks/immutability` directives and one unused import removed. Verified: lint:json --max-warnings 0 → 0 problems. Tests aligned to contracts merged this afternoon (all reproduced red on the pure tip): - providers-constants-split: 235 → 236 (Perplexity Agent, diegosouzapw#12103) - sse-auth: a forced pin outside allowedConnections now yields no credential instead of silently falling back (diegosouzapw#12080) - with-chat-admission-10786: withInjectionGuard(postHandler, { logger: null }) (diegosouzapw#12117) - hard-session-lease-bypass-inventory: classify src/app/api/oauth/codex/import/route.ts (diegosouzapw#12116) - usage-service-hardening: OpenCode Go official usage API shape (diegosouzapw#12124) - i18n placeholder parity: apiManager.restrictedToConnections rewritten as a plain ICU plural (`{count, plural, one {# connection} other {# connections}}`) in en, vi, pt-BR and the 40 __MISSING__ mirrors — the parity extractor counts every `{word}` including the old literal `{s}` Refs diegosouzapw#12103, diegosouzapw#12080, diegosouzapw#12117, diegosouzapw#12116, diegosouzapw#12124, diegosouzapw#12026 * fix(ci): run the ESLint warnings job on the box with an 8 GB heap; reserved-prefix set 398 → 400 The cold full lint with the react-hooks 7 compiler rules is killed on the 7 GB hosted runner with no message (status null → exit 1, JSON never written) — it only looked green while the ESLint cache was warm. tests/unit/provider-node-reserved-prefix.test.ts aligned to the two prefixes the afternoon batch registered (diegosouzapw#12103). * test(ci): document the lint-guard runner exception; diegosouzapw#9147 event-loop gap 400 → 800 ms quality-rail-gate-membership pinned lint-guard to ubuntu-latest; the cold full lint is OOM-killed there, so the job now runs on omni-light with an 8 GB heap — the test keeps fast-gates pinned and asserts the documented exception. With the catalog at 352 providers the hosted shards measure 410–633 ms gaps on 9147-catalog-eventloop-yield (3 runs); 800 ms still fails a true pin. Re-tighten with the v4.0 catalog split. * chore(quality): summarize the ESLint report on failure — a red lint:json printed nothing --format json --output-file swallows every problem; a red 'No new ESLint warnings' job gave zero output (three blind debugging rounds in diegosouzapw#12144), and a killed process (OOM, status null) was equally silent. On any non-zero exit the runner now prints the problem count and the first 60 'file:line rule — message' lines from the report. * chore(lint): freeze react-hooks/immutability for the 5 UI test harnesses in the suppressions file The rule fires for these files in CI but not locally (compiler analysis divergence), so the inline eslint-disable directives read as 'unused directive' warnings locally. A suppressions entry is symmetric: suppressed where the rule fires, tolerated as unpruned (--pass-on-unpruned-suppressions) where it does not. Found via the new lint:json failure summary.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…outes
PR #11936 removed the console fallback from the prompt-injection guard to deduplicate log output, but the dedupe premise only holds for chat-family routes, where guardrailRegistry.runPreCallHooks re-evaluates the request with the pino logger. The 13 middleware-only routes (/v1/embeddings, /v1/images/*, /v1/audio/speech, /v1/moderations, /v1/rerank, /v1/ocr, /v1/search, /v1/segment, /v1/classify, /v1/videos/generations, /v1/music/generations) call createInjectionGuard() with no logger, so a blocked (400) or flagged injection attempt left zero server-side trace. The fix distinguishes an omitted logger (console fallback restored, so middleware-only routes log again) from an explicit logger: null (silence, now opted into by the five double-evaluated chat-family callsites), preserving the #11936 dedupe. Validated by: node --import tsx/esm --test tests/unit/injection-guard-nonchat-route-logging.test.ts (3 subtests fail before the fix, 5/5 pass after).
Summary
Related Issues
Validation
Choose the change type and focused loop from the
Contribution Golden Path. The full unit suite,
Vitest, the 60% coverage gate, and the production build all run in CI on this PR (#8329):
npm run lintTests Added Or Updated
Coverage Notes
src/,open-sse/,electron/, orbin/, explain which tests cover the change.Reviewer Notes