Skip to content

Route ssh key requests through api.Client - #13994

Merged
williammartin merged 2 commits into
trunkfrom
williammartin-route-ssh-key-api-client
Aug 4, 2026
Merged

Route ssh key requests through api.Client#13994
williammartin merged 2 commits into
trunkfrom
williammartin-route-ssh-key-api-client

Conversation

@williammartin

@williammartin williammartin commented Jul 28, 2026

Copy link
Copy Markdown
Member

Description

Part of #13991

This PR migrates ssh-key add, ssh-key delete and ssh-key list to use the api.Client for API interactions. There should be no user visible change.

Two test stubs changed from RESTPayload(200, "") to RESTPayload(200, "{}") because the api client expects to unmarshal json (where previously the body was just thrown away); The REST endpoints do return JSON. We also backfill tests for error paths.

Acceptance Test

➜  williammartin-fuzzy-happiness git:(williammartin-route-ssh-key-api-client) GH_ACCEPTANCE_HOST=github.com \
GH_ACCEPTANCE_ORG=gh-acceptance-testing \
GH_ACCEPTANCE_TOKEN="$(gh auth token --hostname github.com)" \
GH_ACCEPTANCE_SCRIPT=ssh-key.txtar \
go test -tags=acceptance -count=1 -v -run '^TestSSHKeys$' ./acceptance
=== RUN   TestSSHKeys
=== RUN   TestSSHKeys/ssh-key
=== PAUSE TestSSHKeys/ssh-key
=== CONT  TestSSHKeys/ssh-key
    testscript.go:584: WORK=$WORK
        PATH=/var/folders/z7/869nt6ns29d77xln9h9bm8680000gn/T/testscript-main2246370769/bin:/Users/williammartin/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.26.5.darwin-arm64/bin:/Users/williammartin/.local/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/pkg/env/global/bin:/Users/williammartin/.local/bin
        GOTRACEBACK=system
        HOME=$WORK
        TMPDIR=$WORK/.tmp
        devnull=/dev/null
        /=/
        :=:
        $=$
        exe=
        SCRIPT_NAME=ssh_key
        GH_CONFIG_DIR=$WORK
        GH_HOST=github.com
        ORG=gh-acceptance-testing
        GH_TOKEN=gho_************************************
        RANDOM_STRING=fLRDwDIyZK
        GH_TELEMETRY=false
        
        # skip 'it modifies the user''s personal GitHub account SSH keys'
        # scopes admin:ssh_signing_key,admin:public_key
        # Generate a globally unique account SSH key (0.001s)
        > generate-ssh-key sshKey.pub acceptance
        # Add an SSH key to the account (1.004s)
        > exec gh ssh-key add sshKey.pub --title 'acceptance-test-key'
        [stderr]
        ✓ Public key added to your account
        # List the SSH keys (0.477s)
        > exec gh ssh-key list
        [stdout]
        williammartin@github.com        ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFo0cmX3RoBGVVXxRDuaSCnirI4BZxsfZ6DwuusqBcBK        2026-01-06T07:33:03Z    139697945       authentication
        Prod    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1mDtJU7B4IMgXZPAuc8g51ttgfQVN/QvSDfmbJjOJE        2026-04-02T11:44:06Z    147421671       authentication
        acceptance-test-key     ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDYCuEYTC/tycRuYQtka9GljaxsTz3ZuCLNdcYzdjGCK2026-07-28T14:08:32Z    158597383       authentication
        > stdout 'acceptance-test-key'
        # Get the ID of the key we created (0.284s)
        > exec gh api /user/keys --jq '.[] | select(.title == "acceptance-test-key") | .id'
        [stdout]
        158597383
        > stdout2env SSH_KEY_ID
        # Delete the SSH key (0.495s)
        > exec gh ssh-key delete --yes ${SSH_KEY_ID}
        # Check the key is deleted (0.543s)
        > exec gh ssh-key list
        [stdout]
        williammartin@github.com        ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFo0cmX3RoBGVVXxRDuaSCnirI4BZxsfZ6DwuusqBcBK        2026-01-06T07:33:03Z    139697945       authentication
        Prod    ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1mDtJU7B4IMgXZPAuc8g51ttgfQVN/QvSDfmbJjOJE        2026-04-02T11:44:06Z    147421671       authentication
        > ! stdout 'acceptance-test-key'
        PASS
        
