Bug Description:
enclave ssh-init generates a dedicated SSH keypair and copies known_hosts
into ~/.cache/enclave/ssh/ (config.HostSSHDir, internal/config/host_paths.go:36).
The cache root is the wrong home for that content on two counts:
- A private key is not regenerable. The cache root is documented as
"regenerable" (internal/config/host_roots.go:18-23), and the XDG spec
treats cached data as deletable at any time without loss of function.
Deleting this key loses the identity: the matching public key is already
registered with the user's Git providers, so it cannot be recreated, only
replaced and re-registered.
enclave cleanup --all removes the entire cache root
(internal/app/cleanup.go:216) and only skips it when --keep cache is
passed. The --keep auth gate that protects the other credential stores
does not cover the SSH directory, because those stores live under the state
root while SSH does not.
The same reasoning applies to system cache sweepers, which are free to reap
~/.cache contents.
ssh-init also invites users to drop their own keys into the directory
("Alternatively, replace the keys in %s with your desired keys",
internal/app/ssh.go:66), which makes it user-owned content by intent.
Steps to Reproduce:
enclave ssh-init — generates ~/.cache/enclave/ssh/id_ed25519 and prints
the public key to register with a Git provider.
- Register the public key with the Git provider, and confirm
git push works
from inside a session.
enclave cleanup --all — the SSH directory is removed along with the rest
of the cache root. Sessions fall back to the "SSH not configured" warning
(internal/runtime/runtime.go:1047) and the registered public key is now
dead.
Additional Information
- Operating System: Linux
- Enclave Version: rolling-12-g6ab6e6f
Proposed change
Move the SSH directory to the config root: ~/.config/enclave/ssh/ on Linux,
the corresponding Apple config subtree on macOS. Cleanup targets are already
forbidden from resolving under the config root, so this makes the keys
structurally safe from enclave cleanup, and it matches the fact that users
are expected to edit the directory's contents.
The state root is the alternative, consistent with the auth stores under
~/.local/state/enclave/tools/. It needs an explicit cleanup exemption to be
safe, and it fits user-supplied keys less well. Maintainer call — this issue
assumes the config root.
Migration
Existing users must not silently lose SSH access, and the key must be moved
rather than regenerated:
ssh-init creates and reports the new location.
- On startup, if the old
~/.cache/enclave/ssh/ exists and the new location
does not, move it and log the relocation once. Preserve 0700 on the
directory and 0600 on the key files.
- Leave the old path alone when both exist; the new location wins.
Affected code and docs
internal/config/host_paths.go:36 — HostSSHDir root.
internal/app/ssh.go — ssh-init setup and messages.
internal/runtime/runtime.go:1041 — mount lookup, plus the fallback probe
for the old path.
internal/app/cleanup.go — verify no cleanup target resolves to the new
path.
docs/auth.md:186, docs/cli-reference.md:86, docs/ARCHITECTURE.md:33,
and the host-data section in AGENTS.md.
Acceptance criteria
enclave ssh-init writes to the config root with 0700/0600 permissions.
enclave cleanup --all leaves the SSH directory intact, with no --keep
flag required.
- A pre-existing
~/.cache/enclave/ssh/ is relocated on the next run, keeping
the same keypair and permissions.
- Sessions mount the SSH directory read-only from the new location.
- Tests cover the migration (old-only, new-only, both present) and assert that
no cleanup target resolves under the SSH directory.
Bug Description:
enclave ssh-initgenerates a dedicated SSH keypair and copiesknown_hostsinto
~/.cache/enclave/ssh/(config.HostSSHDir,internal/config/host_paths.go:36).The cache root is the wrong home for that content on two counts:
"regenerable" (
internal/config/host_roots.go:18-23), and the XDG spectreats cached data as deletable at any time without loss of function.
Deleting this key loses the identity: the matching public key is already
registered with the user's Git providers, so it cannot be recreated, only
replaced and re-registered.
enclave cleanup --allremoves the entire cache root(
internal/app/cleanup.go:216) and only skips it when--keep cacheispassed. The
--keep authgate that protects the other credential storesdoes not cover the SSH directory, because those stores live under the state
root while SSH does not.
The same reasoning applies to system cache sweepers, which are free to reap
~/.cachecontents.ssh-initalso invites users to drop their own keys into the directory("Alternatively, replace the keys in %s with your desired keys",
internal/app/ssh.go:66), which makes it user-owned content by intent.Steps to Reproduce:
enclave ssh-init— generates~/.cache/enclave/ssh/id_ed25519and printsthe public key to register with a Git provider.
git pushworksfrom inside a session.
enclave cleanup --all— the SSH directory is removed along with the restof the cache root. Sessions fall back to the "SSH not configured" warning
(
internal/runtime/runtime.go:1047) and the registered public key is nowdead.
Additional Information
Proposed change
Move the SSH directory to the config root:
~/.config/enclave/ssh/on Linux,the corresponding Apple config subtree on macOS. Cleanup targets are already
forbidden from resolving under the config root, so this makes the keys
structurally safe from
enclave cleanup, and it matches the fact that usersare expected to edit the directory's contents.
The state root is the alternative, consistent with the auth stores under
~/.local/state/enclave/tools/. It needs an explicit cleanup exemption to besafe, and it fits user-supplied keys less well. Maintainer call — this issue
assumes the config root.
Migration
Existing users must not silently lose SSH access, and the key must be moved
rather than regenerated:
ssh-initcreates and reports the new location.~/.cache/enclave/ssh/exists and the new locationdoes not, move it and log the relocation once. Preserve
0700on thedirectory and
0600on the key files.Affected code and docs
internal/config/host_paths.go:36—HostSSHDirroot.internal/app/ssh.go—ssh-initsetup and messages.internal/runtime/runtime.go:1041— mount lookup, plus the fallback probefor the old path.
internal/app/cleanup.go— verify no cleanup target resolves to the newpath.
docs/auth.md:186,docs/cli-reference.md:86,docs/ARCHITECTURE.md:33,and the host-data section in
AGENTS.md.Acceptance criteria
enclave ssh-initwrites to the config root with0700/0600permissions.enclave cleanup --allleaves the SSH directory intact, with no--keepflag required.
~/.cache/enclave/ssh/is relocated on the next run, keepingthe same keypair and permissions.
no cleanup target resolves under the SSH directory.