Skip to content

Commit ead3c16

Browse files
RFC 53 Lean model and proofs (#530)
Signed-off-by: Shaobo He <shaobohe@amazon.com>
1 parent db9e8ec commit ead3c16

File tree

10 files changed

+140
-65
lines changed

10 files changed

+140
-65
lines changed

cedar-lean/Cedar/Thm/Validation/RequestEntityValidation.lean

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ theorem instance_of_bool_type_refl (b : Bool) (bty : BoolType) :
1515
intro h₀
1616
cases h₁ : b <;> cases h₂ : bty <;> subst h₁ <;> subst h₂ <;> simp only [Bool.false_eq_true] at *
1717

18-
theorem instance_of_entity_type_refl (e : EntityUID) (ety : EntityType) :
19-
instanceOfEntityType e ety = true → InstanceOfEntityType e ety
18+
theorem instance_of_entity_type_refl (e : EntityUID) (ety : EntityType) (eids: EntityType → Option (Set String)) :
19+
instanceOfEntityType e ety eids = true → InstanceOfEntityType e ety
2020
:= by
2121
simp only [InstanceOfEntityType, instanceOfEntityType]
2222
intro h₀
23-
simp only [beq_iff_eq] at h₀
23+
have h₁ : (ety == e.ty) := by
24+
simp at h₀
25+
have ⟨ e₁, _ ⟩ := h₀
26+
simp
27+
exact e₁
28+
simp only [beq_iff_eq] at h₁
2429
assumption
2530

2631
theorem instance_of_ext_type_refl (ext : Ext) (extty : ExtType) :
@@ -30,8 +35,8 @@ theorem instance_of_ext_type_refl (ext : Ext) (extty : ExtType) :
3035
intro h₀
3136
cases h₁ : ext <;> cases h₂ : extty <;> subst h₁ <;> subst h₂ <;> simp only [Bool.false_eq_true] at *
3237

33-
theorem instance_of_type_refl (v : Value) (ty : CedarType) :
34-
instanceOfType v ty = true → InstanceOfType v ty
38+
theorem instance_of_type_refl (v : Value) (ty : CedarType) (schema: EntitySchema) :
39+
instanceOfType v ty schema = true → InstanceOfType v ty
3540
:= by
3641
intro h₀
3742
unfold instanceOfType at h₀
@@ -75,7 +80,7 @@ theorem instance_of_type_refl (v : Value) (ty : CedarType) :
7580
simp only [← Set.in_list_iff_in_set] at hv
7681
specialize h₀ ⟨v, hv⟩
7782
simp only [List.attach_def, List.mem_pmap_subtype, hv, true_implies] at h₀
78-
exact instance_of_type_refl v sty h₀
83+
exact instance_of_type_refl v sty schema h₀
7984
all_goals
8085
contradiction
8186
all_goals
@@ -114,7 +119,7 @@ theorem instance_of_type_refl (v : Value) (ty : CedarType) :
114119
simp only [h₈] at h₇
115120
simp only [h₈, Option.some.injEq] at h₂
116121
subst h₂
117-
exact instance_of_type_refl v vl.getType h₇
122+
exact instance_of_type_refl v vl.getType schema h₇
118123
intro k qty h₁ h₂
119124
have ⟨⟨_, h₄⟩, h₅⟩ := h₀
120125
clear h₀
@@ -158,8 +163,8 @@ decreasing_by
158163
have := Map.sizeOf_lt_of_value h₁
159164
omega
160165

161-
theorem instance_of_request_type_refl (request : Request) (reqty : RequestType) :
162-
instanceOfRequestType request reqty = true → InstanceOfRequestType request reqty
166+
theorem instance_of_request_type_refl (request : Request) (reqty : RequestType) (schema: EntitySchema):
167+
instanceOfRequestType request reqty schema = true → InstanceOfRequestType request reqty
163168
:= by
164169
intro h₀
165170
simp only [InstanceOfRequestType]
@@ -203,15 +208,18 @@ theorem instance_of_entity_schema_refl (entities : Entities) (ets : EntitySchema
203208
split at h₀ <;> try simp only [reduceCtorEq] at h₀
204209
rename_i h₃
205210
constructor
206-
· exact instance_of_type_refl (Value.record data.attrs) (CedarType.record entry.attrs) h₃
211+
· exact instance_of_type_refl (Value.record data.attrs) (CedarType.record entry.attrs) ets h₃
207212
· split at h₀ <;> try simp only [reduceCtorEq] at h₀
208213
rename_i h₄
209214
simp only [Set.all, List.all_eq_true] at h₄
210215
constructor
211216
· intro anc ancin
212217
simp only [Set.contains, List.elem_eq_mem, decide_eq_true_eq] at h₄
213218
rw [← Set.in_list_iff_in_set] at ancin
214-
exact h₄ anc ancin
219+
have h₅ := h₄ anc ancin
220+
simp at h₅
221+
have ⟨ h₆, _ ⟩ := h₅
222+
exact h₆
215223
· split at h₀ <;> try simp only [reduceCtorEq] at h₀
216224
unfold InstanceOfEntityTags
217225
rename_i h₅
@@ -247,8 +255,8 @@ theorem instance_of_action_schema_refl (entities : Entities) (acts : ActionSchem
247255

248256

249257

250-
theorem request_and_entities_match_env (env : Environment) (request : Request) (entities : Entities) :
251-
requestMatchesEnvironment env request →
258+
theorem request_and_entities_match_env (env : Environment) (request : Request) (entities : Entities) (schema: EntitySchema) :
259+
requestMatchesEnvironment env request schema
252260
entitiesMatchEnvironment env entities = .ok () →
253261
RequestAndEntitiesMatchEnvironment env request entities
254262
:= by
@@ -257,7 +265,7 @@ theorem request_and_entities_match_env (env : Environment) (request : Request) (
257265
simp only [requestMatchesEnvironment] at h₀
258266
simp only [entitiesMatchEnvironment] at h₁
259267
constructor
260-
exact instance_of_request_type_refl request env.reqty h₀
268+
exact instance_of_request_type_refl request env.reqty schema h₀
261269
cases h₂ : instanceOfEntitySchema entities env.ets <;> simp only [h₂, Except.bind_err, Except.bind_ok, reduceCtorEq] at h₁
262270
constructor
263271
exact instance_of_entity_schema_refl entities env.ets h₂

cedar-lean/Cedar/Thm/Validation/Typechecker/BinaryApp.lean

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,8 +902,11 @@ private theorem no_tags_type_implies_no_tags {uid : EntityUID} {env : Environmen
902902
replace ⟨e', h₂, h₃⟩ := h₂
903903
simp only [hf', Option.some.injEq] at h₂
904904
subst h₂
905-
simp only [h₃] at h₁
906-
simp only [h₁, map_empty_contains_instance_of_ff]
905+
simp only [EntitySchemaEntry.tags?] at h₁ h₃
906+
split at h₃
907+
· simp only [h₃] at h₁
908+
simp only [h₁, map_empty_contains_instance_of_ff]
909+
· simp only [h₁, map_empty_contains_instance_of_ff]
907910
· exact map_empty_contains_instance_of_ff
908911

909912
private theorem no_type_implies_no_tags {uid : EntityUID} {env : Environment} {entities : Entities}
@@ -1070,6 +1073,8 @@ theorem type_of_getTag_is_sound {x₁ x₂ : Expr} {c₁ c₂ : Capabilities} {e
10701073
replace ⟨_, h₅, h₇⟩ := h₅
10711074
simp only [hf₂, Option.some.injEq] at h₅
10721075
subst h₅
1076+
simp only [EntitySchemaEntry.tags?] at h₂ h₇
1077+
split at h₇
10731078
simp only [h₇] at h₂
10741079
have hf₃ := Map.findOrErr_returns d.tags s Error.tagDoesNotExist
10751080
rcases hf₃ with ⟨v, hf₃⟩ | hf₃ <;>
@@ -1084,6 +1089,7 @@ theorem type_of_getTag_is_sound {x₁ x₂ : Expr} {c₁ c₂ : Capabilities} {e
10841089
simp only [Entities.tagsOrEmpty, hf₁, Map.contains_iff_some_find?] at h₁
10851090
replace ⟨_, h₁⟩ := h₁
10861091
simp only [Map.findOrErr_err_iff_find?_none, h₁, reduceCtorEq] at hf₃
1092+
· cases h₇
10871093

10881094
theorem type_of_binaryApp_is_sound {op₂ : BinaryOp} {x₁ x₂ : Expr} {c₁ c₂ : Capabilities} {env : Environment} {ty : TypedExpr} {request : Request} {entities : Entities}
10891095
(h₁ : CapabilitiesInvariant c₁ request entities)

cedar-lean/Cedar/Thm/Validation/Typechecker/Types.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def InstanceOfRequestType (request : Request) (reqty : RequestType) : Prop :=
8080
InstanceOfType request.context (.record reqty.context)
8181

8282
def InstanceOfEntityTags (data : EntityData) (entry : EntitySchemaEntry) : Prop :=
83-
match entry.tags with
83+
match entry.tags? with
8484
| .some tty => ∀ v ∈ data.tags.values, InstanceOfType v tty
8585
| .none => data.tags = Map.empty
8686

cedar-lean/Cedar/Validation/RequestEntityValidator.lean

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ def instanceOfBoolType (b : Bool) (bty : BoolType) : Bool :=
3939
| _, .anyBool => true
4040
| _, _ => false
4141

42-
def instanceOfEntityType (e : EntityUID) (ety : EntityType ) : Bool := ety == e.ty
42+
def instanceOfEntityType (e : EntityUID) (ety : EntityType ) (eids: EntityType → Option (Set String)) : Bool :=
43+
ety == e.ty &&
44+
match eids ety with
45+
| .some eids => eids.contains e.eid
46+
| _ => true
4347

4448
def instanceOfExtType (ext : Ext) (extty: ExtType) : Bool :=
4549
match ext, extty with
@@ -52,17 +56,17 @@ match rty.find? k with
5256
| .some qty => if qty.isRequired then r.contains k else true
5357
| _ => true
5458

55-
def instanceOfType (v : Value) (ty : CedarType) : Bool :=
59+
def instanceOfType (v : Value) (ty : CedarType) (schema: EntitySchema) : Bool :=
5660
match v, ty with
5761
| .prim (.bool b), .bool bty => instanceOfBoolType b bty
5862
| .prim (.int _), .int => true
5963
| .prim (.string _), .string => true
60-
| .prim (.entityUID e), .entity ety => instanceOfEntityType e ety
61-
| .set s, .set ty => s.elts.attach.all (λ ⟨v, _⟩ => instanceOfType v ty)
64+
| .prim (.entityUID e), .entity ety => instanceOfEntityType e ety schema.entityTypeMembers?
65+
| .set s, .set ty => s.elts.attach.all (λ ⟨v, _⟩ => instanceOfType v ty schema)
6266
| .record r, .record rty =>
6367
r.kvs.all (λ (k, _) => rty.contains k) &&
6468
(r.kvs.attach₂.all (λ ⟨(k, v), _⟩ => (match rty.find? k with
65-
| .some qty => instanceOfType v qty.getType
69+
| .some qty => instanceOfType v qty.getType schema
6670
| _ => true))) &&
6771
rty.kvs.all (λ (k, _) => requiredAttributePresent r rty k)
6872
| .ext x, .ext xty => instanceOfExtType x xty
@@ -79,11 +83,11 @@ def instanceOfType (v : Value) (ty : CedarType) : Bool :=
7983
simp only [Map.mk.sizeOf_spec]
8084
omega
8185

82-
def instanceOfRequestType (request : Request) (reqty : RequestType) : Bool :=
83-
instanceOfEntityType request.principal reqty.principal &&
86+
def instanceOfRequestType (request : Request) (reqty : RequestType) (schema: EntitySchema) : Bool :=
87+
instanceOfEntityType request.principal reqty.principal schema.entityTypeMembers? &&
8488
request.action == reqty.action &&
85-
instanceOfEntityType request.resource reqty.resource &&
86-
instanceOfType request.context (.record reqty.context)
89+
instanceOfEntityType request.resource reqty.resource schema.entityTypeMembers? &&
90+
instanceOfType request.context (.record reqty.context) schema
8791

8892
/--
8993
For every entity in the store,
@@ -97,14 +101,16 @@ def instanceOfEntitySchema (entities : Entities) (ets : EntitySchema) : EntityVa
97101
entities.toList.forM λ (uid, data) => instanceOfEntityData uid data
98102
where
99103
instanceOfEntityTags (data : EntityData) (entry : EntitySchemaEntry) : Bool :=
100-
match entry.tags with
101-
| .some tty => data.tags.values.all (instanceOfType · tty)
104+
match entry.tags? with
105+
| .some tty => data.tags.values.all (instanceOfType · tty ets)
102106
| .none => data.tags == Map.empty
103107
instanceOfEntityData uid data :=
104108
match ets.find? uid.ty with
105109
| .some entry =>
106-
if instanceOfType data.attrs (.record entry.attrs) then
107-
if data.ancestors.all (λ ancestor => entry.ancestors.contains ancestor.ty) then
110+
if instanceOfType data.attrs (.record entry.attrs) ets then
111+
if data.ancestors.all (λ ancestor =>
112+
entry.ancestors.contains ancestor.ty &&
113+
instanceOfEntityType ancestor ancestor.ty ets.entityTypeMembers?) then
108114
if instanceOfEntityTags data entry then .ok ()
109115
else .error (.typeError s!"entity tags inconsistent with type store")
110116
else .error (.typeError s!"entity ancestors inconsistent with type store")
@@ -125,10 +131,10 @@ where
125131
else .error (.typeError "action ancestors inconsistent with type store information")
126132
| _ => .error (.typeError s!"action type {uid.eid} not defined in type store")
127133

128-
def requestMatchesEnvironment (env : Environment) (request : Request) : Bool := instanceOfRequestType request env.reqty
134+
def requestMatchesEnvironment (env : Environment) (request : Request) (schema : EntitySchema): Bool := instanceOfRequestType request env.reqty schema
129135

130136
def validateRequest (schema : Schema) (request : Request) : RequestValidationResult :=
131-
if ((schema.toEnvironments.any (requestMatchesEnvironment · request)))
137+
if ((schema.toEnvironments.any (requestMatchesEnvironment · request schema.ets)))
132138
then .ok ()
133139
else .error (.typeError "request could not be validated in any environment")
134140

@@ -158,7 +164,7 @@ def updateSchema (schema : Schema) (actionSchemaEntities : Entities) : Schema :=
158164
let entriesWithType := actionSchemaEntities.filter (λ k _ => k.ty == ty)
159165
let allAncestorsForType := List.flatten (entriesWithType.values.map (λ edt =>
160166
edt.ancestors.elts.map (·.ty) ))
161-
let ese : EntitySchemaEntry := {
167+
let ese : EntitySchemaEntry := .standard {
162168
ancestors := Set.make allAncestorsForType,
163169
attrs := Map.empty,
164170
tags := Option.none

cedar-lean/Cedar/Validation/Typechecker.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def typeOfLit (p : Prim) (env : Environment) : ResultType :=
5959
| .int _ => ok .int
6060
| .string _ => ok .string
6161
| .entityUID uid =>
62-
if env.ets.contains uid.ty || env.acts.contains uid
62+
if env.ets.isValidEntityUID uid || env.acts.contains uid
6363
then ok (.entity uid.ty)
6464
else err (.unknownEntity uid.ty)
6565

cedar-lean/Cedar/Validation/Types.lean

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,52 @@ abbrev QualifiedType := Qualified CedarType
6161

6262
abbrev RecordType := Map Attr QualifiedType
6363

64-
structure EntitySchemaEntry where
64+
structure StandardSchemaEntry where
6565
ancestors : Cedar.Data.Set EntityType
6666
attrs : RecordType
6767
tags : Option CedarType
6868

69+
inductive EntitySchemaEntry where
70+
| standard (ty: StandardSchemaEntry)
71+
| enum (eids: Set String)
72+
73+
def EntitySchemaEntry.isValidEntityUID (entry: EntitySchemaEntry) (eid: String): Bool :=
74+
match entry with
75+
| .standard _ => true
76+
| .enum eids => eids.contains eid
77+
78+
def EntitySchemaEntry.tags? : EntitySchemaEntry → Option CedarType
79+
| .standard ty => ty.tags
80+
| .enum _ => none
81+
82+
def EntitySchemaEntry.attrs : EntitySchemaEntry → RecordType
83+
| .standard ty => ty.attrs
84+
| .enum _ => Map.empty
85+
86+
def EntitySchemaEntry.ancestors : EntitySchemaEntry → Set EntityType
87+
| .standard ty => ty.ancestors
88+
| .enum _ => Set.empty
89+
6990
abbrev EntitySchema := Map EntityType EntitySchemaEntry
7091

92+
def EntitySchema.entityTypeMembers? (ets: EntitySchema) (et: EntityType) : Option (Set String) :=
93+
match ets.find? et with
94+
| .some (.enum eids) => .some eids
95+
| _ => .none
96+
97+
def EntitySchema.isValidEntityUID (ets : EntitySchema) (uid : EntityUID) : Bool :=
98+
match ets.find? uid.ty with
99+
| .some entry => entry.isValidEntityUID uid.eid
100+
| .none => false
101+
71102
def EntitySchema.contains (ets : EntitySchema) (ety : EntityType) : Bool :=
72103
(ets.find? ety).isSome
73104

74105
def EntitySchema.attrs? (ets : EntitySchema) (ety : EntityType) : Option RecordType :=
75106
(ets.find? ety).map EntitySchemaEntry.attrs
76107

77108
def EntitySchema.tags? (ets : EntitySchema) (ety : EntityType) : Option (Option CedarType) :=
78-
(ets.find? ety).map EntitySchemaEntry.tags
109+
(ets.find? ety).map EntitySchemaEntry.tags?
79110

80111
def EntitySchema.descendentOf (ets : EntitySchema) (ety₁ ety₂ : EntityType) : Bool :=
81112
if ety₁ = ety₂
@@ -124,6 +155,7 @@ deriving instance Repr, DecidableEq, Inhabited for ExtType
124155
deriving instance Repr, DecidableEq, Inhabited for Qualified
125156
deriving instance Repr, Inhabited for CedarType
126157
deriving instance Repr for ActionSchemaEntry
158+
deriving instance Repr for StandardSchemaEntry
127159
deriving instance Repr for EntitySchemaEntry
128160
deriving instance Repr for Schema
129161

@@ -198,4 +230,24 @@ end
198230

199231
instance : DecidableEq CedarType := decCedarType
200232

233+
deriving instance DecidableEq for StandardSchemaEntry
234+
235+
def decEntitySchemaEntry (e₁ e₂: EntitySchemaEntry) : Decidable (e₁ = e₂) := by
236+
cases e₁ <;> cases e₂
237+
case standard.standard t₁ t₂ =>
238+
exact match decEq t₁ t₂ with
239+
| isTrue h => isTrue (by rw [h])
240+
| isFalse _ => isFalse (by intro h; injection h; contradiction)
241+
case enum.enum l₁ l₂ =>
242+
exact match decEq l₁ l₂ with
243+
| isTrue h => isTrue (by rw [h])
244+
| isFalse _ => isFalse (by intro h; injection h; contradiction)
245+
all_goals {
246+
apply isFalse
247+
intro h
248+
injection h
249+
}
250+
251+
instance : DecidableEq EntitySchemaEntry := decEntitySchemaEntry
252+
201253
end Cedar.Validation

cedar-lean/CedarProto/ValidationRequest.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ namespace Cedar.Validation.Proto
2828

2929
deriving instance DecidableEq for ActionSchemaEntry
3030
deriving instance DecidableEq for ActionSchema
31-
deriving instance DecidableEq for EntitySchemaEntry
3231
deriving instance DecidableEq for EntitySchema
3332
deriving instance DecidableEq for Schema
3433

cedar-lean/CedarProto/ValidatorSchema.lean

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,13 @@ def toEntitySchema (ets : EntityTypeWithTypesMap) : EntitySchema :=
7272
Data.Map.make (ets.map
7373
(λ (k,v) => (k,
7474
if v.enums.isEmpty then
75-
{
75+
.standard {
7676
ancestors := ancestorMap.find! k,
7777
attrs := Data.Map.make v.attrs.kvs,
7878
tags := v.tags,
7979
}
8080
else
81-
{
82-
ancestors := ancestorMap.find! k,
83-
attrs := Data.Map.empty,
84-
tags := none,
85-
}
81+
.enum $ Cedar.Data.Set.mk v.enums.toList
8682
)))
8783
end Cedar.Validation.Proto.EntityTypeWithTypesMap
8884

0 commit comments

Comments
 (0)