-- File: lean/AuthSpec.lean -- RBAC Authorization Algebra -- Agents migrate Python source to TypeScript. -- This spec is the ground truth — their code is tested against it. namespace AuthSpec -- Core types structure Permission where resource : String action : String deriving BEq, Repr, DecidableEq structure Role where name : String permissions : List Permission inherits : List String -- role names this role inherits from deriving Repr, DecidableEq -- Flattened role map for lookup abbrev RoleMap := List Role -- Look up a role by name def findRole (roles : RoleMap) (name : String) : Option Role := roles.find? (fun r => r.name == name) -- Check direct permission (no inheritance) def hasDirectPermission (role : Role) (resource action : String) : Bool := role.permissions.any (fun p => p.resource == resource && p.action == action) -- Internal: depth-limited access check (structural recursion on Nat avoids optParam issues) def canAccessAux (roles : RoleMap) (roleName resource action : String) : Nat → Bool | 0 => false | n + 1 => match findRole roles roleName with | none => false | some role => hasDirectPermission role resource action || role.inherits.any (fun parentName => canAccessAux roles parentName resource action n) -- Public API: check permission with inheritance (depth-5 bound is more than enough) def canAccess (roles : RoleMap) (roleName resource action : String) : Bool := canAccessAux roles roleName resource action 5 -- Key invariants agents' code must satisfy -- If the role is not in the map, access is always denied theorem deny_if_no_role (roles : RoleMap) (roleName resource action : String) (h : findRole roles roleName = none) : canAccess roles roleName resource action = false := by simp [canAccess, canAccessAux, h] -- Direct permission grants access theorem direct_permission_grants_access (roles : RoleMap) (r : Role) (resource action : String) (hfound : findRole roles r.name = some r) (hperm : hasDirectPermission r resource action = true) : canAccess roles r.name resource action = true := by simp [canAccess, canAccessAux, hfound, hperm] end AuthSpec