diff --git a/backend/__tests__/unit/helm/litellmStagingEnabled.test.js b/backend/__tests__/unit/helm/litellmStagingEnabled.test.js index 4b03a8de3e..8a8e9872ce 100644 --- a/backend/__tests__/unit/helm/litellmStagingEnabled.test.js +++ b/backend/__tests__/unit/helm/litellmStagingEnabled.test.js @@ -61,3 +61,18 @@ describe('staging LiteLLM is enabled so native-runtime agents (Scout) can answer expect(tol == null || (Array.isArray(tol) && tol.length === 0)).toBe(true); }); }); + +describe('staging native runtime runs injection-guard only (no real OpenAI moderation key)', () => { + test('nativeRuntimeGuardrails is injection-guard — matches prod', () => { + // The native runtime's default guardrail pair includes openai-moderation-enforce, + // which calls OpenAI's moderation API with OPENAI_API_KEY. Staging's openai-api-key is + // an 11-byte placeholder (as prod's was), so that guardrail returned HTTP 401 on EVERY + // native turn before the model call — the second half of the 2026-10-31 Scout-staging + // incident. injection-guard is LiteLLM-native (no key, no external service). If staging + // ever drops this override, enabling litellm alone will not make Scout answer. + expect(staging.backend.env.nativeRuntimeGuardrails).toBe('injection-guard'); + // Prod carries the identical override; keep them in lockstep until a real OpenAI + // moderation key lands in the api-keys secret and both can restore the pair together. + expect(staging.backend.env.nativeRuntimeGuardrails).toBe(dev.backend.env.nativeRuntimeGuardrails); + }); +}); diff --git a/k8s/helm/commonly/values-staging.yaml b/k8s/helm/commonly/values-staging.yaml index 83cd90dad6..e0149a4c20 100644 --- a/k8s/helm/commonly/values-staging.yaml +++ b/k8s/helm/commonly/values-staging.yaml @@ -160,6 +160,18 @@ litellm: backend: env: + # injection-guard ONLY — matches prod (values-dev.yaml). The native runtime's + # default guardrail pair (nativeRuntimeService.ts) includes openai-moderation-enforce, + # which calls OpenAI's moderation API with OPENAI_API_KEY. Staging's api-keys + # openai-api-key is an 11-byte placeholder (prod's is the literal "placeholder" too), + # so that guardrail 401'd on EVERY native turn BEFORE the model call — litellm logged + # 401 from https://api.openai.com/v1/moderations and returned HTTP 401 for + # deepseek-v4-flash. This was the second half of the 2026-10-31 Scout-staging incident: + # enabling litellm (above) fixed the missing-backend 401, this fixes the guardrail 401. + # injection-guard is LiteLLM-native (no key, no external service) and keeps the + # prompt-injection block. Restore the pair only after a real OpenAI moderation key + # lands in the staging api-keys secret. Guard test: litellmStagingEnabled.test.js. + nativeRuntimeGuardrails: "injection-guard" agentComputerEnabled: "true" agentComputerSteelApiUrlTemplate: "http://steel-{userId}.commonly-staging.svc.cluster.local:3000" agentComputerSteelCdpUrlTemplate: "http://steel-{userId}.commonly-staging.svc.cluster.local:9223"