Repository navigation
contract + rbac: walk_rails_authorized and visible_fields (H7) - #1558
Conversation
…op (H7) The access decision already produced a field mask per class, but nothing in lance-graph removed the hidden fields from an output. walk_rails_authorized adds one mask to the walk's AND at every hop -- view.mask, presence, and the mask allowed for that hop's own class -- so a hidden field is never emitted at any depth and a hidden rail is not followed. The mask argument returns a WideFieldMask, not an Option, so there is no permit-all fallback. walk_rails is unchanged and delegates with no decision. 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
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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. |
A refused decision keeps the open default in field_mask, documented as irrelevant on refusal. Fed to walk_rails_authorized it would show every field of a class the actor may not read. visible_fields() returns field_mask only when the decision allows, EMPTY otherwise; the walk's docs point at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3e0c28792
ℹ️ 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".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
One page: the identity -> actor -> roles -> decision -> output pipeline, the four axes and how each combines, the rules that are easy to get wrong (admin is a role, mask-less roles get the class default, refused decisions carry an open mask, hidden rails hide what is behind them), and the 2026-10-14 decision that access control stays policy data keyed by classid and never hand-rolls reasoning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
What
The access decision already returns a field mask per class (
Decision.field_mask, which folds the role masks and the class default from #1556). Until now, nothing in lance-graph used that mask to remove hidden fields from an output. This PR adds the step that does.selection::walk_rails_authorizedis the same walk aswalk_rails, plus one mask in the AND at every hop:allowedreturns aWideFieldMask, not anOption. A class the reader may not read returnsEMPTYand emits nothing.The step is policy data only: the walk applies the caller's decision and decides nothing itself.
walk_railsis unchanged; it now delegates with no decision.Refused decisions show nothing
ScopedDecisionandMembershipDecisionkeep the open default infield_maskwhen access is refused; that field is documented as irrelevant on refusal. Passed straight into the walk, it would show every field of a class the reader may not read.The new method
visible_fields()returns the mask only when the decision allows access, andEMPTYotherwise. The walk's docs tell callers to use it.Tests:
a_refused_decision_shows_no_fieldsfails if the method returnsfield_maskunconditionally.an_allowed_decision_shows_its_field_maskchecks the allowed case.Tests
There are four new tests,
selection::tests::authorized_walk_*:Two disable runs show the tests depend on the new step:
cargo test -p lance-graph-contract: all suites pass.clippy -D warningsis clean.Access-control model document
.claude/knowledge/access-control-model.mdcovers:Not in this PR
ogar-doc-ir'sresolve_doccallswalk_rails. Passing a decision through to it is a separate OGAR PR.lance-graph-report-ogar) have no per-field positions to mask, so they are not covered here.🤖 Generated with Claude Code
https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
Generated by Claude Code