ogar-rbac: mint the canonical RBAC authority, fed by ogar-auth's user - #301
Merged
Merged
Conversation
Establishes the ownership seam:
ogar-auth = canonical user + authentication bindings
ogar-rbac = authorization over that canonical user
ogar-rbac depends on ogar-auth deliberately. The edge is the point: there
is no way to ask this crate a question without first holding an
AuthenticatedUser, which only ogar-auth can produce, so "RBAC does not
accept an arbitrary parallel identity normalizer" becomes a property the
compiler checks rather than a convention.
ogar-auth::user realizes vocabulary that was already minted rather than
inventing an IAM model: auth_store (0x0B01) -> UserStore, project_actor
(0x0104) -> User/UserId, project_role (0x0117) -> User::roles,
project_membership (0x0108) -> User::memberships. Providers stay data,
as auth_store's own is-a children already model them: ProviderId is an
opaque label, never an enum, so a new IdP is a preminted class with a
different claim_grammar row and not a new match arm. The envelope every
path converges on is the contract's existing ActorContext -- reused, not
re-declared, which is what keeps a second identity type from appearing.
UserStore maps identities; it does not release secrets. User carries
opaque KeyRefs and there is deliberately no aggregate accessor, so an
identity lookup cannot quietly become unrestricted key retrieval.
Kiosk is preserved as a first-class mode: an unauthenticated user takes
the same authorization path and yields the same decision, because roles
belong to the identity and never to the login method.
What did NOT move: the generic authorize/authorize_scoped kernel stays in
lance-graph-rbac and is consumed, never cloned; the contract stays
zero-dep and is never reached into from OGAR.
The authority is an OBJECT (OgarRbac), not `impl ClassRbac for
OgarClassView` -- that is E0117 from any third crate, and sharing a
repository does not change Rust coherence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGkLH5cYiiWM4QmNkvBBvf
AdaWorldAPI
marked this pull request as ready for review
September 6, 2026 13:46
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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.
What
Establishes the ownership seam the ruling fixed:
ogar-rbacdepends onogar-authdeliberately. The edge is the point: there is no way to ask this crate a question without first holding anAuthenticatedUser, which onlyogar-authcan produce — so "RBAC does not accept an arbitrary parallel identity normalizer" is a property the compiler checks, not a convention.ogar-auth::userrealizes already-minted vocabularyIt invents no IAM model. The classes exist:
auth_store0x0B01UserStoreproject_actor0x0104User/UserIdproject_role0x0117User::rolesproject_membership0x0108User::membershipsauth_zitadel/auth_ory_keto…0x0B02+AuthBinding::providerProviders stay data, exactly as
auth_store's ownis-achildren already model them (claim_grammaras an attribute).ProviderIdis an opaque label, never an enum — a new IdP is a preminted class with a different row, not a new match arm.The envelope every path converges on is the contract's existing
ActorContext— reused, not re-declared, which is what stops a second identity type appearing.No secret aggregation
UserStoremaps identities; it does not release secrets.Usercarries opaqueKeyRefs and there is deliberately no aggregate accessor, so an identity lookup cannot quietly become unrestricted key retrieval.Kiosk preserved
An unauthenticated kiosk user takes the same authorization path and yields the same decision — roles belong to the identity, never to the login method.
a2ui-rshas zero files touched.What did NOT move
authorize/authorize_scopedkernel stays inlance-graph-rbac— consumed, never cloned.lance-graph-contractstays zero-dep; OGAR only ever depends downward on it.CapabilityAuthority/ hotplug untouched — orthogonal.The authority is an object (
OgarRbac), notimpl ClassRbac for OgarClassView: that is E0117 from any third crate, and sharing a repository does not change Rust coherence.Tests
ogar-auth19/19,ogar-rbac7/7, fmt +clippy -D warningsclean. Falsifiers covered: wide{1,7,92}projection, canonical-identity ownership, orphan legality, kiosk parity, provider ignorance (no provider branching), two bindings → one user, key-reference-not-material.Depends on AdaWorldAPI/lance-graph#1206 (Axis-4 widening); the git deps point at that branch and move to
mainwhen it merges.🤖 Generated with Claude Code
https://claude.ai/code/session_01PGkLH5cYiiWM4QmNkvBBvf
Generated by Claude Code