Skip to content

Python: Harden FIDES core policy foundation - #9875

Draft
Eduard van Valkenburg (eavanvalkenburg) wants to merge 2 commits into
mainfrom
fides-core-policy-foundation
Draft

Eduard van Valkenburg (eavanvalkenburg) wants to merge 2 commits into
mainfrom
fides-core-policy-foundation

Conversation

@eavanvalkenburg

@eavanvalkenburg Eduard van Valkenburg (eavanvalkenburg) commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Motivation & Context

A private security review identified cases where FIDES could validate or execute a tool call with weaker authority than
the hidden values and runtime arguments inspected by policy. Invalid tool metadata could also fall back to permissive
defaults, and opaque session state containing lone Unicode surrogates could fail durable serialization.

This first replacement layer establishes the core FIDES policy foundation for later transport and replay layers. It
keeps policy checks ahead of hidden-value materialization and validator execution, binds authorization to exact
materialized arguments and runtime kwargs, and preserves JSON-safe session state.

Description & Review Guide

  • What are the major changes?
    • Parse FIDES tool metadata through one fail-closed policy parser and audit invalid declarations as
      invalid_policy.
    • Resolve hidden references into a detached preflight snapshot, then materialize and validate only after every
      policy middleware authorizes the call.
    • Revalidate exact argument and runtime authority at the final handler and on retries, including task-local pipeline
      isolation and direct tool invocation.
    • Encode durable FIDES state with ASCII escapes so lone surrogates round-trip through JSON and MessagePack stores.
    • Add focused regressions in test_security.py and update the FIDES developer guidance.
  • What is the impact of these changes?
    • Blocked calls no longer expose expanded hidden values to Pydantic validators or mutate live invocation arguments.
    • Unknown, mistyped, or incorrectly cased security metadata blocks execution instead of weakening policy.
    • Post-policy argument/runtime mutations and unsafe retry reuse fail closed.
    • Validation passed:
      • cd python && uv run --directory packages/core pytest tests/test_security.py -q -k 'invalid_tool_policy_is_blocked or hidden_surrogate_round_trips_in_file_session_store or all_reference_forms_resolve_and_block_untrusted_arguments or blocked_hidden_value_never_reaches_argument_validator or later_policy_blocks_before_hidden_value_validation or equal_value_reference_substitution_fails_closed or runtime_kwarg_mutation_after_approval_fails_closed or runtime_session_substitution_after_approval_fails_closed or callable_policy_blocks_before_hidden_value_validation or hidden_argument_retry_rematerializes_from_original_reference or retry_after_policy_revalidates_materialized_runtime_authority'
        • Passed.
      • cd python && uv run --directory packages/core pytest tests/test_security.py -q
        • Passed.
      • cd python && uv run poe syntax -P core
        • Passed.
      • cd python && uv run poe pyright -P core
        • Passed with 0 errors and 0 warnings.
      • cd python && uv run poe test-typing -P core
        • Passed all five configured test type checkers.
      • cd python && uv run poe test -P core
        • Passed: 9,098 passed, 20 skipped, and 2 xfailed.
  • What do you want reviewers to focus on?
    • The preflight-to-materialization boundary in security.py and the minimal final-handler hooks in
      _middleware.py and _tools.py.
    • This layer intentionally excludes replay/history reconstruction, approval replay/binding, service-history
      continuation, AG-UI transport, and MCP result/carrier handling. Those remain later replacement layers.

Related Issue

N/A - security hardening based on a privately reported issue. Per SECURITY.md, vulnerability details are not tracked
in a public GitHub issue; maintainer direction was explicitly confirmed before implementation. This draft is layer 1
of the replacement stack for #9652 and isolates only the core policy foundation rather than competing with the full
mixed-scope implementation.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: GitHub Copilot assisted with adapting the implementation, regression tests, documentation, and
this PR description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI balanced review requested due to automatic review settings October 30, 2026 08:48
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python labels Oct 30, 2026
@github-code-quality

github-code-quality Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Python

Python / code-coverage/python

main 4d4e216 fides-core-policy-fo... b04ad3b +/-
92% 92% 0%
View coverage of the 3 most impacted files.
File main 4d4e216 fides-core-policy-fo... b04ad3b +/-
packages/core/a...ework/_tools.py 95% 95% 0%
packages/core/a.../_middleware.py 96% 96% 0%
packages/core/a...ork/security.py 90% 91% +1%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 30, 2026 13:46 UTC

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical authorization gaps omit runtime kwargs from checks, materialize hidden values before policy approval, and permit validator-transformed arguments to execute without renewed authorization.

3 open issues
What changed in this PR

This PR establishes the core Python FIDES hardening layer, separating policy preflight from hidden-value materialization ahead of later transport and replay work.

Changes:

  • Centralizes fail-closed tool metadata parsing and audits invalid declarations.
  • Adds detached argument preflight and invocation-boundary authority checks.
  • Makes durable state surrogate-safe and adds regression tests and developer guidance.
File Description
python/​samples/​02-agents/​security/​FIDES_DEVELOPER_GUIDE.md Documents authorization ordering and strict metadata validation.
python/​packages/​core/​tests/​test_security.py Adds policy, hidden-value, runtime-mutation, retry, and serialization regressions.
python/​packages/​core/​agent_framework/​security.py Implements policy parsing, detached preflight, authority checks, and ASCII-escaped state.
python/​packages/​core/​agent_framework/​_tools.py Adds a materialization hook to tool invocation.
python/​packages/​core/​agent_framework/​_middleware.py Tracks active pipelines and materializes arguments before the final handler.

Review effort: Balanced

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 6e36e0bcee9d
Model: gpt-5.6-sol

Overview

The PR centralizes FIDES metadata parsing, separates hidden-value preflight from materialization, and adds final-handler and retry checks backed by focused regressions. Its task-local materialization state is reset reliably, and recognized invalid metadata values now fail closed. Two residual gaps remain: misspelled security keys can still remove a declared restriction, and unsupported runtime authority is omitted from mutation binding.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (1 high, 1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/core/agent_framework/security.py

args = cast(Any, context.arguments)
if isinstance(args, Mapping) and arg_name in args:
return cast(Any, args[arg_name]), "arguments"
return _top_level_argument_value_from(context.arguments, context.kwargs, arg_name)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to pass this to a new function? can't we just update this one?


def _top_level_argument_keys(context: FunctionInvocationContext) -> set[str]:
"""Union of top level keys in context.arguments and context.kwargs."""
return _top_level_argument_keys_from(context.arguments, context.kwargs)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

This branch was previously deployed

1 inactive deployment
github-app-auth — b04ad3be Deployed Oct 30, 2026 by eavanvalkenburg via add_label #26681
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants