Clone with the login token, and add SSH keys automatically #59
worktree-clone-auth-ssh-key-auto
into main
anvil auth login did not get you a working checkout. Two gaps:
repo clone only ever spoke SSH. It built git@host:org/repo.git unconditionally, so a freshly logged-in user was rejected by git with “Permission denied (publickey)” — a message naming neither Anvil nor the fix. The server accepts the login token for git-over-HTTPS (Basic auth, password = PAT, username ignored), so that credential existed the whole time and was never offered.
Clone now defaults to HTTPS with the login token. --ssh opts back in.
The token is not written into the clone:
- not in the remote URL (that persists a secret into
.git/configand survivesauth rotate), - not in
-c http.extraHeader(that exposes it in argv to every process on the machine).
Instead git is pointed at the anvil binary as a credential helper, scoped to the configured server so the token is never offered to another host. The helper is written into the new clone too, so git pull/git push keep working without a prompt. New hidden subcommand: anvil auth git-credential.
ssh-key add required --name and --key-file. Now bare anvil ssh-key add (or --auto):
- finds the best key in
~/.ssh— Ed25519 > ECDSA > RSA > DSA, stable ordering, skipping certificates andknown_hosts; - names it from the key’s own comment, else
user@host; - skips the upload when the fingerprint is already registered, so it is safe to re-run from a setup script;
- recovers a deleted public half via
ssh-keygen -yinstead of generating a second key beside the good one; - with no key and a terminal, walks through creating one (type, path, comment;
ssh-keygenowns the passphrase prompt so it never touches our argv or memory); - with no terminal, refuses unless
--yes— minting a credential silently inside a script is not a default.
Public keys are parsed and fingerprinted in-process (SHA256, OpenSSH display form). That parser is also what refuses to upload a private key passed by mistake.
Verification
Against the live server:
- fresh clone of
fangorn/faradayauthenticates with the login token alone, no SSH key involved; .git/configholds a plain remote URL and the scoped helper — no token;- subsequent
git fetchsucceeds withGIT_TERMINAL_PROMPT=0, proving the helper answers the 401 unattended; - the helper emits zero bytes for a
github.comchallenge; - live discovery on a machine holding both key types picks
~/.ssh/id_ed25519.pub.
699 tests pass (up from 684); clippy clean under -D warnings; cargo fmt --check clean. New: 10 end-to-end tests for the auto path against a mock server with a redirected ~/.ssh, plus unit tests for key parsing/fingerprinting/discovery and the credential-helper protocol.
Backwards compatible: the old ssh-key add --name X --key-file Y form still works, and the clone JSON still carries ssh_url.
🤖 Generated with Claude Code