Repository navigation
feat(pii): apply PII middleware to the Open Responses API - #12708
Conversation
|
@mudler Code-review sign-off at I found and fixed one bypass in The docs also clarify an existing limitation: stored history from Reviewed against master Validation: an isolated module running the actual adapter and its actual Ginkgo specs, with only schema/PII carrier types stubbed, produced 12 passing and four failing specs before the fix, then 16 passing specs afterward. I independently repeated the passing run. This does not validate route or WebSocket integration. The repository package tests failed to compile because generated protobuf types ( The fix commit carries Assisted-by attribution but no fabricated human Signed-off-by trailer. A human must certify that commit, and the full CI suite still needs to validate the branch before merging. |
93f96c2 to
5221828
Compare
|
Pushed two commits on top: the first is #12755 ( |
The per-model PII filter ran on /v1/chat/completions, /v1/completions,
/v1/messages and the Ollama routes, but not on POST /v1/responses. A
model whose policy blocks or masks a secret on the chat route served the
same content unfiltered when it was sent through the Responses API.
Add a piiadapter.OpenResponses adapter and wire pii.RequestMiddleware
into the POST /v1/responses and /responses chain, after the model config
is resolved and merged and before the handler converts input items into
prompt messages. The adapter covers instructions, input as a string, and
in an input item array the text of message and reasoning items (string
content or input_text/output_text parts, including typeless
{role, content} items), function_call arguments and function_call_output
output; structured tool output is scanned as the JSON the handler
forwards. Image, file, audio and video parts are left untouched.
The Responses WebSocket mode (GET /v1/responses) is not HTTP middleware
and cannot filter, so a response.create for a model with PII filtering
enabled is now refused with pii_unsupported_transport instead of being
served unfiltered. The docs list the new route and this limit.
Tests: adapter specs for every covered field, each with a clean-text
counter-check; a route spec driving the real middleware chain with an
in-process pattern detector (block on string input, content part,
instructions and tool output; mask; clean input passes unchanged); and
WebSocket specs proving the refusal and that models without a PII
policy are still served.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Stefan Walcz <stefan.walcz@walcz.de>
The Responses handler forwards non-string tool output as JSON. Scan that full encoding so string arrays and extra fields cannot bypass PII filtering. Cover array scans, redaction, clean values and route blocking. Document that stored history is resolved after request filtering. Assisted-by: Codex:gpt-6 Signed-off-by: Stefan Walcz <stefan.walcz@walcz.de>
Extend block_unscanned_media to /v1/responses: input_image, input_file and input_audio parts inside message items, and the same types as bare input items, are reported as unscanned content. Tool output stays allowed, as it is scanned as JSON text. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Stefan Walcz <stefan.walcz@walcz.de>
242e1cb to
407fb2c
Compare
Description
The PII middleware (
pii.RequestMiddleware) protects/v1/chat/completions,/v1/completions,/v1/mcp/chat/completions, the Anthropic and the Ollama routes, but not the Open Responses API. A deployment that blocks or masks PII with a detector policy could therefore be bypassed by sending the same content toPOST /v1/responses(or/responses).This PR:
piiadapter.OpenResponses()for the Open Responses request schema:instructions,inputas a string, andinputitems — message items (string content orinput_text/output_textparts), reasoning content,function_callarguments andfunction_call_output(string, text parts, or object output scanned as the JSON the handler sends to the model). Image/file/audio/video parts are left untouched, like in the other adapters.openResponsesMiddleware()so the route test runs the real chain.GET /v1/responses: messages on the socket do not pass through HTTP middleware. Rather than serving them unfiltered, the socket handler now refuses withpii_unsupported_transportwhen the model has PII enabled with at least one detector (the same condition the HTTP middleware uses). Models without a PII policy are served as before.docs/content/operations/middleware.mdlists/v1/responses, the covered fields and the known limits (requests whosemodelnames an agent are routed byAgentResponsesInterceptorbefore model resolution and stay unfiltered, as before).Notes for Reviewers
core/services/routing/piiadapter30/30 (12 new),core/services/routing/pii76/76,core/http/endpoints/openresponses68/68 (3 new),core/http/routes203/203 (4 new). Each detect/redact spec has a counter-check that clean input stays byte-identical. Removing the middleware turns 3 of 4 route specs red; disabling the WebSocket guard turns the refusal spec red.make lint(golangci-lint not installed here) and the e2e suites.Signed commits
🤖 Generated with Claude Code