Skip to content

Validate agent SSH key: fix false-pass auth check, add per-org SSO, wire into claudeconfig#12

Merged
technicalpickles merged 5 commits into
mainfrom
agent-ssh-key-sso-and-auth-check
Jun 15, 2026
Merged

Validate agent SSH key: fix false-pass auth check, add per-org SSO, wire into claudeconfig#12
technicalpickles merged 5 commits into
mainfrom
agent-ssh-key-sso-and-auth-check

Conversation

@technicalpickles

Copy link
Copy Markdown
Owner

Summary

  • check-agent-ssh-key's SSH auth check was a false pass: without -F /dev/null it authenticated via the human laptop key (same GitHub account, so the Hi <user>\! greeting was identical) and would have green-lit a broken or unregistered agent key. Now it forces the agent key and asserts the accepted fingerprint matches.
  • Added a per-org SAML SSO probe (work role): a key can authenticate to github.com yet still be rejected for org repos until authorized for that org's SSO. This caught the agent key being authorized for one org but not another.
  • claudeconfig.sh now validates the active role's agent SSH identity after applying config, fail-loud, with --skip-ssh-check for offline / fresh-setup. Rationale and the contrast with ADR 0036's warn-not-fail are in ADR 0037.
  • setup-agent-ssh-key now spells out the SSO-authorization step (the bit that's easy to forget) and points at the verifier instead of a manual badge check.

Test plan

  • bin/check-agent-ssh-key work --email josh.nichols+agent@gusto.com reports both orgs SSO-authorized and "works with this key".
  • ssh -v confirmed: with -F /dev/null the server accepts the agent key; without it, the laptop key.
  • claudeconfig.sh --help, bad-arg (exit 2), email derivation, base no-op, and --skip-ssh-check early-return all verified. Full apply not run here (it rewrites live ~/.claude/settings.json).

Note

With validation live, your next claudeconfig.sh (work role) fails until gh auth refresh -h github.com -s user:email, the real gap the check flags today. That's fail-loud working as intended; --skip-ssh-check bypasses it.

technicalpickles and others added 5 commits June 15, 2026 15:08
…gent-ssh-key

check-agent-ssh-key step 7 omitted -F /dev/null, so ~/.ssh/config's additive
`Host *` IdentityFile leaked the human laptop key as a candidate (IdentitiesOnly=yes
does not drop config-supplied identities). ssh offered the laptop key first and the
server accepted it; since both keys live on the same GitHub account the greeting was
identical, so the check passed via the wrong key and would green-light even a broken
or unregistered agent key. Add -F /dev/null plus a fingerprint assertion against the
-v 'Server accepts key' line so step 7 genuinely exercises this key.

Add step 8: per-org SAML SSO authorization probe, gated on the work role. A key can
authenticate to github.com yet still be rejected for org-owned repos until authorized
for that org's SAML SSO (browser-only, not exposed via gh/API). Probe a canary repo
per org with git ls-remote and detect the 'enabled or enforced SAML SSO' error. Found
when the work agent key authed fine but was unauthorized for guideline-app (Gusto was
already authorized). Non-work roles get an empty org list and skip the block.

Bean: dotfiles-w4tk

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
setup-agent-ssh-key never mentioned the work-role SAML SSO authorization step
(github.com/settings/keys -> Configure SSO) -- the exact gap that let an
un-authorized agent key slip through. Add it as a work-role-only step, and replace
the manual 'make a commit / check the badge' verification with a pointer to
check-agent-ssh-key, which now validates files, Keychain, GitHub registration, auth,
and per-org SSO in one shot.

Bean: dotfiles-w4tk

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize claudeconfig.sh from apply-only to apply-and-validate: after the
existing config phases, a validate phase delegates to bin/check-agent-ssh-key for
the active role and fails loud if the key is wrong. Apply runs first, so config is
never left half-written; only the exit code reflects validation.

The agent email is read from the role's gitconfig include
(home/.gitconfig.d/claude-agent-<role> user.email), so there's one source of truth
and no per-role email mapping to drift. Roles with no agent include (e.g. base) are
a no-op.

--skip-ssh-check (or SKIP_SSH_CHECK=1) bypasses only the validation, leaving apply
intact -- needed offline and on fresh machines, where claudeconfig runs before the
key is registered/SSO-authorized on GitHub. setup-agent-ssh-key step 4 now uses it.

Bean: dotfiles-cr2m

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the decision to validate the active role's agent SSH identity from
claudeconfig.sh (fail-loud, with --skip-ssh-check escape hatch), and reconcile the
hard-fail stance with ADR 0036's warn-not-fail for missing role files: a missing
role file degrades to a usable config, a broken agent identity is external state
that fails confusingly at runtime. Captures the two failure modes that motivated it
(wrong-key false pass, missing per-org SAML SSO authorization).

Bean: dotfiles-cr2m

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.beans/ files are auto-generated by the beans tracker and routinely contain
markdown-emphasis-like text (*, _) that prettier rewrites, breaking format:check
on every push. Add .beans/ to the prettier ignore list so they're never linted.

Also prettier --write two files that had drifted on main (.claude/settings.json,
doc/adr/0031), which is what turned main's CI red since 2026-06-13. This greens
both PR #12 and main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@technicalpickles technicalpickles merged commit 9b3d6e8 into main Jun 15, 2026
1 check passed
@technicalpickles technicalpickles deleted the agent-ssh-key-sso-and-auth-check branch June 15, 2026 20:01
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