feat(policy): IsActiveAdmin field + AllowActionFromChainP entry point
Lays the rails for the consolidation refactor — the decider gains a
single admin-bypass branch at the top of InternalDecider.Allow, and a
new principal-aware entry point computes IsActiveAdmin from chain +
Principal.Elevated. No caller uses the new path yet, so behavior is
unchanged; lock-in tests stay green.
AllowInput.User.IsActiveAdmin bool // caller-computed bypass flag
AllowActionFromChainP(ctx, d, chain, p, path, action) (bool, error)
The decider's branch:
if input.User.IsActiveAdmin { return true, nil }
is the ONLY admin escape hatch in the package. Strict-ancestor rule
for .zddc edits is preserved inside AllowActionFromChainP via
IsAdminForChain(chain, email, excludeLeaf=true) when action==ActionAdmin.
Email-only entry points (AllowFromChain, AllowActionFromChain) leave
IsActiveAdmin=false implicitly — they're for read-path callers that
don't need admin bypass (directory listing, archive index, profile
read endpoints).
Next commits: migrate authorizeAction and plan-review's pre-flight
to AllowActionFromChainP, then delete the scattered IsAdmin/
IsSubtreeAdmin/CanEditZddc early-outs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1c0777a847
commit
465d2f605c
1 changed files with 50 additions and 0 deletions
|
|
@ -73,6 +73,20 @@ import (
|
||||||
type AllowInput struct {
|
type AllowInput struct {
|
||||||
User struct {
|
User struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
// IsActiveAdmin is true when the caller has admin authority on
|
||||||
|
// THIS chain AND has opted into admin powers for this request.
|
||||||
|
// The CALLER is responsible for computing it (it depends on the
|
||||||
|
// chain and on Principal.Elevated, both known at the call site);
|
||||||
|
// the decider consults it as a short-circuit at the top of
|
||||||
|
// Allow. This is the single bypass point — every write that
|
||||||
|
// should ignore WORM/ACL for an elevated admin flows through it,
|
||||||
|
// every read that should ditto.
|
||||||
|
//
|
||||||
|
// Callers using the email-only entry points (AllowFromChain,
|
||||||
|
// AllowActionFromChain) get IsActiveAdmin=false implicitly —
|
||||||
|
// they're saying "ignore admin bypass for this lookup." Callers
|
||||||
|
// that want the bypass use AllowActionFromChainP.
|
||||||
|
IsActiveAdmin bool `json:"is_active_admin,omitempty"`
|
||||||
} `json:"user"`
|
} `json:"user"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Action string `json:"action,omitempty"`
|
Action string `json:"action,omitempty"`
|
||||||
|
|
@ -219,6 +233,17 @@ func (d *InternalDecider) Allow(_ context.Context, input AllowInput) (bool, erro
|
||||||
verb := actionVerb(input.Action)
|
verb := actionVerb(input.Action)
|
||||||
email := input.User.Email
|
email := input.User.Email
|
||||||
|
|
||||||
|
// Single admin-bypass site. The caller has already verified that
|
||||||
|
// the principal (a) holds an admins: grant somewhere in this chain
|
||||||
|
// and (b) has opted into admin powers (Elevated). When both are
|
||||||
|
// true, any action is permitted — WORM zones included — preserving
|
||||||
|
// the human escape hatch for mis-filed documents. No other site in
|
||||||
|
// the codebase grants admin authority; every write that should
|
||||||
|
// bypass ACL/WORM flows through this one branch.
|
||||||
|
if input.User.IsActiveAdmin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WORM zone: a directory whose cascade declares `worm:` (see
|
// WORM zone: a directory whose cascade declares `worm:` (see
|
||||||
// defaults.zddc.yaml — archive/<party>/received and issued carry
|
// defaults.zddc.yaml — archive/<party>/received and issued carry
|
||||||
// `worm: {}`) is write-locked. Inside it, the effective verbs
|
// `worm: {}`) is write-locked. Inside it, the effective verbs
|
||||||
|
|
@ -354,6 +379,31 @@ func AllowActionFromChain(ctx context.Context, d Decider, chain zddc.PolicyChain
|
||||||
return d.Allow(ctx, in)
|
return d.Allow(ctx, in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllowActionFromChainP is the principal-aware entry point. Computes
|
||||||
|
// IsActiveAdmin from the chain + Principal.Elevated and threads it
|
||||||
|
// into AllowInput, so the decider's single admin-bypass branch fires
|
||||||
|
// when (and only when) the caller actually holds elevated admin
|
||||||
|
// authority on this chain.
|
||||||
|
//
|
||||||
|
// Strict-ancestor rule for .zddc edits: action == ActionAdmin signals
|
||||||
|
// a .zddc write, and IsAdminForChain is called with excludeLeaf=true
|
||||||
|
// so the leaf .zddc's own admins entry cannot authorize editing the
|
||||||
|
// file that grants it. Other actions use the full chain walk.
|
||||||
|
//
|
||||||
|
// Use this entry point in write-path handlers (file API, plan-review,
|
||||||
|
// accept-transmittal). Read-path callers that don't need admin
|
||||||
|
// bypass can stay on AllowActionFromChain / AllowFromChain — they
|
||||||
|
// implicitly leave IsActiveAdmin=false.
|
||||||
|
func AllowActionFromChainP(ctx context.Context, d Decider, chain zddc.PolicyChain, p zddc.Principal, path, action string) (bool, error) {
|
||||||
|
excludeLeaf := action == ActionAdmin
|
||||||
|
isAdmin := p.Elevated && p.Email != "" &&
|
||||||
|
zddc.IsAdminForChain(chain, p.Email, excludeLeaf)
|
||||||
|
in := AllowInput{Path: path, Action: action, PolicyChain: chainToSerializable(chain)}
|
||||||
|
in.User.Email = p.Email
|
||||||
|
in.User.IsActiveAdmin = isAdmin
|
||||||
|
return d.Allow(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
// cachingDecider wraps another Decider with a small per-decision cache.
|
// cachingDecider wraps another Decider with a small per-decision cache.
|
||||||
// Designed for the external-OPA hot path: a single .archive listing or
|
// Designed for the external-OPA hot path: a single .archive listing or
|
||||||
// directory enumeration can hit the same (email, dir-policy) tuple
|
// directory enumeration can hit the same (email, dir-policy) tuple
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue