Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TPE Lean model #548

Merged
merged 45 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fe79c65
prototype
shaobo-he-aws Feb 18, 2025
83e97af
updates
shaobo-he-aws Feb 18, 2025
b1dcd47
Updates
shaobo-he-aws Feb 21, 2025
a55d831
completely use Residual as inputs
shaobo-he-aws Feb 21, 2025
bc8d77d
assign meaning to Residual
shaobo-he-aws Feb 21, 2025
1444e57
I have no idea what I was doing but it kinda makes sense
shaobo-he-aws Feb 21, 2025
a55ae5e
restructure code
shaobo-he-aws Feb 22, 2025
e8ea818
prototype 0
shaobo-he-aws Feb 22, 2025
2a4f812
we can just use `TypedExpr` as the input
shaobo-he-aws Feb 23, 2025
5bf1f5b
bug fix
shaobo-he-aws Feb 23, 2025
5c1801b
updates
shaobo-he-aws Feb 24, 2025
b5b0660
Merge remote-tracking branch 'origin/main' into feature/shaobo/tpe-ex…
shaobo-he-aws Feb 24, 2025
558fdb3
updates
shaobo-he-aws Feb 24, 2025
6a35a7c
unit tests and fixes
shaobo-he-aws Feb 24, 2025
5a0a7a7
another test and fixes
shaobo-he-aws Feb 25, 2025
3d12849
clean up a little bit
shaobo-he-aws Feb 25, 2025
43e1c59
updates
shaobo-he-aws Feb 26, 2025
bff7c0d
Merge remote-tracking branch 'origin/main' into feature/shaobo/tpe-ex…
shaobo-he-aws Feb 26, 2025
d215e9f
concretization
shaobo-he-aws Feb 26, 2025
a3cba4e
Updates
shaobo-he-aws Feb 26, 2025
f524359
updates
shaobo-he-aws Feb 27, 2025
d111cc8
Updates
shaobo-he-aws Feb 27, 2025
bbe7c66
updates
shaobo-he-aws Feb 27, 2025
8875354
updates
shaobo-he-aws Feb 27, 2025
edca6a3
updates
shaobo-he-aws Feb 27, 2025
fe563f3
updates
shaobo-he-aws Feb 27, 2025
6f0491c
error function
shaobo-he-aws Feb 27, 2025
c38ca57
updates
shaobo-he-aws Feb 27, 2025
4cb69eb
Merge remote-tracking branch 'origin/main' into feature/shaobo/tpe-ex…
shaobo-he-aws Feb 27, 2025
e553a1d
bug fix and unit tests
shaobo-he-aws Feb 27, 2025
53165f7
remove ↦
shaobo-he-aws Feb 28, 2025
56c90a4
updates
shaobo-he-aws Feb 28, 2025
5814e1d
attrsOf
shaobo-he-aws Feb 28, 2025
c9e5f4f
tried to simplify termination proofs
shaobo-he-aws Feb 28, 2025
f545b9c
format
shaobo-he-aws Feb 28, 2025
e1df698
fix proof
shaobo-he-aws Feb 28, 2025
e12c25a
added comment
shaobo-he-aws Feb 28, 2025
8cd9dbc
clean up
shaobo-he-aws Feb 28, 2025
68608c8
more clean up
shaobo-he-aws Feb 28, 2025
9702bb0
error propagation
shaobo-he-aws Feb 28, 2025
251c653
more unit tests
shaobo-he-aws Mar 3, 2025
1f58453
Merge remote-tracking branch 'origin/main' into feature/shaobo/tpe-ex…
shaobo-he-aws Mar 3, 2025
0c3e505
datetime
shaobo-he-aws Mar 3, 2025
54dfbb8
Merge remote-tracking branch 'origin/main' into feature/shaobo/tpe-ex…
shaobo-he-aws Mar 3, 2025
5d884df
review feedback
shaobo-he-aws Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cedar-lean/Cedar.lean
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ import Cedar.Data
import Cedar.Spec
import Cedar.Thm
import Cedar.Validation
import Cedar.TPE
4 changes: 2 additions & 2 deletions cedar-lean/Cedar/Spec/Evaluator.lean
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ def getAttr (v : Value) (a : Attr) (es : Entities) : Result Value := do
let r ← attrsOf v es.attrs
r.findOrErr a attrDoesNotExist

def bindAttr (a : Attr) (res : Result Value) : Result (Attr × Value) := do
def bindAttr [Monad m] (a : Attr) (res : m α) : m (Attr × α) := do
let v ← res
.ok (a, v)
pure (a, v)

def evaluate (x : Expr) (req : Request) (es : Entities) : Result Value :=
match x with
Expand Down
19 changes: 19 additions & 0 deletions cedar-lean/Cedar/TPE.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/-
Copyright Cedar Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-/