--- PASS: TestSSHKeys (0.00s)
    --- PASS: TestSSHKeys/ssh-key (2.81s)
PASS
ok      github.com/cli/cli/v2/acceptance        3.247s

Notes

This is a stacked PR. It targets #13989 and the stack ultimately lands on wm/support-api-host-lift-and-shift.

@williammartin
williammartin force-pushed the williammartin-route-ssh-key-api-client branch from d2d8e48 to c9470a3 Compare July 28, 2026 14:05
@williammartin
williammartin marked this pull request as ready for review July 28, 2026 14:25
@williammartin
williammartin requested a review from a team as a code owner July 28, 2026 14:25
@williammartin
williammartin requested review from tidy-dev and removed request for a team July 28, 2026 14:25

@tidy-dev tidy-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

Side note: Seems deleting a signing key doesn't work... surprised me and seems to be preexisting behavior

@williammartin
williammartin force-pushed the williammartin-route-ssh-key-api-client branch from c9470a3 to d6105c4 Compare July 31, 2026 11:21
Copilot AI review requested due to automatic review settings August 1, 2026 07:52
@williammartin
williammartin force-pushed the williammartin-route-ssh-key-api-client branch from d6105c4 to 93a4d4b Compare August 1, 2026 07:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the effort in #13991 to consolidate REST API interactions behind api.Client by migrating the gh ssh-key subcommands (add, delete, list) off direct http.Client request construction. The intent is a lift-and-shift refactor with no user-visible behavior changes, while aligning these commands with cross-cutting API behavior support.

Changes:

  • Replaced direct http.Client request/response handling with api.NewClientFromHTTP(httpClient).REST(...) for SSH key list/add/delete flows.
  • Added/updated unit tests to cover HTTP error paths and adjusted POST stubs to return JSON bodies expected by the API client.
  • Updated acceptance test data to generate a unique SSH public key at runtime instead of using a static key fixture.
Show a summary per file
File Description
pkg/cmd/ssh-key/shared/user_keys.go Routes user key listing through api.Client REST calls instead of manual HTTP+JSON handling.
pkg/cmd/ssh-key/shared/user_keys_test.go Adds coverage for REST HTTP error handling in user key listing.
pkg/cmd/ssh-key/delete/http.go Routes SSH key delete/get through api.Client REST calls.
pkg/cmd/ssh-key/delete/delete_test.go Adds coverage for HTTP error handling in delete/get SSH key helpers.
pkg/cmd/ssh-key/add/http.go Routes SSH key uploads through api.Client REST calls while keeping payload construction intact.
pkg/cmd/ssh-key/add/add_test.go Updates POST stubs to return JSON and adds coverage for upload HTTP error paths.
acceptance/testdata/ssh-key/ssh-key.txtar Switches to generating a unique SSH key during the acceptance test instead of embedding a static key file.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 7/7 changed files
  • Comments generated: 0
  • Review effort level: Lite

Base automatically changed from williammartin-wp-01-deploy-key-api-client to trunk August 4, 2026 08:25
williammartin and others added 2 commits August 4, 2026 10:25
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7ea49581-d435-4617-8830-5f40a036754c
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d5151527-3286-43fd-a420-38f496a076fa
@williammartin
williammartin force-pushed the williammartin-route-ssh-key-api-client branch from 93a4d4b to 29a4d8b Compare August 4, 2026 08:25
@williammartin

Copy link
Copy Markdown
Member Author

@tidy-dev

Side note: Seems deleting a signing key doesn't work... surprised me and seems to be preexisting behavior

Can you file an issue? Not sure what the UX is here.

