Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/saf/authority/01-session.md
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00

201 lines
9.3 KiB
Markdown

# Session authority
The Souveraine session has one authority. `sessiond` receives evidence from the
system, applies Souveraine policy, exposes named verbs, and keeps the trail.
The shell is its face. It is not a second policy engine.
This chapter owns the living architecture. The longer doctrine and audit
records remain in SouveraineOS under `docs/SESSION-AUTHORITY-DOCTRINE.md`,
`docs/SESSION-TRUST-ARCHITECTURE.md`, and `docs/TRUST-BOUNDARY-MATRIX.md`.
## The authority it is, and the authorities it consumes
Classical Linux gives ambient authority to processes sharing a UID. It has
several narrower authorities, but no single object that means "the state and
permission of this person's session." Souveraine does not replace those
authorities with hand-maintained booleans. It consumes them:
- the compositor owns what is presented and the Wayland lock protocol;
- logind owns seat/session facts, `LockedHint`, suspend, shutdown, and
inhibitors;
- PAM owns authentication;
- Wayland idle protocols own compositor-observed idleness;
- NetworkManager owns link and bearer facts;
- the kernel and their owning daemons own device evidence.
`sessiond` is the one place where those truths become Souveraine policy and
action. A shadow copy is not a second truth. If it can drift from the owner, it
may be a cache with explicit invalidation, but it may not decide.
## Who owns the lockscreen
Casey is the person who authenticates. Casey's Unix account must not therefore
own the mechanism that decides whether the device is securely locked. The
lockscreen is hostile-input-facing, present before Personal data is unlocked,
and remains present after that key is evicted. It is a security target in its
own right.
The target local principal is `souveraine-session`, distinct from all four
other subjects:
- `souveraine` is the machine signer;
- `souveraine-session` runs sessiond and owns the secure lock lifecycle;
- `casey` is the human authentication and Personal-data subject;
- `souvie`, `annie`, and `vanguard` are agent principals;
- borrowed modes may act through `casey`, but own none of the lock boundary.
The same split applies on the laptop and phone. A larger screen does not make
the human-owned lock process safer, and a phone form factor does not make an
agent the session authority.
The compositor enforces ext-session-lock. Sessiond, running as
`souveraine-session`, acquires and retains that protocol authority, owns the
PAM conversation, decides transitions, and writes the trail. QuickShell may
draw the rich face and request verbs, but it cannot release the secure lock by
writing a boolean or dying. An agent may request lock and may receive an
explicit step-up grant; no agent owns unlock.
Successful PAM authenticates Casey and permits the authority to install or
release Casey's Personal-class key. It does not turn sessiond into Casey or
give `souveraine-session` access to Casey's decrypted home. Credentials should
cross only through the PAM conversation; the resulting grant is narrow,
fresh, and auditable.
The pre-unlock surface owns only package code plus Ambient and tightly scoped
Revealable state. It does not read agent memory, messages, photos, credentials,
or Casey's Personal store. Notification previews and now-playing metadata are
projected into the Revealable store before lock; the lockscreen does not reopen
the Personal database after key eviction.
At boot, the compositor and lock authority rise without Casey's home, user
manager, or agent substrate. The dedicated principal receives only the narrow
Wayland socket/protocol and PAM access it needs, not membership that makes the
whole human session readable. After the compositor acknowledges the secure
lock, Personal keys may be evicted while the lock surface continues to draw.
This boundary is not built. `souveraine-sessiond.service` is currently a user
unit with no `User=` setting, so it runs as whichever human user manager owns
the graphical session. On the laptop, the machine-tier `souveraine` account
exists and `souveraine-session` does not. The boot ordering is useful and
fail-closed, but it is not yet an independent lockscreen principal.
## Sixty percent agent, forty percent user
The agent owns device operation. If the system can perform an ordinary device
operation, there should be an agent-reachable verb for it. A missing verb is a
defect unless the operation crosses a user-only invariant.
The user uniquely owns being the user: credentials, fresh authentication,
step-up consent, and the decision to cross a boundary whose meaning cannot be
delegated. The user is not required to act as a remote control for mundane
operations merely because the agent's path was never built.
This is the 60/40 split. It is not a percentage implemented in code. It is a
design test for every capability surface.
## Requests are not acknowledgements
The authority distinguishes intent, attempted action, and observed fact.
`screenLocked` can express a request or policy state. `screenLockSecure` means
the compositor has actually established the secure lock. A request to lock is
not permission to blank as though the lock were already held. The dark-panel
path therefore requests lock, waits for acknowledgement within a fixed budget,
and records a security error if the acknowledgement never arrives before the
panel is blanked.
The same rule applies elsewhere:
- starting a systemd unit is not readiness;
- issuing a compositor command is not proof that a surface arrived;
- accepting a socket write is not proof that a state transition committed;
- a green package build is not proof that the device installed or exercised it.
The session start graph and its readiness boundary live in
[session start](../surface/02-session-start.md).
## Capability tiers
Tier is metadata on the verb being guarded, checked at the authority. It is not
a separate permissions subsystem in the shell.
| Tier | Requirement | Typical reach |
|---|---|---|
| `ambient` | no authentication | time, weather, timers, media transport, non-personal questions |
| `personal` | the session is genuinely unlocked | messages, memory, contacts, fleet and conversation state |
| `stepUp` | fresh authentication for the named family | send, delete, publish, payment, physical access, revealing personal content on lock |
Step-up does not unlock the session. It can grant a narrow action family or
reveal content in place on the lock surface. A future grant therefore needs an
action family, freshness, provenance, and expiry; "fingerprint succeeded" is
not itself a session-wide capability.
## Verbs, refusals, and inspection
Every operation exposed by sessiond should have one stable name and one
decision point. The same capability may be rendered as a shell button, a body
tool, or an agent request, but those are clients of the verb, not parallel
implementations.
An authority-grade verb carries enough structure to answer:
- what was requested and by whom;
- what current state and evidence it used;
- which tier and inhibitor applied;
- whether it accepted, refused, or failed;
- what observable acknowledgement completed it;
- what belongs in the forensic trail.
Refusal is data. Stable refusal codes let a face explain, a caller retry only
when retry is meaningful, and the trail distinguish policy from breakage.
`describe` is the inspection surface: clients should not copy a verb list and
guess which actions are live.
## Idle and inhibitors
Idleness is evidence from the compositor, not a timer duplicated in every
surface. Applications and system work can inhibit consequences, but an
inhibitor is scoped, named, and inspectable. It is not a permanent alternate
writer of panel or lock state.
The authority may decide to dim, lock, blank, doze, suspend, or stay awake.
The state machine records that decision and the executor performs the action.
No shell timer, hypridle listener, or device script gets an independent vote.
## The boundary that exists today
The current local session socket is mode `0600` and accepts same-user callers.
That is a useful local boundary, not the eventual attested capability system.
A process running as the user can still reach more than the doctrine intends.
The account and process boundary that turns peer credentials into an actual
agent identity is specified in
[agent principals](../identity/02-agent-principal.md). Until it lands, Agent
Health must describe a live agent as `acting-as-human`, not infer personhood or
authority from a SeedID alone.
Also not yet true:
- step-up metadata is not wired across send, delete, push, or physical-access
verbs;
- fingerprint authentication and short-lived reveal grants are not live on
blueline;
- callers do not present capability tokens or binary attestation;
- every device operation does not yet have a complete `describe`-derived
control surface;
- refusal and acknowledgement shapes are not yet uniform across every family.
Those are security and control gaps. A polished button does not close them.
## Proof
Keep four claims separate:
1. **source** — the authority and verb exist in the tree;
2. **package** — CI built and signed the owning files and dependencies;
3. **installed** — the device owns those package files and no higher-priority
local splint shadows them;
4. **exercised** — the real caller, authority, executor, and acknowledgement ran
on the intended body.
The last is the only proof that a lock was secure, a panel moved, or an action
crossed the boundary it claims.