import Cedar.TPE.Input
import Cedar.TPE.Residual
import Cedar.TPE.Evaluator
229 changes: 229 additions & 0 deletions cedar-lean/Cedar/TPE/Evaluator.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/-
Copyright Cedar Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-/

import Cedar.TPE.Input
import Cedar.TPE.Residual

namespace Cedar.TPE

open Cedar.Data
open Cedar.Spec
open Cedar.Validation

inductive Error where
| evaluation (err : Spec.Error)
| invalidPolicy (err : TypeError)
| invalidEnvironment
| invalidRequestOrEntities
deriving Repr, Inhabited, DecidableEq

instance : Coe Spec.Error Error where
coe := Error.evaluation

/- Convert an optional value to a residual: Return `.error ty` when it's none -/
def someOrError : Option Value → CedarType → Residual
| .some v, ty => .val v ty
| .none, ty => .error ty

/- Convert an optional value to a residual: Return `self` when it's none -/
def someOrSelf : Option Value → CedarType → Residual → Residual
| .some v, ty, _ => .val v ty
| .none, _, self => self

def varₚ (req : PartialRequest) (var : Var) (ty : CedarType) : Residual :=
match var with
| .principal => varₒ req.principal.asEntityUID
| .resource => varₒ req.resource.asEntityUID
| .action => varₒ req.action
| .context => varₒ (req.context.map (.record ·))
where
varₒ := (someOrSelf · ty (.var var ty))

def ite (c t e : Residual) (ty : CedarType) : Residual :=
match c with
| .val (.prim (.bool b)) _ => if b then t else e
| .error _ => .error ty
| _ => .ite c t e ty

def and : Residual → Residual → CedarType → Residual
| .val true _, r, _ => r
| .val false _, _, _ => false
| .error _, _, ty => .error ty
| l, .val true _, _ => l
| l, r, ty => .and l r ty

def or : Residual → Residual → CedarType → Residual
| .val true _, _, _ => true
| .val false _, r, _ => r
| .error _, _, ty => .error ty
| l, .val false _, _ => l
| l, r, ty => .and l r ty

def apply₁ (op₁ : UnaryOp) (r : Residual) (ty : CedarType) : Residual :=
match r with
| .error _ => .error ty
| _ =>
match r.asValue with
| .some v => someOrError (Spec.apply₁ op₁ v).toOption ty
| .none => .unaryApp op₁ r ty

def inₑ (uid₁ uid₂ : EntityUID) (es : PartialEntities) : Option Bool :=
if uid₁ = uid₂ then .some true else (es.ancestors uid₁).map (Set.contains · uid₂)

def inₛ (uid : EntityUID) (vs : Set Value) (es : PartialEntities): Option Bool := do
(← vs.toList.mapM (Except.toOption ∘ Value.asEntityUID)).anyM (inₑ uid · es)

def hasTag (uid : EntityUID) (tag : String) (es : PartialEntities) : Option Bool :=
(es.tags uid).map (Map.contains · tag)

def getTag (uid : EntityUID) (tag : String) (es : PartialEntities) (ty : CedarType) : Residual :=
match es.tags uid with
| .some tags => someOrError (tags.find? tag) ty
| .none => .binaryApp .getTag uid tag ty

def apply₂ (op₂ : BinaryOp) (r₁ r₂ : Residual) (es : PartialEntities) (ty : CedarType) : Residual :=
match op₂, r₁, r₂ with
| .eq, .val v₁ _, .val v₂ _ =>
.val (v₁ == v₂) ty
| .less, .val (.prim (.int i)) _, .val (.prim (.int j)) _ =>
.val (i < j : Bool) ty
| .less, .val (.ext (.datetime d₁)) _, .val (.ext (.datetime d₂)) _ =>
.val (d₁ < d₂: Bool) ty
| .less, .val (.ext (.duration d₁)) _, .val (.ext (.duration d₂)) _ =>
.val (d₁ < d₂: Bool) ty
| .lessEq, .val (.prim (.int i)) _, .val (.prim (.int j)) _ =>
.val (i ≤ j : Bool) ty
| .lessEq, .val (.ext (.datetime d₁)) _, .val (.ext (.datetime d₂)) _ =>
.val (d₁ ≤ d₂: Bool) ty
| .lessEq, .val (.ext (.duration d₁)) _, .val (.ext (.duration d₂)) _ =>
.val (d₁ ≤ d₂: Bool) ty
| .add, .val (.prim (.int i)) _, .val (.prim (.int j)) _ =>
someOrError (i.add? j) ty
| .sub, .val (.prim (.int i)) _, .val (.prim (.int j)) _ =>
someOrError (i.sub? j) ty
| .mul, .val (.prim (.int i)) _, .val (.prim (.int j)) _ =>
someOrError (i.mul? j) ty
| .contains, .val (.set vs₁) _, .val v₂ _ =>
.val (vs₁.contains v₂) ty
| .containsAll, .val (.set vs₁) _, .val (.set vs₂) _ =>
.val (vs₂.subset vs₁) ty
| .containsAny, .val (.set vs₁) _, .val (.set vs₂) _ =>
.val (vs₁.intersects vs₂) ty
| .mem, .val (.prim (.entityUID uid₁)) _, .val (.prim (.entityUID uid₂)) _ =>
someOrSelf (inₑ uid₁ uid₂ es) ty self
| .mem, .val (.prim (.entityUID uid₁)) _, .val (.set vs) _ =>
someOrSelf (inₛ uid₁ vs es) ty self
| .hasTag, .val (.prim (.entityUID uid₁)) _, .val (.prim (.string tag)) _ =>
someOrSelf (hasTag uid₁ tag es) ty self
| .getTag, .val (.prim (.entityUID uid₁)) _, .val (.prim (.string tag)) _ =>
getTag uid₁ tag es ty
| _, .error _, _ | _, _, .error _ => .error ty
| _, _, _ => self
where
self := .binaryApp op₂ r₁ r₂ ty

