Repository navigation
rbac: RBAC hot-plug socket (contract::rbac_plug, additive) - #1404
Conversation
The hotplug.rs pattern applied to authorization. contract::rbac_plug: RbacPlug (one const per consumer: classids + role names), RbacAuthority (implemented by OGAR), RbacBinding (private fields, no Default, Result lookups, grants and masks bounded to the plug), RbacDrift (named refusals), ActorSource + PluggedRbac (the ClassRbac view; out-of-plug questions deny), and verify_concepts_against_mirror. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing (6)
✨ Finishing Touches📝 Generate docstrings
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Comment |
impl RbacAuthority for OgarRbac<S>: binds a consumer's RbacPlug to the source's grants. Plugged classids must be minted in ogar-vocab and agree with the contract mirror; plugged roles must be defined by the source. GrantSource gains defaulted defines_role and field_mask_of. Pairs with AdaWorldAPI/lance-graph#1404 (contract::rbac_plug). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4855a3873
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .map(|(role, gs)| { | ||
| let kept = gs | ||
| .into_iter() | ||
| .filter(|g| classids.contains(&g.target_classid)) |
There was a problem hiding this comment.
Filter bindings to the plug's declared roles
When an authority supplies grant rows beyond plug.roles—for example, by loading its complete grant table—this constructor filters only by class ID and retains every role. If the actor source reports one of those undeclared roles, grants_for finds it and PluggedRbac::grant_permits authorizes access even though the consumer omitted that role from its plug. Pass the declared role set into construction and reject or discard grants and masks for roles outside it.
Useful? React with 👍 / 👎.
| fn field_mask(&self, role: RoleId, class: ClassId) -> WideFieldMask { | ||
| match self.binding.field_mask_for(role, class) { | ||
| Ok(Some(mask)) => mask.clone(), | ||
| Ok(None) => WideFieldMask::from(FieldMask::FULL), |
There was a problem hiding this comment.
Preserve unrestricted fields beyond position 63
For a class with more than 64 fields, omitting a field mask is documented as unrestricted, but this fallback sets only the low 64 bits; the existing WideFieldMask::full_for documentation explicitly requires the field count to represent all fields in a wide class. Consequently, an unrestricted grant on classes such as the 109-field motivating case silently loses every field at position 64 or above in authorize_memberships and authorize_scoped. The binding must carry enough schema width to construct a full mask, or require an explicit mask for wide classes.
Useful? React with 👍 / 👎.
This applies the
hotplug.rspattern to authorization. A consumer declares one const naming the classes it gates and the roles it uses. OGAR, as the authority, binds that const to its grant data. The consumer then pairs the binding with its own source of actors and gets aClassRbacthat the existing kernels accept. This removes the hand-copied policy tables, such as MedCare-rs'smedcare-rbac, and the role masks callers supply themselves, such as a2ui-rs's.Changes
New module
lance-graph-contract::rbac_plug. All of it is additive and nothing existing changes.RbacPlug { consumer, classids, roles }: the consumer's one const. Roles areRoleIdnames.RbacAuthority::bind(&RbacPlug) -> Result<RbacBinding, RbacDrift>: implemented by the authority. The OGAR implementation inogar-rbacis the paired next PR.RbacBinding: private fields, noDefault, and every lookup (plugged,grants_for,permits,field_mask_for) returns aResult. Grants and field masks on classes outside the plug are dropped when the binding is built, so it can't carry access the plug didn't ask for.declared_grantsis the audit surface.RbacDrift: named refusals:UnknownClassid,UnknownRole,NotPlugged,RoleNotPluggedandMirrorDrift.verify_concepts_against_mirroris the RBAC twin ofhotplug::verify_against_mirror.ActorSource+PluggedRbac: theClassRbacview. Roles and memberships come from the actor source, grants and masks from the binding. A question outside the plug is a denial, and it gets an empty field mask. Scopes come from memberships, so decide withauthorize_memberships.Tests and disable runs
plug_tests) that runs a bound binding throughauthorize_membershipswith a physician in two practices. clippy-D warningsand fmt are clean.pluggedaccepting any class;Board
entries/2026-10-08-rbac-hotplug-socket.md(index regenerated) and theLATEST_STATEdelta.Next
impl RbacAuthority for OgarRbac<S>, as a paired PR. It builds against lance-graphmain, so its CI stays red until this PR merges.🤖 Generated with Claude Code
https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
Generated by Claude Code