SouveraineOS umbrella: docs, dumps, handoffs, cross-repo STATE
This commit is contained in:
commit
dc4fd14bbd
13 changed files with 2360 additions and 0 deletions
104
docs/SESSION-TRUST-ARCHITECTURE.md
Normal file
104
docs/SESSION-TRUST-ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Session and interaction trust model
|
||||
|
||||
This is the contract for the Souveraine shell on laptop and phone. It records
|
||||
the boundary between orchestration we own and the Linux/Wayland authorities we
|
||||
must consume rather than replace.
|
||||
|
||||
## Authorities and projections
|
||||
|
||||
| Question | Authority | Souveraine's role |
|
||||
| --- | --- | --- |
|
||||
| Can this machine suspend, hibernate, power off, or reboot? | logind `Can*` methods | Query and expose the answer; execute the matching logind/systemd verb. |
|
||||
| Has the compositor secured the display? | `WlSessionLock.secure` | Mirror it as `screenLockSecure`; never infer it from a button press. |
|
||||
| Does the shell want its lock surface shown? | `GlobalStates.screenLocked` | Maintain this request state and persist it across a shell crash. |
|
||||
| Has the user authenticated? | PAM and the lock's `LockContext` | Start a PAM conversation; only it may release `WlSessionLock`. |
|
||||
| Why is automatic idle sleep suppressed? | The active idle mechanism | Keep a reason/cookie registry, but report only mechanisms that are actually applied. |
|
||||
|
||||
`screenLocked` and `screenLockSecure` must stay distinct. The first closes
|
||||
ordinary shell surfaces immediately. The second is the only proof suitable for
|
||||
personal-data disclosure. A failed or delayed Wayland lock is therefore
|
||||
visible as `lockRequested: true, locked: false`, not mistaken for success.
|
||||
|
||||
## Session IPC
|
||||
|
||||
All structured IPC results are JSON strings. Quickshell IPC only marshals
|
||||
primitive QML types, so `: var` silently becomes `void` and loses its payload.
|
||||
|
||||
`session.lock()` means “the Wayland lock was requested”; it does not claim
|
||||
the compositor is secure yet. `session.state()` exposes the subsequent
|
||||
`locked` acknowledgement and the most recent asynchronous power-action result.
|
||||
Power verbs return `status: "started"` when their command has started; a later
|
||||
exit is available in `lastAction`. Refusals always log and return a reason.
|
||||
|
||||
The current public inhibitor surface implements `idle` and `sleep`. It is
|
||||
intentionally wrong to accept `shutdown`, `logout`, or `user-switch` until each
|
||||
owns a real mechanism. The eventual contract is:
|
||||
|
||||
| Kind | Backend | Status |
|
||||
| --- | --- | --- |
|
||||
| `idle` | Native Wayland idle inhibitor once verified on both targets; until then the tested hypridle control path. | Implemented. |
|
||||
| `sleep` | A live logind/systemd inhibitor FD or `systemd-inhibit` process, held for the cookie lifetime. | Implemented via SessionEvents delay-mode inhibitor. |
|
||||
| `logout`, `user-switch` | Shell policy checks at those operations, not fake logind inhibitors. | Not yet implemented. |
|
||||
|
||||
Every inhibitor must have a non-empty human reason, a cookie, and a visible
|
||||
holder in `state()`. Releasing an unknown cookie is a refusal.
|
||||
|
||||
## Lock and suspend sequencing
|
||||
|
||||
The next lifecycle change is not another cached state machine. It is a logind
|
||||
event ingress, implemented in `services/SessionEvents.qml`:
|
||||
|
||||
1. [done] Subscribe to the current logind session's `Lock` signal and request the
|
||||
Wayland lock on receipt. This makes external `loginctl lock-session` calls
|
||||
meaningful without assuming logind implements a screen locker.
|
||||
2. [done] Hold one delay-mode sleep inhibitor from shell startup.
|
||||
3. [done] On logind `PrepareForSleep(true)`, request the Wayland lock and wait for
|
||||
`WlSessionLock.secure`; release the delay inhibitor only then.
|
||||
4. [done] Reacquire it after `PrepareForSleep(false)`.
|
||||
|
||||
The delay budget is logind's `InhibitDelayMaxUSec` (commonly five seconds), so
|
||||
this must be timed on the Pixel 3 before it becomes a security claim. The
|
||||
failure policy is fail closed: if the lock is not secure before the deadline,
|
||||
leave a diagnostic event and do not pretend the session was locked.
|
||||
|
||||
## Interaction capability tiers
|
||||
|
||||
The lock screen, media controls, and agent are one policy system, not three.
|
||||
Each operation and each response is labelled with a minimum tier:
|
||||
|
||||
| Tier | Requirement | Examples |
|
||||
| --- | --- | --- |
|
||||
| `ambient` | None | clock, weather, timers, transport controls, non-personal answers |
|
||||
| `personal` | No lock is requested and the compositor is not secure (`!screenLocked && !screenLockSecure`) | messages, calendar, memories, fleet state, conversation history |
|
||||
| `stepUp` | Recent successful reauthentication | sending, pushes, deletion, payments, physical access |
|
||||
|
||||
Media metadata is `ambient` by default but must be configurable to `personal`.
|
||||
When the lock occurs, in-flight personal or step-up agent output is withheld or
|
||||
redacted; only ambient output remains visible.
|
||||
|
||||
Step-up authentication is a separate `PamContext`, using a dedicated PAM
|
||||
service such as `souveraine-stepup`. It never unlocks the session and it never
|
||||
accepts a boolean from an agent as proof. A successful result mints a
|
||||
short-lived, in-memory grant bound to the local action family. The grant must
|
||||
be cleared on lock, session end, PAM failure, and expiry. The exact freshness
|
||||
window is a deliberate policy setting, not an implementation accident.
|
||||
|
||||
Implemented in `services/StepUpAuth.qml`. The PAM service file
|
||||
(`/etc/pam.d/souveraine-stepup`) is NOT shipped by the shell — it is
|
||||
root-owned system configuration and must be installed/audited separately.
|
||||
Before enabling it, verify that one polkit agent owns the session and that
|
||||
no legacy desktop power manager is competing for idle or sleep policy.
|
||||
|
||||
The trust boundary matrix is documented in `TRUST-BOUNDARY-MATRIX.md`.
|
||||
|
||||
## Required verification
|
||||
|
||||
- `session.capabilities()` matches logind `Can*` on laptop and phone.
|
||||
- `session.lock()` reaches `locked: true` only after `WlSessionLock.secure`.
|
||||
- `loginctl lock-session` and suspend both take the same Wayland lock path.
|
||||
- Unsupported inhibitors refuse; each supported cookie visibly changes its
|
||||
mechanism and is released exactly once.
|
||||
- A lock during personal agent output hides it; a lock during an ambient timer
|
||||
leaves only the timer visible.
|
||||
- Step-up grants cannot survive lock, timeout, shell restart, or action-family
|
||||
changes. [done — StepUpAuth revokes on lock, expiry timer runs every 30s]
|
||||
Loading…
Reference in a new issue