Skip to content

chore(uv): install gh CLI from apt repository instead of downloading#164

Merged
nozaq merged 4 commits into
mainfrom
claude/uv-image-gh-cli-setup-oxxgxt
Jul 13, 2026
Merged

chore(uv): install gh CLI from apt repository instead of downloading#164
nozaq merged 4 commits into
mainfrom
claude/uv-image-gh-cli-setup-oxxgxt

Conversation

@nozaq

@nozaq nozaq commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Refactors the uv Dockerfile to install the gh CLI from GitHub's official apt repository rather than downloading and verifying a release tarball. This simplifies the build process and reduces the number of downloads required.

Key Changes

  • Added a new RUN stage that installs gh from GitHub's official apt repository using the committed githubcli-archive-keyring.gpg keyring
  • Removed the manual download, checksum verification, and extraction of the gh release tarball from the main RUN stage
  • Simplified architecture variable assignments by removing the now-unused GH_ARCH variable
  • Updated the gh invocation to use the system-installed binary instead of the temporary extracted binary
  • Added githubcli-archive-keyring.gpg to the build-checks workflow triggers to ensure rebuilds when the keyring is updated
  • Added automation in the update-keys workflow to keep the GitHub CLI apt repository keyring in sync
  • Updated the README to document that gh is installed from GitHub's official apt repository and that the keyring is maintained by the update-keys workflow

Implementation Details

  • The GitHub CLI apt repository keyring is mounted as a read-only bind mount during the apt installation stage
  • The keyring file is committed to the repository and automatically synced by the update-keys workflow, similar to other repository keyrings
  • This approach reduces build complexity by leveraging the system package manager instead of manual binary management

https://claude.ai/code/session_01EZ4MfLxpAmfPHDfvBiPQ1B

Replace the direct tarball download of gh in the builder stage with an
apt install from https://cli.github.com/packages, pinned to GH_VERSION.
The repository signing keyring is bind-mounted from
uv/githubcli-archive-keyring.gpg, which is committed to this repo and
kept in sync by the update-keys workflow.

Note: uv/githubcli-archive-keyring.gpg itself is added separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ4MfLxpAmfPHDfvBiPQ1B
GH_VERSION now pins a package version installed from GitHub's apt
repository, not a GitHub release tag, so Renovate should track versions
actually published there (datasource=deb) rather than github-releases,
avoiding a mismatch if a release lags its apt package.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ4MfLxpAmfPHDfvBiPQ1B
nozaq and others added 2 commits July 13, 2026 20:40
Renovate's deb datasource treats binaryArch as a single value used
verbatim in the Packages path (binary-<arch>), unlike components which
does support a comma-separated list. amd64,arm64 would have produced an
invalid binary-amd64,arm64 path; amd64 alone is sufficient since gh's
apt package version is identical across architectures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZ4MfLxpAmfPHDfvBiPQ1B
@nozaq nozaq merged commit 4f6b1e9 into main Jul 13, 2026
164 checks passed
@nozaq nozaq deleted the claude/uv-image-gh-cli-setup-oxxgxt branch July 13, 2026 20:55
nozaq pushed a commit that referenced this pull request Jul 13, 2026
rustup publishes no signature for rustup-init, so it had no independent
trust anchor — the checksum file was fetched from the same channel as
the binary. Commit the expected per-architecture SHA-256 values to
rust/build.yaml and verify downloads against those instead: each
checksum is fetched once per version from the official channel, then
frozen in git and reviewed like any other change.

A new update-checksums workflow keeps the pin in sync: when Renovate
bumps RUSTUP_VERSION, the pull_request run re-derives the checksums
from rustup's official rustup-init.sha256 files (not by downloading and
hashing the artifact — same trust boundary, less bandwidth) and pushes
a fix-up commit to the update branch (converging on the second run);
scheduled runs open a housekeeper PR on drift, which would also surface
an upstream artifact changing content for an unchanged version.

Scoped to rust only: uv's gh CLI, which previously used the same
checksum-pinning approach to bootstrap attestation verification, now
installs from GitHub's official apt repository with GPG-keyring
verification instead (#164), which needs no such workaround.

Verified the rustup-init extraction against the live checksum files for
both architectures; the values match what's pinned in rust/build.yaml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rt6cdQY4Q3ie1xpMgyy33S
nozaq pushed a commit that referenced this pull request Jul 13, 2026
The rust Dockerfile gained required build args (pinned rustup-init
checksums) that sandbox-rust did not pass, which would break
devcontainer checks. Add them, refresh the stale UV_VERSION/
MISE_VERSION pins found along the way (these weren't actually
Renovate-managed — renovate.jsonc's devcontainer.json regex manager
only matches @-suffixed values, so plain version args like these were
silently drifting; worth a separate follow-up), and update
update-checksums.yml to also keep sandbox-rust's checksums in sync
with rust/build.yaml.

sandbox-uv no longer needs a GH_SHA256/checksum workaround: gh is now
installed from GitHub's official apt repository with GPG-keyring
verification (#164), so its GH_VERSION annotation is updated to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rt6cdQY4Q3ie1xpMgyy33S
nozaq pushed a commit that referenced this pull request Jul 13, 2026
sandbox-uv's UV_VERSION and sandbox-mise's MISE_VERSION had drifted
from their images' build.yaml (these plain version args aren't
Renovate-managed — renovate.jsonc's devcontainer.json regex manager
only matches @-suffixed values, so they were silently going stale;
worth a separate follow-up). Refresh both, and update sandbox-uv's
GH_VERSION renovate annotation to match #164's new datasource=deb
tracking now that gh installs from GitHub's apt repository.

sandbox-rust needs no changes: rust/Dockerfile now verifies rustup-init
against a checksum file committed directly under rust/ (bind-mounted
from the build context) rather than a build arg, so sandbox-rust's
existing DEBIAN_TAG/RUSTUP_VERSION args are already sufficient — no
per-devcontainer duplication needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rt6cdQY4Q3ie1xpMgyy33S
nozaq pushed a commit that referenced this pull request Jul 13, 2026
sandbox-uv's UV_VERSION and sandbox-mise's MISE_VERSION had drifted
from their images' build.yaml (these plain version args aren't
Renovate-managed — renovate.jsonc's devcontainer.json regex manager
only matches @-suffixed values, so they were silently going stale;
worth a separate follow-up). Refresh both, and update sandbox-uv's
GH_VERSION renovate annotation to match #164's new datasource=deb
tracking now that gh installs from GitHub's apt repository.

sandbox-rust needs no changes: rust/Dockerfile now verifies rustup-init
against a checksum file committed directly under rust/ (bind-mounted
from the build context) rather than a build arg, so sandbox-rust's
existing DEBIAN_TAG/RUSTUP_VERSION args are already sufficient — no
per-devcontainer duplication needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rt6cdQY4Q3ie1xpMgyy33S
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.

2 participants