fix: stop uploading a duplicate SSH key on key-heavy accounts#9
Conversation
ensureSshAccess() decides whether its key is already on the account by listing GET /ssh-keys — but that endpoint is paginated (10/page, newest first) and the CLI read only page 1 and ignored meta.last_page. On an account with more keys than fit on page 1, the CLI's own key is invisible, so it concludes 'not uploaded' and uploads ANOTHER copy, then attaches it to the site. The SSH connection cache is per-site, so this repeats for every site the user touches and duplicate 'InstaWP CLI' keys pile up in their account. Fetch every page (per_page=100, follow meta.last_page, hard-capped at 20 pages) so matching sees the whole key list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
QA: PASS ✅Env: throwaway InstaWP sandboxes on a test account (our own; 5 pre-existing keys) · 1. Repro before the fix (pre-fix build @
|
Root cause
ensureSshAccess()works out whether its key is already on the account by listingGET /ssh-keys— but that endpoint is paginated (DEFAULT_TEMPLATE_PAGINATION= 10/page, newest first) and the CLI read only page 1, ignoringmeta.last_page.Once an account's key list spills past page 1, the CLI's own key is invisible to it → it concludes "not uploaded" → uploads another copy of a key it already has (
POST /ssh-keys, labelInstaWP CLI) and attaches that to the site instead of the original.How it accumulates (verified in QA — and it's slower than "one per site"): the fresh duplicate is now the newest key, so it sits on page 1 and the next site finds it. The count doesn't grow again until ≥10 newer keys push it back off page 1. So it's one duplicate per "key fell off page 1" episode, not one per site. User-visible symptom is the same: identical
InstaWP CLIkeys accumulating, and the site attached to a duplicate rather than the key the user already had.(
POST /sites/{id}/ssh-keys/{keyId}is already idempotent, so the duplication is purely in the account key list.)Fix
fetchUploadedKeys()now pages through the whole list (per_page=100, followsmeta.last_page, hard-capped at 20 pages) so matching sees every key on the account. No behaviour change when the account has a single page of keys.Test
New regression test: the CLI key sits on page 2 of the account list → it must be matched and attached (id 7), with no upload. It fails on
mainand passes here. Full suite: 486 passing, typecheck clean.QA: PASS ✅
Verified end-to-end against the production API (which does not carry the server-side fix, so this isolates PR #9's effect). The pre-fix build reproduced the duplicate; the PR build produced zero uploads across two fresh sites with the CLI key on page 2, reusing the existing key. First-ever-run path still creates exactly one key. Full evidence in the QA comment below.
Companion PR
InstaWP/client-app#2609 makes
POST /ssh-keysidempotent on identical key material. That closes the fail-open path this PR can't: a failed list call is silently treated as "the account has no keys", and concurrentinstawpruns can race. Also QA-passed. The pair should land together.Run
/code-review ultra <PR#>before merge.— Engineer (agent-os)