Conversation
…laim
Add generic claim-gated candidate selection. Candidates carry a `labels`
map; the filter carries `match_claims: [{claim, label}]`. Per request the
filter reads the claim off the authenticated identity and keeps only
candidates whose matching label equals it, so a request is never routed
outside the caller's entitlement (data residency, tier, and so on).
The gate reuses the AuthenticatedIdentity extension the policy engine
already publishes, so no new plumbing is added. It fails closed: a gate
with no identity or a missing claim denies. A fenced-out capability
returns the same 404 as an unknown one, so a caller cannot enumerate the
capabilities it is fenced out of. The ungated path is unchanged and
allocates nothing new; a gate also fences session-affinity reuse and
weighted selection, so no draw lands out of scope.
Both static and overlay candidate modes carry the label, so a fleet
registry can drive the fence through the hot-reloaded overlay.
Signed-off-by: Sam Batschelet <sbatsche@redhat.com>
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.
Summary
Adds a generic, config-driven fence to
intelligent_route. Candidates carry alabelsmap, andmatch_claimskeeps only candidates whose label equals a claim on the authenticated identity, before the model-name pick. Adding an entitlement dimension (residency, tier, sovereignty) is configuration, not code.It fails closed. When a request carries no authenticated identity, is missing the gated claim, or matches no in-scope candidate, the gateway denies it rather than routing. A fenced-out capability returns the same 404 as an unknown one, so a caller cannot enumerate what it is fenced out of. Session-affinity reuse and weighted selection both respect the fence. The ungated path (no
match_claims) is unchanged and allocates nothing new. It reuses theAuthenticatedIdentityextensiontoken_rate_limitalready reads, so it adds no new plumbing.Matching is exact-equality only. Richer operators (range, hierarchy, set membership) are out of scope and can be added later without breaking this config.
Granting a user an entitlement
The fence holds no per-user state. The entitlement rides in the caller's token as a claim, sourced from the IdP (for example a Keycloak user attribute mapped into the JWT). alice's token carries:
{ "sub": "alice", "grid_region": "eu-west-1", "tier": "gold" }The gateway validates the token, lands
grid_regionon the authenticated identity, andmatch_claimskeeps only candidates whoseregionlabel equals it, so alice routes to theeu-west-1site. Granting or changing alice's residency is an IdP change (set the attribute), never a gateway change. A second dimension is the same move: the IdP addsgrid_tier, and the config adds{ claim: grid_tier, label: tier }plus atierlabel on candidates.Related issue
Closes #1282
Validation
cargo test -p praxis-ai-filters --lib routing::gives 405 passed. Covers matching, unlabeled-candidate exclusion, no-eligible-member, weighted-draws-stay-in-scope, validation bounds, fail-closed-without-identity, and the ungated-unchanged path.intelligent-route-claim-gating.yamlplus a fail-closed integration test.make lintclean. Commits are signed with aSigned-off-bytrailer.Breaking changes
None.
match_claimsandlabelsdefault empty, so existing configs route exactly as before.