def attrsOf (r : Residual) (lookup : EntityUID → Option (Map Attr Value)) : Option (Map Attr Value) :=
match r with
| .val (.record m) _ => .some m
| .val (.prim (.entityUID uid)) _ => lookup uid
| _ => none

def hasAttr (r : Residual) (a : Attr) (es : PartialEntities) (ty : CedarType) : Residual :=
match r with
| .error _ => .error ty
| _ =>
match attrsOf r es.attrs with
| .some m => m.contains a
| .none => .hasAttr r a ty

def getAttr (r : Residual) (a : Attr) (es : PartialEntities) (ty : CedarType) : Residual :=
match r with
| .error _ => .error ty
| _ =>
match attrsOf r es.attrs with
| .some m => someOrError (m.find? a) ty
| .none => .getAttr r a ty

def set (rs : List Residual) (ty : CedarType) : Residual :=
match rs.mapM Residual.asValue with
| .some xs => .val (.set (Set.make xs)) ty
| .none => if rs.any Residual.isError then .error ty else .set rs ty

def record (m : List (Attr × Residual)) (ty : CedarType) : Residual :=
match m.mapM λ (a, r₁) => bindAttr a r₁.asValue with
| .some xs => .val (.record (Map.make xs)) ty
| .none => if m.any λ (_, r₁) => r₁.isError then .error ty else .record m ty

def call (xfn : ExtFun) (rs : List Residual) (ty : CedarType) : Residual :=
match rs.mapM Residual.asValue with
| .some xs => someOrError (Spec.call xfn xs).toOption ty
| .none => if rs.any Residual.isError then .error ty else .call xfn rs ty

def evaluate
(x : TypedExpr)
(req : PartialRequest)
(es : PartialEntities) : Residual :=
match x with
| .lit l ty => .val l ty
| .var v ty => varₚ req v ty
| .ite x₁ x₂ x₃ ty =>
ite (evaluate x₁ req es) (evaluate x₂ req es) (evaluate x₃ req es) ty
| .and x₁ x₂ ty =>
and (evaluate x₁ req es) (evaluate x₂ req es) ty
| .or x₁ x₂ ty =>
or (evaluate x₁ req es) (evaluate x₂ req es) ty
| .unaryApp op₁ x₁ ty =>
apply₁ op₁ (evaluate x₁ req es) ty
| .binaryApp op₂ x₁ x₂ ty =>
apply₂ op₂ (evaluate x₁ req es) (evaluate x₂ req es) es ty
| .hasAttr x₁ a ty =>
hasAttr (evaluate x₁ req es) a es ty
| .getAttr x₁ a ty =>
getAttr (evaluate x₁ req es) a es ty
| .set xs ty =>
set (xs.map₁ (λ ⟨x₁, _⟩ => evaluate x₁ req es)) ty
| .record axs ty =>
record (axs.map₁ (λ ⟨(a, x₁), _⟩ => (a, (evaluate x₁ req es)))) ty
| .call xfn xs ty =>
call xfn (xs.map₁ (λ ⟨x₁, _⟩ => evaluate x₁ req es)) ty
termination_by x
decreasing_by
all_goals
simp_wf
try omega
any_goals
rename_i h
replace h := List.sizeOf_lt_of_mem h
try simp at h
omega

def evaluatePolicy (schema : Schema)
(p : Policy)
(req : PartialRequest)
(es : PartialEntities)
: Except Error Residual :=
match schema.environment? req.principal.ty req.resource.ty req.action with
| .some env =>
if requestAndEntitiesIsValid env req es
then
do
let expr := substituteAction env.reqty.action p.toExpr
let (te, _) ← (typeOf expr ∅ env).mapError Error.invalidPolicy
.ok (evaluate te req es)
else .error .invalidRequestOrEntities
| .none => .error .invalidEnvironment

end Cedar.TPE
Loading