Skip to content

feat(vault-agent): session resume across restart via kernel keyring (opt-in)#15

Merged
UnbreakableMJ merged 1 commit into
mainfrom
session-resume
Jun 15, 2026
Merged

feat(vault-agent): session resume across restart via kernel keyring (opt-in)#15
UnbreakableMJ merged 1 commit into
mainfrom
session-resume

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

What

Opt-in session resume across agent restarts on Linux. The agent starts cold
and locked today, so every restart (crash, stop-agent + auto-spawn, logout)
forces a full master-password unlock. With agent.session_keyring enabled, an
unlock mirrors the user key into the Linux kernel session keyring so a
restarted agent resumes unlocked without the master password — bounded by
the idle-lock TTL.

Why the kernel keyring

To usefully resume, a cold agent needs the user key back (it's what
decrypts items), not just the server token — which means the key must persist
outside the agent's memory. That's in tension with PRD §7.3 / G4 ("master key
never resident outside the agent process … never swapped"). The kernel session
keyring is the most PRD-aligned option: kernel memory, never on disk, never
swapped, possessor-gated, evicted on logout.
It's the sole, default-off
carve-out to G4, now documented in PRD §7.3. Off, the key never leaves the
process; the feature is a no-op on non-Linux.

How

  • session.rsSessionBlob (user key + account + deadline) and
    store/load/clear over the pure-Rust linux-keyutils crate
    ([target.'cfg(target_os = "linux")'], MIT/Apache-2.0; no C dep → avoids the
    ring/-flto link breakage). No-op stub elsewhere.
  • state.rspersist_session (deadline = idle_lock_secs, kernel
    set_timeout so a dead agent's session self-expires; re-armed on activity,
    throttled). The lock() funnel is split: lock() (in-memory wipe) for
    Quit/SIGTERM → resumable; lock_and_clear_session() for vault lock /
    idle-lock → clears the keyring (durably locked).
  • main.rs--session-keyring flag; try_resume() at startup rebuilds
    the vault via the existing unlock::load_cache + vault_from_user_key path,
    honoring the deadline. SIGTERM keeps lock() (resumable).
  • vault-configagent.session_keyring key → --session-keyring on
    auto-spawn (same path as idle_lock_secs).

Resume model

path clears keyring? resumes?
vault lock / idle-lock yes no — user/policy locked
stop-agent (Quit) / SIGTERM / crash no yes, within the idle-lock TTL
logout / reboot n/a (keyring gone) no

Tests

  • SessionBlob serde round-trip (cross-platform) + a keyring store/load/clear
    round-trip that skips gracefully where no keyring exists (passes on this host).
  • vault-config: agent.session_keyring get/set/unset + agent_args flag
    emission (only when true).
  • Existing agent suites green; the lock() split leaves current lock behavior
    intact.

Local CI-exact gates all green: fmt, fresh isolated clippy -D warnings,
cargo test --workspace --all-targets under RUSTFLAGS=-D warnings,
cargo deny check (the new linux-keyutils dep — licenses ok), both
headless builds.

🤖 Generated with Claude Code

…opt-in)

Opt-in `agent.session_keyring` (Linux): on unlock, mirror the user key into
the kernel session keyring (kernel memory — never on disk, never swapped,
possessor-gated, evicted on logout) so a restarted agent resumes unlocked
without the master password, bounded by the idle-lock TTL.

- session.rs: SessionBlob + store/load/clear over linux-keyutils
  (target.linux dep, MIT/Apache-2.0); no-op stub on non-Linux.
- state.rs: session_keyring flag, persist_session (deadline = idle TTL),
  throttled re-arm on touch(); split lock() (in-memory, used by Quit/SIGTERM
  -> resumable) from lock_and_clear_session() (vault lock / idle-lock ->
  clears keyring, durably locked).
- main.rs: --session-keyring flag; try_resume() at startup via
  unlock::load_cache + vault_from_user_key; SIGTERM keeps lock() (resumable).
- vault-config: agent.session_keyring key (parse_bool) -> --session-keyring
  on auto-spawn.
- Sole, default-off carve-out to PRD §7.3/G4; documented in PRD/README.

Tests: SessionBlob serde round-trip (xplat) + keyring store/load/clear
(skips where no keyring); vault-config get/set/unset + agent_args flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@UnbreakableMJ
UnbreakableMJ merged commit 4922e3e into main Jun 15, 2026
8 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the session-resume branch June 15, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant