Skip to content

Commit 7dd9f3a

Browse files
claudehyperpolymath
authored andcommitted
proof(lean4): mechanize Sandbox Isolation (safety_proofs.md Theorem 1)
Promotes the sandbox guarantee from a paper proof to machine-checked Lean, on core Lean (no deps): * sandbox_no_call_executes : the evaluator is INCAPABLE of executing an external call -- Eval has no rule for `call` (the only constructor that could reach a host/module operation), so policy evaluation performs no external effect. The core "no I/O escape" guarantee in the pure model. * callNames / callNamesArgs : the function names a policy would invoke. * sandbox_clean / sandbox_cleanArgs : the static containsDangerous check is SOUND -- a statically-clean policy invokes no dangerous function (mechanises Theorem 1.1). Mutual structural recursion over the AST. Verified: lake build OK; #print axioms shows sandbox_no_call_executes has no axioms, sandbox_clean/Args only propext -- no sorryAx. https://claude.ai/code/session_01DQACj3RFmAPZaBPgR9SAaS
1 parent 89166e9 commit 7dd9f3a

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

academic/formal-verification/lean4/Phronesis.lean

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,93 @@ def containsDangerousArgs : List PhrExpr → Bool
402402
| e :: es => containsDangerous e || containsDangerousArgs es
403403
end
404404

405+
-- The function names a policy would invoke via `call` (the ONLY effectful
406+
-- constructor — there is no fs/network/syscall node in the grammar).
407+
mutual
408+
def callNames : PhrExpr → List String
409+
| .lit _ => []
410+
| .var _ => []
411+
| .binOp _ e₁ e₂ => callNames e₁ ++ callNames e₂
412+
| .unOp _ e => callNames e
413+
| .ite e₁ e₂ e₃ => callNames e₁ ++ callNames e₂ ++ callNames e₃
414+
| .field e _ => callNames e
415+
| .mem e₁ e₂ => callNames e₁ ++ callNames e₂
416+
| .call f args => f :: callNamesArgs args
417+
def callNamesArgs : List PhrExpr → List String
418+
| [] => []
419+
| e :: es => callNames e ++ callNamesArgs es
420+
end
421+
422+
-- SANDBOX (operational): the evaluator is incapable of executing an external
423+
-- call. `Eval` has no rule for `call` — the only constructor that could reach
424+
-- a module/host operation — so policy evaluation performs NO external effect.
425+
-- This is the core "no I/O escape" guarantee of Theorem 1 in the pure model.
426+
theorem sandbox_no_call_executes : ∀ ρ f args v,
427+
¬ Eval ρ (PhrExpr.call f args) v := by
428+
intro ρ f args v h; cases h
429+
430+
-- SANDBOX (static, mechanises Theorem 1.1): a statically-clean policy invokes
431+
-- no dangerous function. If `containsDangerous e = false` then every name in
432+
-- `callNames e` is non-dangerous. Proved by mutual structural recursion over
433+
-- the expression tree and its argument lists.
434+
mutual
435+
theorem sandbox_clean : ∀ (e : PhrExpr),
436+
containsDangerous e = false → ∀ f, f ∈ callNames e → isDangerousCall f = false
437+
| .lit _ => by intro _ f hf; simp [callNames] at hf
438+
| .var _ => by intro _ f hf; simp [callNames] at hf
439+
| .binOp _ e₁ e₂ => by
440+
intro h f hf
441+
simp only [containsDangerous, Bool.or_eq_false_iff] at h
442+
simp only [callNames, List.mem_append] at hf
443+
cases hf with
444+
| inl hf => exact sandbox_clean e₁ h.1 f hf
445+
| inr hf => exact sandbox_clean e₂ h.2 f hf
446+
| .unOp _ e => by
447+
intro h f hf
448+
simp only [containsDangerous] at h
449+
simp only [callNames] at hf
450+
exact sandbox_clean e h f hf
451+
| .ite e₁ e₂ e₃ => by
452+
intro h f hf
453+
simp only [containsDangerous, Bool.or_eq_false_iff] at h
454+
simp only [callNames, List.mem_append] at hf
455+
cases hf with
456+
| inl hf =>
457+
cases hf with
458+
| inl hf => exact sandbox_clean e₁ h.1.1 f hf
459+
| inr hf => exact sandbox_clean e₂ h.1.2 f hf
460+
| inr hf => exact sandbox_clean e₃ h.2 f hf
461+
| .field e _ => by
462+
intro h f hf
463+
simp only [containsDangerous] at h
464+
simp only [callNames] at hf
465+
exact sandbox_clean e h f hf
466+
| .mem e₁ e₂ => by
467+
intro h f hf
468+
simp only [containsDangerous, Bool.or_eq_false_iff] at h
469+
simp only [callNames, List.mem_append] at hf
470+
cases hf with
471+
| inl hf => exact sandbox_clean e₁ h.1 f hf
472+
| inr hf => exact sandbox_clean e₂ h.2 f hf
473+
| .call g args => by
474+
intro h f hf
475+
simp only [containsDangerous, Bool.or_eq_false_iff] at h
476+
simp only [callNames, List.mem_cons] at hf
477+
cases hf with
478+
| inl hf => subst hf; exact h.1
479+
| inr hf => exact sandbox_cleanArgs args h.2 f hf
480+
theorem sandbox_cleanArgs : ∀ (args : List PhrExpr),
481+
containsDangerousArgs args = false → ∀ f, f ∈ callNamesArgs args → isDangerousCall f = false
482+
| [] => by intro _ f hf; simp [callNamesArgs] at hf
483+
| e :: es => by
484+
intro h f hf
485+
simp only [containsDangerousArgs, Bool.or_eq_false_iff] at h
486+
simp only [callNamesArgs, List.mem_append] at hf
487+
cases hf with
488+
| inl hf => exact sandbox_clean e h.1 f hf
489+
| inr hf => exact sandbox_cleanArgs es h.2 f hf
490+
end
491+
405492
/-! # 19. Subtyping -/
406493

407494
inductive Subtype : PhrType → PhrType → Prop where

0 commit comments

Comments
 (0)