@williammartin
williammartin merged commit 8d81d03 into trunk Aug 4, 2026
11 checks passed
@williammartin
williammartin deleted the williammartin-route-ssh-key-api-client branch August 4, 2026 08:35
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Aug 21, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [cli/cli](https://github.com/cli/cli) | minor | `v2.97.0` → `v2.98.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>cli/cli (cli/cli)</summary>

### [`v2.98.0`](https://github.com/cli/cli/releases/tag/v2.98.0): GitHub CLI 2.98.0

[Compare Source](cli/cli@v2.97.0...v2.98.0)

#### Security

A security vulnerability has been identified, and fixed, that binds the local forwarded port to all available network interfaces by default.

Users of `gh codespace ports forward` are advised to update `gh` to version `v2.98.0` as soon as possible.

For more information see: <GHSA-vfhh-p7hm-pxfh>

#### Support worktrees in `pr checkout`

Users can now checkout a pull request into a git worktree by using the new `--worktree PATH` flag in `gh pr checkout`:

```shell
gh pr checkout 12 --worktree ../wt-feature
```

#### Add semantic search to `search issues`

The `gh search issues` command now supports semantic search for issues. Users can select the search type by passing the `--search-type` flag:

```shell
gh search issues --search-type semantic ...

gh search issues --search-type hybrid ...
```

For more information about semantic search see: ["Improved Search for github issues is now generally available"](https://github.blog/changelog/2026-04-02-improved-search-for-github-issues-is-now-generally-available/).

#### What's Changed

##### ✨ Features

- Add --worktree flag to gh pr checkout by [@&#8203;tidy-dev](https://github.com/tidy-dev) in [#&#8203;13946](cli/cli#13946)
- Set GH\_EXTENSION=1 when gh invokes an extension by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14072](cli/cli#14072)
- Add --search-type flag for semantic and hybrid issue search by [@&#8203;michaeljacholke](https://github.com/michaeljacholke) in [#&#8203;14006](cli/cli#14006)

##### 🐛 Fixes

- Fix `RESTWithNext` error type, repairing `gh status` and attestation retries by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;13988](cli/cli#13988)
- Trim spaces when parsing X-Oauth-Scopes in `gh release create` by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14065](cli/cli#14065)
- Fix project item-add output for non-TTY by [@&#8203;zwick](https://github.com/zwick) in [#&#8203;14056](cli/cli#14056)

##### 📚 Docs & Chores

- Slim down dependabot triage comments by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14019](cli/cli#14019)
- Require explicit MR review ownership by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14028](cli/cli#14028)
- Collapse spam triage into the agentic issue-triage workflow by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14027](cli/cli#14027)
- Run Dependabot triage every hour by [@&#8203;sergiou87](https://github.com/sergiou87) in [#&#8203;14030](cli/cli#14030)
- Route deploy key requests through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;13989](cli/cli#13989)
- Route ssh key requests through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;13994](cli/cli#13994)
- Route gpg key requests through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;13997](cli/cli#13997)
- Route autolink requests through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14013](cli/cli#14013)
- Route extension requests through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14059](cli/cli#14059)
- Route release creation through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14062](cli/cli#14062)
- Tell agents to use the MR template in AGENTS.md by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14074](cli/cli#14074)
- Make Dependabot triage cheaper and more decisive by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14079](cli/cli#14079)
- Route release deletions through api.Client by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14077](cli/cli#14077)
- Give Dependabot triage a real reachability check by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14087](cli/cli#14087)
- Restore automatic spam issue closure by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14088](cli/cli#14088)
- Add a scheduled tech debt burndown skill by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14095](cli/cli#14095)
- Use reflect.Pointer instead of deprecated reflect.Ptr by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14098](cli/cli#14098)
- Clarify what belongs in the MR template's testing section by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14103](cli/cli#14103)
- Rename cli-code-reviewer skill to code-review by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;14116](cli/cli#14116)
- Add aw-actions group to dependabot configuration by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;14123](cli/cli#14123)
- Isolate tests from local machine's auth and git configuration by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;14128](cli/cli#14128)
- Don't ask for feature detection cleanup comments when not needed by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;14139](cli/cli#14139)
- Accept pre-release tags in deployment validation by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;14193](cli/cli#14193)
- ci: add temporary step to verify Linux repo signing keys by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;14202](cli/cli#14202)
- Revert "ci: add temporary step to verify Linux repo signing keys" by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;14203](cli/cli#14203)
- Fix issue triage action compatibility \[skip changelog] by [@&#8203;tidy-dev](https://github.com/tidy-dev) in [#&#8203;14207](cli/cli#14207)

##### :dependabot: Dependencies

- chore(deps): bump github.com/sigstore/sigstore-go from 1.2.2 to 1.3.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14047](cli/cli#14047)
- chore(deps): bump the codeql-actions group across 1 directory with 3 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14049](cli/cli#14049)
- chore(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14048](cli/cli#14048)
- chore(deps): bump github.com/google/go-containerregistry from 0.21.7 to 0.21.8 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14066](cli/cli#14066)
- chore(deps): bump actions/attest from 4.2.1 to 4.2.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14100](cli/cli#14100)
- chore(deps): bump azure/login from 3.0.0 to 3.0.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14101](cli/cli#14101)
- chore(deps): bump the codeql-actions group across 1 directory with 3 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14091](cli/cli#14091)
- chore(deps): bump github/gh-aw-actions/setup-cli from 0.83.4 to 0.85.4 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14068](cli/cli#14068)
- chore(deps): bump github.com/google/go-containerregistry from 0.21.8 to 0.21.9 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14119](cli/cli#14119)
- chore(deps): bump github.com/klauspost/compress from 1.19.1 to 1.19.2 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14120](cli/cli#14120)
- chore(deps): bump the aw-actions group with 2 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14147](cli/cli#14147)
- chore: sign APT repository with both keys by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;13271](cli/cli#13271)
- chore(deps): bump github.com/yuin/goldmark from 1.8.4 to 1.8.5 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14029](cli/cli#14029)
- chore(deps): bump actions/attest from 4.2.0 to 4.2.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14050](cli/cli#14050)
- Bump golangci-lint in CI to v2.12.2 by [@&#8203;williammartin](https://github.com/williammartin) in [#&#8203;14102](cli/cli#14102)
- chore(deps): bump the aw-actions group with 2 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14124](cli/cli#14124)
- chore(deps): bump google.golang.org/protobuf from 1.36.11 to 1.36.12 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14140](cli/cli#14140)
- Upgrade gh-aw workflows to v0.85.4 by [@&#8203;tidy-dev](https://github.com/tidy-dev) in [#&#8203;14141](cli/cli#14141)
- Bump Go to 1.26.6 by [@&#8203;github-actions](https://github.com/github-actions)\[bot] in [#&#8203;14143](cli/cli#14143)
- chore: bump go to 1.26.7 by [@&#8203;babakks](https://github.com/babakks) in [#&#8203;14205](cli/cli#14205)
- chore(deps): bump github.com/stretchr/testify from 1.11.1 to 1.12.1 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14204](cli/cli#14204)
- chore(deps): bump the codeql-actions group across 1 directory with 3 updates by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14169](cli/cli#14169)
- chore(deps): bump golang.org/x/crypto from 0.54.0 to 0.55.0 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14164](cli/cli#14164)
- chore(deps): bump charm.land/lipgloss/v2 from 2.0.5 to 2.0.6 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;14166](cli/cli#14166)
- Bump gh-aw-actions to v0.87.1 and recompile agentic workflows by [@&#8203;BagToad](https://github.com/BagToad) in [#&#8203;14210](cli/cli#14210)

#### New Contributors

- [@&#8203;sergiou87](https://github.com/sergiou87) made their first contribution in [#&#8203;14030](cli/cli#14030)
- [@&#8203;michaeljacholke](https://github.com/michaeljacholke) made their first contribution in [#&#8203;14006](cli/cli#14006)

**Full Changelog**: <cli/cli@v2.97.0...v2.98.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODguMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4OC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
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.

4 participants