microsoft / microsoft/agent-governance-toolkit
RFC: verifiable residency across delegation chains (implements ADR-0008 problems 4 and 5)
- Dominant language
- Python
- Stars
- 6.3k
- Forks
- 1.1k
- Avg merge
- 5d 11h
- Merged PRs (30d)
- 142
Description
## Summary
ADR-0008 identified data residency and trust-tier composition as open problems (numbers 4 and 5 of the five raised in #1386) and deliberately scoped them to "framing decisions" rather than concrete answers. Neither has been implemented. This RFC proposes closing both, together, because they turn out to be the same problem: residency is only meaningful if it survives delegation, and delegation is only safe if residency composes.
The concrete gap: ADR-0008 models residency as declared metadata (`PolicyMetadata.processing_regions: list[str]`, `AgentPolicyClaims.data_residency`). A declared region string is unverifiable. Nothing binds it to evidence, and nothing carries it across more than one hop. So an agent can satisfy every check ADR-0008 specifies and still route data out of its permitted jurisdiction through a sub-agent, with no record that it happened.
## Motivation
Three reasons this is worth doing now.
**1. It is already on the roadmap and has stalled.** #1386 raised it in April. ADR-0008 answered problems 1 to 3 and deferred 4 and 5. Both ADR-0007 and ADR-0008 are still `proposed`, and neither has landed in code: `AgentPolicyClaims`, `PolicyMetadata`, `processing_regions` and `PolicyFederationProvider` have zero implementations in the Python tree today. The one `data_residency` occurrence is an unrelated optional field in `agent-os/nexus`.
**2. The regulatory date referenced in the original discussion has now passed.** #1386 and ADR-0008 both cite EU AI Act Article 12 record-keeping, enforcement 2026-08-02. That date is behind us. AGT ships an Annex IV exporter (`governance/annex_iv.py`) and an evidence pipeline (`governance/evidence_pipeline.py`), so the toolkit already takes conformity documentation seriously. Residency is the one obligation in that family with no mechanism behind it.
**3. The declared-versus-verified distinction is where sovereignty claims actually fail.** Deploying in an EU region is necessary and not sufficient. If an agent delegates and the sub-agent calls an endpoint outside the permitted set, the deployment was compliant and the data flow was not. This is the failure mode a regulator will ask about, and today no part of AGT can answer.
Worked example, which is the acceptance test I would want:
> A resource owner permits processing in `FR` only. A lead agent delegates summarisation to a sub-agent, which calls a model endpoint that is EU-branded but served from a region outside `FR`. Every component behaved as configured. Expected behaviour: the delegation fails closed before any data moves, and the resulting record lets a third party verify that it failed closed.
## Detailed Design
Deliberately specified as required properties and interface surface rather than a chosen mechanism. Mechanism detail is a follow-up, see "staging" below.
**Properties the design must satisfy**
1. **Attested, not declared.** A jurisdiction assertion must be backed by evidence, not a configuration string. Concretely, it must bind to (a) attestation evidence for what is running, and (b) a signed statement from an identified, accountable operator for where it is running. These are separate roots of trust with different strengths, and the design must not conflate them. See Security Implications.
2. **Composes transitively.** A residency constraint must intersect across every hop of a delegation chain and must never widen. This is the same monotonicity property already enforced for capabilities by `identity/delegation.py` (`ScopeChain`, `DelegationLink`), so the mechanism should reuse that machinery rather than parallel it.
3. **Fails closed, pre-flight.** Enforcement happens at derivation time, before data moves, consistent with ADR-0008's pre-flight framing. An out-of-jurisdiction delegation is never issued rather than detected afterwards.
4. **Offline-verifiable.** A relying party must be able to recompute the residency verdict from the record with no live call to any participant. AGT already has the substrate for this in `governance/audit.py` Merkle chaining and `governance/decision_bom.py`.
5. **Graduated conformance.** A declared region and an attested one must not be indistinguishable to a verifier. The design needs explicit levels so a deployer cannot read the weakest form as the strongest.
**Interface surface affected**
- `governance/policy_evaluator.py` and `governance/async_policy_evaluator.py`: jurisdiction becomes a predicate in evaluation, deny-by-default rather than absent.
- `identity/delegation.py`: `DelegationLink` carries a jurisdiction assertion; `ScopeChain.verify()` gains a residency check alongside capability narrowing.
- `governance/federation.py`: `PolicyCategory` has `DATA_EXPORT` but it carries no geography. This is where ADR-0008's `processing_regions` would actually land.
- `identity/attestation.py`: attestation evidence needs to carry, or reference, the placement statement.
- `identity/provider_chain.py`: an EU trust-list-backed provider is additive under ADR-0007, which is why this does not require reworking identity.
- `governance/decision_bom.py`: residency verdict becomes part of reconstructible decision context.
**Staging.** I would propose this as two RFCs rather than one. This RFC settles whether the capability is wanted, where it lands, and what properties it must satisfy. A second RFC specifies the mechanism and data model. I am splitting it because the mechanism has an intellectual-property review in flight and I do not want to hold up the direction decision on that, nor pre-empt it. If maintainers would rather see the whole thing at once, say so and I will wait and post one RFC.
## Alternatives Considered
**Extend ADR-0008 rather than a new RFC.** Attractive, and my first instinct. Rejected because ADR-0008 is a policy-federation document whose problems 1 to 3 are coherent and implementable on their own. Bolting an attestation-backed jurisdiction model into it would roughly double its scope and stall the parts that are ready. ADR-0008 should land as-is.
**Declared regions only, matching ADR-0008 as written.** Cheapest option and it is what the ADR currently specifies. Rejected because an unverifiable residency claim is worse than none: it creates documented, auditable confidence in a property nobody checked. If the project prefers this, my strong suggestion is to label it explicitly as declared-only so it cannot be mistaken for enforcement.
**Detect after the fact instead of enforcing pre-flight.** Cheaper, and post-hoc detection is where most of the industry sits. Rejected on the evidence: the best published agentic attack detector (Uber's ADR) reports 67% of attacks caught at zero false positives on ADR-Bench, which is state of the art and still misses roughly one in three. A residency violation that is detected 67% of the time is not a control a regulator will accept. Detection and evidence compose; neither substitutes for the other.
**Do it outside AGT entirely.** Discussed under Target Placement below, because it is really a placement question rather than a design alternative.
## Security Implications
**The limitation that most matters, stated plainly.** Hardware attestation proves what code is running. It does not prove where the machine is. There is no trustworthy geography in an SEV-SNP or TDX report, because nothing in the silicon knows what country it is in.
So this design cannot deliver cryptographic proof of location, and any RFC claiming otherwise would be wrong. What it can deliver is a split claim:
- **What is running:** hardware-rooted, verifiable offline against a vendor root, requiring no trust in the operator. Strong.
- **Where it is running:** rooted in a signed statement from an identified operator. This is operator-trust, not hardware-trust. An operator with physical control of the machine can defeat it.
The security property gained is therefore non-repudiation rather than prevention: an operator has signed a statement, bound to a specific attested instance, that is attributable to them afterwards. I think that is the strongest claim available and the RFC should say so in those words, so that no deployer reads more into it.
Additionally out of scope, and worth naming so it is not assumed: an adversary with physical access to the host is not defended against here, and per published work on TEE fault and memory attacks, is not currently defended against by any shipping confidential-computing silicon.
New attack surface introduced: the placement statement becomes a forgery target, and the trust list that roots operator identity becomes an availability and integrity dependency in the policy path. Both need treatment in the mechanism RFC.
## Migration / Backward Compatibility
No breaking changes intended. Jurisdiction is absent today, so every construct is additive. Two compatibility notes:
- Deny-by-default on jurisdiction only applies once a policy declares a permitted set. Policies that say nothing about jurisdiction behave exactly as they do now.
- `ScopeChain.verify()` gaining a residency check is additive for chains carrying no jurisdiction assertion.
Timing note: this touches the policy evaluation path, which the ACS v5 migration (#3444) and the cedarling removal (#3451) also touched recently. I would rather build on top of settled ACS v5 than land alongside it. Happy to sequence behind whatever is still in flight, and I would appreciate a pointer on what that is.
## Scope
Cross-package (2 to 3 packages). Primarily `agent-mesh`, touching `agent-os` policy surfaces.
## Target Placement
This is the question I most want maintainer input on, and I would rather ask it openly than assume an answer.
Sovereign deployment brings dependencies that AGT may reasonably not want to carry: eIDAS-anchored trust lists, EUDI wallet identity, EU-operated key custody profiles, and jurisdiction-specific policy packs. Those are European regulatory plumbing. They date, they need maintenance by someone tracking EU rulemaking, and they are useful to a subset of AGT users.
Three options as I see them:
1. **In `agent-mesh` directly.** Best for coherence, since delegation and attestation already live there. Worst for maintenance burden, since AGT inherits EU regulatory plumbing.
2. **A separate package inside AGT.** Keeps it in the project with a clean dependency boundary. Someone still has to maintain the EU-specific parts.
3. **A separate sovereign-scoped project, reusing `agent-mesh` under MIT with attribution.** Lowest burden on AGT. Costs some coherence and risks drift.
I have a preference for 3 and an interest in declaring it, so discount it accordingly: I would be the one maintaining it, and I would rather carry EU regulatory tracking myself than ask this project to. I am also conscious that I wrote much of the delegation and trust-scoring code in question, which is a reason to be more careful about proposing to take it elsewhere, not less. If maintainers prefer 1 or 2, I will implement it here and that is a good outcome.
If 3 is the answer, I would want it to be explicit and on the record rather than a quiet fork: a distinct distribution name (not `agentmesh-platform`), Microsoft copyright headers and attribution preserved, upstream contribution of anything genuinely general, and no claim on the AGT name.
## Prior Art
- #1386, which raised all five problems. This RFC addresses 4 and 5.
- ADR-0007 (external JWKS federation), ADR-0008 (cross-org policy federation), both `proposed`. ADR-0009 (RFC 9334 RATS alignment) is `accepted` and is the attestation vocabulary this should align to rather than reinvent.
- IDSA Rulebook and Gaia-X: usage-control contracts and connector-mediated policy enforcement, mature for datasets. The gap is that a data space contract assumes a dataset moving between two connectors, whereas agents delegate and compose calls at runtime, so the contracted party is not necessarily the party that touches the data. That mismatch is the substance of this RFC.
- Google DeepMind, February 2026, on delegation as a transfer of authority, responsibility and accountability requiring zero-trust verification. Framework-level, no implementation.
- W3C DIDs and Verifiable Credentials, and Cisco AGNTCY's agent identity framework, for the identity substrate. Note that the crowded part of the landscape (Entra Agent ID, Okta XAA, Auth0 for GenAI, AGNTCY) is caller-side identity. None of them make jurisdiction a policy predicate or compose it across delegation, which is what this RFC is about.
- EU AI Act Regulation 2024/1689 Articles 11 and 12, and Annex IV, already partly served by `governance/annex_iv.py`.
## Checklist
- [x] I have searched existing issues and RFCs for duplicates (#1386, #1234, #1385, #3043 reviewed; #1386 is the direct predecessor)
- [x] I have read the ADR index for related decisions
- [x] I am willing to implement this RFC or help review an implementation
Contributor guide
Research direction
Start with ADR-0008 and the mentioned entry points in identity/delegation.py, governance/policy_evaluator.py, identity/attestation.py, and governance/decision_bom.py. First resolve the target placement and maintainer direction, then define the mechanism and data model in a follow-up RFC. Done means the capability and boundaries are accepted before implementation begins.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authorization, backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100