Files
rose-ash/lib/acl/engine.sx
giles fe47334e52
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 56s
acl: Phase 1 direct grants + deny-overrides, 24 tests
Datalog ACL layer (schema/facts/engine/api) over lib/datalog/. Direct
grant permits unless explicit deny names same (S,A,R) — deny-overrides
via stratified negation. Conformance wrapper + scoreboard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:32:13 +00:00

30 lines
1.2 KiB
Plaintext

;; lib/acl/engine.sx — ACL ruleset + decision reducer over lib/datalog/.
;;
;; The engine is a thin layer: it owns the permit ruleset (SX data rules) and
;; reduces a (subject, action, resource) decision to a Datalog query against a
;; db built from EDB facts. The rule engine itself is Datalog's.
;;
;; Phase 1 policy — direct grants with deny-overrides:
;;
;; permit(S, A, R) :- grant(S, A, R), not deny(S, A, R).
;;
;; A grant permits unless an explicit deny names the same (S, A, R). Deny wins:
;; the negated literal {:neg (deny S A R)} stratifies cleanly because deny is an
;; EDB relation (no rule derives it), so the fixpoint is well-defined.
(define
acl-phase1-rules
(quote ((permit S A R <- (grant S A R) {:neg (deny S A R)}))))
;; Build a Datalog db from a list of EDB facts under the Phase 1 ruleset.
(define acl-build-db (fn (facts) (dl-program-data facts acl-phase1-rules)))
;; Core decision: does the db permit subject S to perform action A on
;; resource R? Reduces to a ground Datalog query on the derived `permit`
;; relation — non-empty result means permitted.
(define
acl-permit?
(fn
(db subj act res)
(> (len (dl-query db (list (quote permit) subj act res))) 0)))