mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-10-01 19:43:49 +00:00
fix(agentgit): register the member's SSH key on every BBS login, not just at signup (#131)
provisionGit returned early when the Forgejo account already existed, so
EnsureKey only ever ran during first provisioning. A member who deleted their
key on git.profullstack.com never got it back: every later BBS login hit the
`if !created { return }` and skipped key registration entirely. The comment on
the web verify path ("key is added on next BBS login") was describing behaviour
that could not happen.
Key registration now runs on every provisionGit call that carries a session
key. EnsureKey was already idempotent — it GETs the account's keys and compares
key material ignoring the comment — so re-running it is free when nothing
changed, and it re-adds a removed key, picks up a rotated one, and backfills
members who joined before AgentGit captured keys. The welcome email stays gated
on `created`, since the one-time password is only meaningful for a new account.
Two things that would have made this unreliable in the new every-login path:
- The key title was the constant "agentbbs". Forgejo rejects a duplicate title
with 422, so a member who rotated their BBS key would have had the new one
silently dropped. The title now carries a short fingerprint, so distinct keys
coexist and the same key stays stable across logins.
- EnsureKey mapped *every* 422 to "already exists" and returned nil. That hid
genuine rejections forever, which matters far more now the call is on the hot
path. Only "has been used" bodies are swallowed; a rejected key surfaces with
Forgejo's own reason so it lands in the logs.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
249a4e669b
commit
078937109c
4 changed files with 182 additions and 9 deletions
|
|
@ -207,8 +207,15 @@ func (c Config) EnsureKey(username, title, pubKey string) (added bool, err error
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Forgejo answers 422 both for "this key/title is already here" (benign, we
|
||||
// raced or the comment differs) and for "this key content is unusable".
|
||||
// Treating every 422 as benign hid real rejections forever, so only swallow
|
||||
// the ones that say the key or title is already taken.
|
||||
if status == http.StatusUnprocessableEntity {
|
||||
return false, nil // key already exists (raced or comment differs)
|
||||
if alreadyUsed(resp) {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("forgejo rejected key %q: %s", username, truncate(resp, 200))
|
||||
}
|
||||
if status < 200 || status >= 300 {
|
||||
return false, fmt.Errorf("forgejo add key %q: %d: %s", username, status, truncate(resp, 200))
|
||||
|
|
@ -216,6 +223,14 @@ func (c Config) EnsureKey(username, title, pubKey string) (added bool, err error
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// alreadyUsed reports whether a 422 body is Forgejo saying the key or its title
|
||||
// is already on the account, as opposed to rejecting the key content itself.
|
||||
// Forgejo's wording: "Key content has been used as non-deploy key" /
|
||||
// "Key title has been used".
|
||||
func alreadyUsed(resp string) bool {
|
||||
return strings.Contains(strings.ToLower(resp), "has been used")
|
||||
}
|
||||
|
||||
// keyMaterial returns the type+base64 of an authorized-key line, dropping the
|
||||
// optional comment so the same key compares equal regardless of how it's labeled.
|
||||
func keyMaterial(authorizedKey string) string {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue