Capability is data; the guard and the sandbox are its two consumers
The capability model reads no session and renders nothing: capability
holds the lattice and the folds over it, and the in-process guard and the OS
sandbox are its two readers, so they cannot disagree about what a stack
permits. The order is capability < sandbox < guard. Reinforces
capability-stage-collapse and
moves the builder witness-collapse names,
sandbox_projection, below the guard that used to hold it.
Context
Authority had no home. The model (Capabilities, GrantStack, the lattice)
lived in types, its enforcement in capability, and its sandbox projection
back in types; the three folds in capability (exec::rules, fs::region,
the deputy overlap) read the model from above and were rendered by a builder
that took a Context.
Admitted, the proof that an exec was judged, was minted by the audited check, not by the judgment, so a launch could trust a value whose mint also wrote to the trail.- A grant string was frozen in two places,
path/sigil.rsandcapability/decode.rs, each with its own relative-path, foreign-root andHOMErules;PolicyErrorsat intypes/flow.rs. - Three builders of the capability observation, one per door.
- The kernel list was a third language.
ExecProjectioncarried an orderedVec<ExecRule>thatkernel()wrote andfrom_kernel()read back into the table it came from, because the model sat above the sandbox and could not be named from it.
Decision
- The model is
capability(rank 3).Capabilities,GrantStack,Verdict,Meet,Widen, and the two tables of one-table-two-instances, named nothing intypes.GrantStack::admitis the one exec judgment and the only mint ofAdmitted; a refusal is data (Refused,ExecDenial), worded by the guard.GrantStack::admits(&Program)is head-only admission andrespelledthe refusing deny’s other spelling. - One boolean vocabulary.
Flag { Detach, EditorRead, EditorWrite, EditorTui, ShellChdir }withGrantStack::permits(Flag): a meet over the layers, silence permitting.Shell::check(Flag, who)is its one door. - The projection is the sandbox’s (rank 4).
SandboxProjection::of(&GrantStack, &Resolver, Option<&Admitted>)folds once, at spawn, off the sameregionand the very table that admitted the launch.ExecProjection::RestrictedcarriesExecRulesitself, built byExecRules::for_kernel(carriers admitted, each file at its final verdict), soExecRule,kernelandfrom_kernelare gone; Seatbelt reads the table inprecedenceorder, Landlock and the envelope read it as the guard does. The projection takes aGrantStackand aResolver, never aShell. - The guard is
guard(rank 7).enforcewords the model’s refusals and returns a typedDenial { check, error };Shell::refusedmints itsBreakand records it throughShell::record_check, the one door for a check, with noMooring, so on the trail alone. A head admission passes itsMooringto the same door and so broadcasts. - A grant string becomes a
FrozenPathinguard::freeze, against oneFreezeCtx(FreezeCtx::of(&Shell), ownedenvandcwd):path,paths,absolute.FrozenPath::from_surfaceis the one minting door, and thexdg:escape guard asks the fs guard’s own question,from_surface(home).contains::<Allow>(resolved.real().as_path()).PolicyErrorand thegitdir:refusals live there,decodeandSpawnGrantbeside it.
Rejected
- Leaving the projection in
capability. It would name the OS vocabulary (Rendered, the backends’WriteReach), and the model is data the backends read, not the other way round. ExecProjectionpublic. It now holdsExecRules, which ispub(crate)withTableandScope; the projection’sexecfield is crate-private andtest_accessanswers the three questions the integration tests ask of it.- Flags as four forwarders and a verb gate. One enum is one vote, one fold and one refusal wording.
Consequences
- Guard and profile agree by construction: both ask
regionper op and the exec tableadmitjudged with. What separates them is when the fold runs, afresh per check against a liveResolver, or once per spawn (two-enforcers). - The kernel’s rules are the guard’s table. The property that the rendered
last-match list judges as the table and its carriers is tested over
precedence, and the tablefor_kernelreturns judges as the one it was built from. - One door records every reported check, a refusal or a flagged deputy:
Shell::record_check(Option<&Mooring>, Check)overobserve_stamped. Only a head refusal holds aMooring, so only it reaches the rail as well.
Where
core/src/capability.rs and capability/{lattice,exec,fs,table,deputy}.rs
(GrantStack, Flag, admit, Admitted, Refused, ExecDenial,
for_kernel, precedence), core/src/sandbox/projection.rs
(SandboxProjection::of, ExecProjection, FsRules, WriteReach),
core/src/guard.rs and guard/{enforce,shell,freeze,decode,grant}.rs
(check_exec, check_flag, Denial, Shell::refused, FreezeCtx,
PolicyError, decode_capability_map, SpawnGrant), and
core/src/types/audit/door.rs (Shell::record_check).