Python: fix FIDES session isolation and runtime integration gaps - #7528
Open
lerelerele wants to merge 1 commit into
Open
Python: fix FIDES session isolation and runtime integration gaps#7528lerelerele wants to merge 1 commit into
lerelerele wants to merge 1 commit into
Conversation
FIDES kept conversation scoped security state on shared middleware instances, so a single Agent or middleware instance serving more than one conversation could leak context labels, audit records and pending approvals across conversation boundaries. A blocked tool call also terminated the invocation loop without a visible result, which could reach the user as an empty response. Move conversation scoped state into AgentSession.state and address the A1 to C3 items from microsoft#7455: - A1: context label, audit log, pending approvals and counters live in AgentSession.state; variable stores are keyed per session. - A2: a blocked call returns a correlated function_result instead of terminating with no content, so the model can explain the refusal or choose another action. Approval requests still pause for the user. - A3: audit records carry a per run turn and a per call call_index instead of the constant -1. - B1: new tool_labels configuration for tools the application did not construct, such as harness and MCP tools. - B2: approval request additional_properties propagate into the reconstructed function call. - B3: standing approval rules and auto approval callbacks can no longer approve a FIDES policy violation. - B4: new public build_function_call_content() extension point; the former private method remains as an alias. - B5: new deny_untrusted_tools; deny takes precedence over allow. - C1: new enable_quarantine=False so labels and policy enforcement can be used without quarantine tooling. - C2: the quarantine client is bound to the current async context instead of a process global slot. - C3: MCP read only tools receive a PUBLIC confidentiality cap, since their arguments still leave the process, with a granular mark_read_tools_as_sinks opt out. Also hardens durable state: label metadata is sanitized before it reaches session storage, and the audit log is capped per session with a configurable limit. Middleware order is unchanged, and direct middleware calls made without an AgentSession keep working through explicit fallbacks. Adds 21 regression tests in tests/test_fides_7455_regressions.py.
lerelerele
temporarily deployed
to
github-app-auth
August 5, 2026 11:33 — with
GitHub Actions
Inactive
lerelerele
had a problem deploying
to
github-app-auth
August 5, 2026 11:33 — with
GitHub Actions
Error
lerelerele
temporarily deployed
to
github-app-auth
August 5, 2026 11:33 — with
GitHub Actions
Inactive
lerelerele
temporarily deployed
to
github-app-auth
August 5, 2026 11:33 — with
GitHub Actions
Inactive
Author
|
@microsoft-github-policy-service agree |
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.
I have implemented the A1 to C3 items from this issue locally and I would like to open a PR for it. Flagging it here first, per the repo's suggested workflow, since it is a sizeable change and it touches behavior.
What it covers
The core change is architectural: conversation scoped FIDES state moves out of shared middleware attributes and into
AgentSession.state, so a middleware orAgentinstance reused across concurrent conversations can no longer leak context labels, audit records or pending approvals between them.AgentSession.state; variable stores are keyed per session.function_resultinstead of terminating the loop with no content, so the model can explain the refusal or choose another action. Approval requests still pause for the user.turnand a per callcall_indexinstead of the constant-1.tool_labelsconfiguration for tools the application did not construct, such as harness and MCP tools.additional_propertiespropagate into the reconstructed function call.build_function_call_content()extension point, with the former private method kept as an alias.deny_untrusted_tools, where deny takes precedence over allow.enable_quarantine=False, so labels and policy enforcement can be used without quarantine tooling.mark_read_tools_as_sinksopt out that leaves the write side gate untouched.Middleware order is unchanged, and direct middleware calls made without an
AgentSessionkeep working through explicit fallbacks.Observable behavior changes
Every symbol this touches is marked
@experimental(feature_id=ExperimentalFeature.FIDES), so I have not treated this as a breaking change, but I want these four called out before anyone reviews the diff:exception, so it participates inmax_consecutive_errors_per_request. With the default limit, three consecutive blocked calls disable tools for the remainder of that request. This is a deliberate circuit breaker against retry loops.readOnlyHint=Truenow getmax_allowed_confidentiality=PUBLICby default.set_quarantine_client()is context local rather than process global, and theSecureAgentConfigconstructor no longer registers the client.before_run()binds it, and it never clears a client another caller installed.session. Without one they resolve the last session seen in the current async context.If you would rather treat any of these as breaking, say so and I will follow the process for that instead.
Two additions this issue did not ask for
I would like agreement on these before opening the PR, since new APIs are supposed to be discussed first:
max_audit_log_entries(default 1000,Nonefor unlimited). Once the audit log lives inAgentSession.stateit is serialized to durable storage, so an unbounded log would grow the session payload without limit.begin_turn(session). A3 asks for a real turn number, and without a run boundary hook the counter can only be per tool call, which is not what the audit field means.What it does not cover
This does not address #7466. It does not make
SecureAgentConfigthe default, does not add it to samples, and does not change the public documentation or learning path.Verification
Python 3.12. 21 new regression tests in
python/packages/core/tests/test_fides_7455_regressions.py, including one that asserts a blocked call leaves no unanswered function call in the invocation loop. Full core unit suite: 3926 passed, 18 skipped, 2 xfailed. Ruff format, Ruff check and Pyright are clean on the changed files.Open questions for maintainers
session.state["_fides"]key names and shape, since they become part of the durable session contract.AgentSessionmechanism rather than a session keyed store on the middleware.Happy to split this into smaller PRs per group if you prefer to review each fix independently.