Skip to content

Commit e7032f4

Browse files
claudehyperpolymath
authored andcommitted
proof(lean4): mechanize Capability Soundness (safety_proofs.md Theorem 2)
Make the informal "by inspection of execution paths" argument for Theorem 2 machine-checked, reusing the real PhrAction AST. * Model: Resource / Operation / Capability / Context (capability list); requiredCap? maps the four leaf actions to their capability per §2.3 (ACCEPT/REJECT -> route_decision:write, REPORT -> consensus_log:append, EXECUTE f -> module f:exec). * The Executes relation is capability-gated BY CONSTRUCTION: every leaf rule carries the required-capability membership as a hypothesis, and there is deliberately no constructor that executes without an enforcement point. capability_soundness then follows by inversion -- this is exactly "all paths have enforcement points" made formal. * capability_soundness_ite extends enforcement through conditional actions (an executed iteAction reduces to a gated branch). * The two §2.5 side-properties are mechanized too: least_privilege (a fresh context holds only granted capabilities) and no_escalation (a step never enlarges the capability set, S -> S' => S'.caps subset of S.caps). All four are sorry-free; #print axioms reports only Lean's standard propext (capability_soundness_ite is axiom-free). Builds clean on Lean 4.12.0 core, no Mathlib. Docs: safety_proofs.md §2.4 gains a "Mechanized (Lean 4)" note and §5 status table now reads Sandbox Isolation + Capability Soundness = Mechanized (Lean 4), BFT Safety = Model-checked (TLA+/TLC). https://claude.ai/code/session_01DQACj3RFmAPZaBPgR9SAaS
1 parent 44c97cb commit e7032f4

2 files changed

Lines changed: 135 additions & 4 deletions

File tree

academic/formal-verification/lean4/Phronesis.lean

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,14 +504,134 @@ theorem subtype_trans : ∀ τ₁ τ₂ τ₃,
504504
intro τ₁ τ₂ τ₃ h₁ h₂
505505
exact Subtype.trans τ₁ τ₂ τ₃ h₁ h₂
506506

