saf: name the borrowed hand and lock owner
Make the laptop and phone obey the same principal map: Souvie, Annie/Aster, and Vanguard are dedicated residents; Kitty, Gem, and Hal knowingly borrow Casey's UID. Their live posture is regenerated from actual credentials for every model request, outside memory, replay, and compaction.\n\nTake the lock boundary out of all of them. Casey authenticates, agents may request, and the dedicated souveraine-session principal holds the hostile pre-unlock edge with only Ambient and Revealable reach.
This commit is contained in:
parent
af60d9e401
commit
ee496a7c6e
4 changed files with 172 additions and 6 deletions
|
|
@ -27,6 +27,58 @@ authorities with hand-maintained booleans. It consumes them:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -33,12 +33,17 @@ agents. The name is reserved.
|
|||
|
||||
Casey's devices retain Casey's human account. Agents do not borrow it.
|
||||
|
||||
| Agent | Role | Suggested local account |
|
||||
| Agent | Role | Required local account on Casey's admitted nodes |
|
||||
|---|---|---|
|
||||
| Souvie / Souveraine | default Souveraine agent on a fresh system | `souvie` |
|
||||
| Annie | Casey's primary personal agent | `annie` |
|
||||
| Annie, in both Ani and Aster cadence | Casey's primary personal agent | `annie` |
|
||||
| Vanguard | named additional agent | `vanguard` |
|
||||
|
||||
"Each node" includes this laptop. The laptop is not a development exception,
|
||||
and the phone is not a special appliance case. When these three resident
|
||||
agents run on either body, their turn, subconscious pass, memory access, and
|
||||
tools must cross the worker boundary under the mapped account.
|
||||
|
||||
The display name is editable. The agent ID, SeedID, and admitted account
|
||||
mapping are not derived again when the display name changes. Account names are
|
||||
chosen once, checked against the local account database and reserved names,
|
||||
|
|
@ -58,6 +63,73 @@ Unix user. Aster shares Annie's principal unless Casey and the system later
|
|||
admit her as an independently authorized agent. The account boundary follows
|
||||
authority, not the number of internal thought streams.
|
||||
|
||||
## Resident agents and borrowed-user modes
|
||||
|
||||
Not every named mode needs a Unix account. Kitty, Gem, and Hal are intended to
|
||||
run as hosted or borrowed-user modes under Casey's account rather than claim a
|
||||
fully admitted resident identity. That is a deliberate posture, not the same
|
||||
failure as Annie accidentally running as Casey.
|
||||
|
||||
The durable agent record therefore carries a principal intent, not one vague
|
||||
boolean:
|
||||
|
||||
| Intent | Expected runtime | Meaning |
|
||||
|---|---|---|
|
||||
| `dedicated` | the named agent account | full node admission and kernel-backed identity |
|
||||
| `borrowed-user` | the invoking human account | a hosted mode using authority the human process can already reach |
|
||||
|
||||
On Casey's current fleet Souvie, Annie/Aster, and Vanguard are `dedicated`.
|
||||
Kitty, Gem, and Hal are `borrowed-user`. Promoting a borrowed mode to a resident
|
||||
agent is an admission ceremony; changing a UI label or model does not do it.
|
||||
|
||||
A borrowed-user mode must know, in every model request, that readable does not
|
||||
mean owned or shareable. Its operating posture is stricter:
|
||||
|
||||
- Casey's files, groups, sockets, credentials, and decrypted home are borrowed
|
||||
reach, not the mode's personal territory;
|
||||
- do not widen mode bits, ACLs, group membership, links, remotes, publication,
|
||||
or sharing outside the explicit task without Casey's confirmation;
|
||||
- prefer the named workspace or a narrow temporary copy over exploring the
|
||||
rest of the human home;
|
||||
- never read or disclose a resident agent's private memory merely because the
|
||||
shared human UID permits it;
|
||||
- attribute actions to a borrowed mode acting through Casey's principal, not
|
||||
to an independently admitted agent.
|
||||
|
||||
This caution is context and policy, not a substitute for containment. A
|
||||
borrowed process still has Casey's kernel permissions; sensitive verbs must
|
||||
remain behind the same capability and consent gates.
|
||||
|
||||
## The live principal fact
|
||||
|
||||
The intent in `agent.json` is durable. The live posture is observed afresh from
|
||||
the selected agent or mode, node mapping, process credentials, and worker unit.
|
||||
The trigger may expose a convenient `operating_as_user` boolean, but that
|
||||
boolean is only a projection of the facts and is never an authorization input.
|
||||
|
||||
The runtime projection contains at least:
|
||||
|
||||
```text
|
||||
agent_id, display_name, principal_intent
|
||||
expected_account, effective_account, effective_uid
|
||||
node_id, worker_pid, trigger, observed_at
|
||||
posture = isolated | borrowed-user | acting-as-human | drift
|
||||
```
|
||||
|
||||
It is injected as a fresh system block into **every model request**, including
|
||||
Ani and Aster passes, subagents, resumed conversations, and later tool rounds
|
||||
after a mode switch. It is not ordinary conversation history and cannot be
|
||||
microcompacted, replayed from an old session, or taught back as assistant
|
||||
speech.
|
||||
|
||||
A machine-generated cache may be exposed as
|
||||
`/run/souveraine/agent-principals/{agent_id}.json` and a Markdown rendering for
|
||||
inspection. It does not belong in the agent-writable, Git-backed
|
||||
`system/dynamic/` memory tree: an awareness file the agent can edit cannot be
|
||||
the source of who the kernel says she is. The prompt projection rechecks the
|
||||
effective credentials when it reads the cache. Authorization always checks
|
||||
the actual peer and process credentials again at the verb boundary.
|
||||
|
||||
## Creation is logical creation followed by admission
|
||||
|
||||
The current creation path makes a UUID, an agent seed, memory directories, an
|
||||
|
|
@ -82,7 +154,7 @@ Agent creation should ask for the authority shape, not merely a name and
|
|||
model:
|
||||
|
||||
- create a new identity or admit an existing one;
|
||||
- local principal name, with the suggested name visible;
|
||||
- principal intent and, for a resident, the required local account name;
|
||||
- which node and role are being admitted;
|
||||
- whether the privileged admission completed;
|
||||
- which operating skill was projected from the admitted capabilities.
|
||||
|
|
@ -171,8 +243,9 @@ The top-level states are deliberately blunt:
|
|||
| State | Meaning |
|
||||
|---|---|
|
||||
| `isolated` | account, ownership, worker, commission, and peer identity agree |
|
||||
| `borrowed-user` | hosted mode intentionally uses the invoking human's account and receives the cautious borrowed-permission posture |
|
||||
| `unadmitted` | logical agent exists; this node has no completed admission |
|
||||
| `acting-as-human` | a turn or tool is executing as Casey or another human UID |
|
||||
| `acting-as-human` | a `dedicated` agent's turn or tool is unexpectedly executing as Casey or another human UID |
|
||||
| `principal-drift` | mapping exists but NSS, ownership, unit, or peer facts disagree |
|
||||
| `identity-drift` | account is healthy but agent key or node commission does not match |
|
||||
| `stopped` | admission is sound and no worker is currently expected/running |
|
||||
|
|
@ -180,7 +253,9 @@ The top-level states are deliberately blunt:
|
|||
`acting-as-human`, `principal-drift`, and `identity-drift` are not yellow
|
||||
decorations. They refuse personal and step-up authority. Ambient conversation
|
||||
may remain available in a visibly degraded compatibility mode while migration
|
||||
is unfinished.
|
||||
is unfinished. `borrowed-user` is intentional and may use only the human-granted
|
||||
capability surface; it never becomes `isolated` merely because Casey's UID can
|
||||
read something.
|
||||
|
||||
The audit trail records both logical and kernel-backed subjects: agent ID,
|
||||
node ID, account name, UID, PID, operation, human requestor or consent grant,
|
||||
|
|
@ -217,11 +292,14 @@ gives the newly admitted agent an accurate way to use and explain it.
|
|||
- The setup wizard defaults inconsistently between `Souveraine` state and an
|
||||
`Ani` form field; neither creates a Unix account.
|
||||
- the packaged `souveraine` account exists only for the machine tier;
|
||||
- on the laptop, NSS currently has no `souvie`, `annie`, or `vanguard`
|
||||
accounts, and all seven agent records live below Casey's home;
|
||||
- the Agent settings diagnostics check IDs and paths, not principal or process
|
||||
identity;
|
||||
- the server hosts multiple agents inside the human's process and home;
|
||||
- no admission executor, per-agent worker boundary, account mapping, account
|
||||
health result, or generated operating skill exists yet.
|
||||
health result, fresh runtime-principal projection, or generated operating
|
||||
skill exists yet.
|
||||
|
||||
Until those pieces land, the system must say **logical identity present,
|
||||
kernel principal absent**. That is the live gap this chapter owns.
|
||||
|
|
|
|||
|
|
@ -64,6 +64,26 @@ bulk of older tool-result output with an explicit cleared marker, keeping the
|
|||
recent results intact. The typed record is compacted first; replay projects the
|
||||
result afterward.
|
||||
|
||||
## Current authority never replays
|
||||
|
||||
Identity memory says who an agent understands herself to be. It cannot say
|
||||
which Unix principal is handling this request now. Every model request receives
|
||||
a fresh runtime-principal system block described in
|
||||
[agent principals](../identity/02-agent-principal.md): dedicated resident,
|
||||
intentional borrowed-user mode, actual UID, expected account, node, and drift.
|
||||
|
||||
That block is synthesized from current process and admission facts after
|
||||
history replay. It is not stored as assistant or user text, not committed to
|
||||
the agent's memfs, and not an input to compaction. Resume recomputes it. A mode
|
||||
switch recomputes it. Ani and Aster receive the same `annie` account fact;
|
||||
Kitty, Gem, and Hal receive the explicit warning that they are borrowing
|
||||
Casey's Unix authority.
|
||||
|
||||
This is the same invariant as reasoning: a typed system fact must not be
|
||||
flattened into speech. A stale replay must never convince a borrowed mode that
|
||||
it owns Casey's permissions, or convince an unadmitted resident that it has
|
||||
the account it was meant to receive.
|
||||
|
||||
## Three properties that are load-bearing
|
||||
|
||||
All three were learned from failures, and all look like details until they
|
||||
|
|
|
|||
|
|
@ -33,6 +33,22 @@ This graph raises [session authority](../authority/01-session.md); it does not
|
|||
replace it. systemd owns process lifetime and dependency order. Sessiond owns
|
||||
session policy once its socket is ready.
|
||||
|
||||
## The principal split still owed
|
||||
|
||||
This is the process-order graph that exists; it is not yet the final security
|
||||
boundary. All of its units are currently user units and therefore inherit the
|
||||
human graphical session's UID. The target moves sessiond's lock lifecycle to
|
||||
the dedicated `souveraine-session` principal described in
|
||||
[session authority](../authority/01-session.md), while the user manager keeps
|
||||
only the presentation and application lifetimes that belong there.
|
||||
|
||||
The compositor must offer that principal a narrow way to hold
|
||||
ext-session-lock and render the fallback without granting it Casey's home or
|
||||
general session bus. The lock authority must be ready before the user home is
|
||||
decrypted and remain ready after the Personal key is evicted. Changing unit
|
||||
placement without proving the Wayland connection, PAM path, handoff, crash
|
||||
retake, and key-eviction order would only move the black screen to a new UID.
|
||||
|
||||
## Package boundary
|
||||
|
||||
`souveraine-viewtop` owns the compositor and the session edge on both x86_64
|
||||
|
|
|
|||
Loading…
Reference in a new issue