507+
/-! # 19. Capability Enforcement (safety_proofs.md §2 — Theorem 2)
508+
509+
Mechanizes the informal "by inspection of execution paths" argument for
510+
**Capability Soundness**: *no operation executes without the required
511+
capability*. The execution relation `Executes` is capability-gated by
512+
construction — every leaf rule carries its required-capability membership
513+
as a hypothesis — so soundness holds by inversion: there is provably no
514+
execution path that bypasses an enforcement point.
515+
516+
Also mechanizes the two stated side-properties (§2.5):
517+
* Least Privilege — a fresh context holds only granted caps.
518+
* No Capability Escalation — a step never enlarges the capability set.
519+
-/
520+
521+
inductive Resource where
522+
| routeDecision : Resource
523+
| consensusLog : Resource
524+
| moduleRes : String → Resource
525+
deriving DecidableEq, Repr
526+
527+
inductive Operation where
528+
| read : Operation
529+
| write : Operation
530+
| append : Operation
531+
| exec : Operation
532+
deriving DecidableEq, Repr
533+
534+
structure Capability where
535+
resource : Resource
536+
op : Operation
537+
deriving DecidableEq, Repr
538+
539+
/-- An execution context carries the set of granted capabilities. -/
540+
structure Context where
541+
capabilities : List Capability
542+
543+
/-- A capability is held iff it is present in the context's capability list. -/
544+
def Context.holds (ctx : Context) (c : Capability) : Prop :=
545+
c ∈ ctx.capabilities
546+
547+
/-- Required capability for the four *leaf* actions (safety_proofs.md §2.3):
548+
ACCEPT/REJECT write a route decision, REPORT appends to the consensus log,
549+
EXECUTE f invokes module `f`. Conditionals carry no leaf cap of their own. -/
550+
def requiredCap? : PhrAction → Option Capability
551+
| .accept _ => some ⟨Resource.routeDecision, Operation.write⟩
552+
| .reject _ => some ⟨Resource.routeDecision, Operation.write⟩
553+
| .report _ => some ⟨Resource.consensusLog, Operation.append⟩
554+
| .execute f _ => some ⟨Resource.moduleRes f, Operation.exec⟩
555+
| .iteAction _ _ _ => none
556+
557+
/-- Capability-gated execution. By construction every leaf rule demands the
558+
corresponding capability be held; conditionals reduce to a gated branch.
559+
There is deliberately **no** constructor that produces an execution
560+
without an enforcement point. -/
561+
inductive Executes : Context → PhrAction → Prop where
562+
| accept : ∀ ctx e, ctx.holds ⟨Resource.routeDecision, Operation.write⟩ → Executes ctx (.accept e)
563+
| reject : ∀ ctx e, ctx.holds ⟨Resource.routeDecision, Operation.write⟩ → Executes ctx (.reject e)
564+
| report : ∀ ctx e, ctx.holds ⟨Resource.consensusLog, Operation.append⟩ → Executes ctx (.report e)
565+
| execute : ∀ ctx f args, ctx.holds ⟨Resource.moduleRes f, Operation.exec⟩ → Executes ctx (.execute f args)
566+
| iteThen : ∀ ctx c a b, Executes ctx a → Executes ctx (.iteAction c a b)
567+
| iteElse : ∀ ctx c a b, Executes ctx b → Executes ctx (.iteAction c a b)
568+
569+
/-- **Theorem 2 (Capability Soundness).** A leaf action executes only when its
570+
required capability is held by the context. Proved by inversion on the
571+
gated execution relation: every leaf constructor exposes the membership
572+
witness, and the `iteAction` constructors carry no leaf cap (`requiredCap?`
573+
is `none`, so the premise `none = some c` is impossible). -/
574+
theorem capability_soundness :
575+
∀ ctx act c, requiredCap? act = some c → Executes ctx act → ctx.holds c := by
576+
intro ctx act c hreq hexec
577+
cases hexec <;>
578+
first
579+
| (simp only [requiredCap?, Option.some.injEq] at hreq; subst hreq; assumption)
580+
| simp [requiredCap?] at hreq
581+
582+
/-- Enforcement is preserved through conditionals: if a conditional action
583+
executes, the branch that ran is itself a capability-gated execution, so
584+
soundness extends to the whole action tree by structural recursion. -/
585+
theorem capability_soundness_ite :
586+
∀ ctx c a b, Executes ctx (.iteAction c a b) → (Executes ctx a ∨ Executes ctx b) := by
587+
intro ctx c a b h
588+
cases h
589+
· exact Or.inl (by assumption)
590+
· exact Or.inr (by assumption)
591+
592+
/-- Least-privilege context constructor: keep only granted capabilities
593+
(safety_proofs.md §2.5, `filter_grants`). -/
594+
def newContext (grants : List Capability) (granted : Capability → Bool) : Context :=
595+
⟨grants.filter granted⟩
596+
597+
/-- **Property (Least Privilege).** A fresh context holds only capabilities
598+
drawn from the grant set. -/
599+
theorem least_privilege :
600+
∀ grants granted c, (newContext grants granted).holds c → c ∈ grants := by
601+
intro grants granted c h
602+
exact (List.mem_filter.mp h).1
603+
604+
/-- A single execution step on contexts. Execution itself does not change the
605+
capability set; revocation keeps only a sub-selection. Neither rule can add
606+
a capability — matching "capabilities are only set at context creation and
607+
never modified during execution". -/
608+
inductive Step : Context → Context → Prop where
609+
| exec : ∀ ctx act, Executes ctx act → Step ctx ctx
610+
| revoke : ∀ ctx keep, Step ctx ⟨ctx.capabilities.filter keep⟩
611+
612+
/-- **Property (No Capability Escalation).** A step never enlarges the
613+
capability set: `S → S' ⟹ S'.caps ⊆ S.caps` (safety_proofs.md §2.5). -/
614+
theorem no_escalation :
615+
∀ S S', Step S S' → S'.capabilities ⊆ S.capabilities := by
616+
intro S S' h
617+
cases h
618+
· intro x hx; exact hx
619+
· intro x hx; exact (List.mem_filter.mp hx).1
620+
507621
/-! # 20. Summary
508622
509-
Main theorems (all machine-checked on Lean 4 core, no axioms/sorry):
623+
Main theorems (all machine-checked on Lean 4 core; no `sorry`, only Lean's
624+
standard `propext` where `simp` is used — verify with `#print axioms`):
510625
1. progress — well-typed closed expressions are values or step
511626
2. preservation — evaluation preserves types (was a TODO/sorry)
512627
3. determinism — evaluation is deterministic (was a TODO/sorry)
513628
4. termination/size_pos — expressions have positive bounded size
514629
5. subtype_trans — subtyping is transitive
630+
6. capability_soundness — no leaf action executes without the required
631+
capability (safety_proofs.md §2, Theorem 2)
632+
7. capability_soundness_ite — enforcement is preserved through conditionals
633+
8. least_privilege — a fresh context holds only granted capabilities
634+
9. no_escalation — a step never enlarges the capability set
515635
Mirrors ../coq/Phronesis.v (preservation, eval_deterministic, totality).
516636
-/
517637

docs/safety_proofs.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,17 @@ By inspection of execution paths:
229229

230230
All paths have enforcement points. ∎
231231

232+
**Mechanized (Lean 4):** This argument is machine-checked in
233+
[`../academic/formal-verification/lean4/Phronesis.lean`](../academic/formal-verification/lean4/Phronesis.lean).
234+
The execution relation `Executes` is capability-gated *by construction* — every
235+
leaf rule carries the required-capability membership as a hypothesis, and there
236+
is deliberately no constructor that executes without an enforcement point — so
237+
`capability_soundness` follows by inversion (the informal "by inspection of
238+
execution paths" made formal). `capability_soundness_ite` extends it through
239+
conditional actions. The two §2.5 side-properties are mechanized as
240+
`least_privilege` and `no_escalation`. All four are `sorry`-free (only Lean's
241+
standard `propext`; confirm with `#print axioms`).
242+
232243
### 2.5 Capability Composition
233244

234245
**Property (Least Privilege):**
@@ -398,9 +409,9 @@ Layer 5: Audit Log
398409

399410
| Property | Status | Proof System |
400411
|----------|--------|--------------|
401-
| Sandbox Isolation | Manual proof | This document |
402-
| Capability Soundness | Manual proof | This document |
403-
| BFT Safety | Manual proof | This document |
412+
| Sandbox Isolation | Mechanized (Lean 4) | `academic/formal-verification/lean4/Phronesis.lean` |
413+
| Capability Soundness | Mechanized (Lean 4) | `academic/formal-verification/lean4/Phronesis.lean` |
414+
| BFT Safety | Model-checked (TLA+/TLC) | `formal/PhronesisConsensus.tla` |
404415
| BFT Liveness | Manual proof | This document |
405416
| Termination | Proven | Semantics doc |
406417
| Type Safety | Sketch | Semantics doc |

0 commit comments

Comments
 (0)