Repository navigation
fix(cloud-environment): install gh from the pinned upstream release asset - #533
Conversation
…sset Cloud sessions installed `gh` with `apt-get install -y gh`, which pulls whatever Ubuntu's archive ships: 2.45.0, observed live in a cloud session and 53 minor versions behind the two lanes that pin explicitly — the CI runner image (ci-runner's Dockerfile, GH_VERSION 2.98.0) and local dev machines (dotfiles, mise, 2.98.0). Scripts and hooks that shell out to `gh` therefore ran against a different CLI depending on where they ran. Install the same checksummed release asset the runner image does: `gh_2.98.0_linux_amd64.tar.gz` from `github.com/cli/cli/releases`, verified against the SHA-256 ci-runner pins, extracted to `/usr/local/bin`, tarball removed. amd64-only for the same reason the runner image is: the pinned hash covers that one asset. The step keeps the script's best-effort contract — every failure path logs a WARN and the build still exits 0. The comment the apt install carried named `cli.github.com`, the upstream apt repo, as the blocker. That is still true and still avoided: this fetches a release asset from `github.com`, which is on the default allowlist, not an apt repo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPLatLkg4329L8eyfxhuMa
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 3m 53s —— View job Code review complete
SummaryThe change is well-scoped and does what the PR body says: One finding, posted inline on
Everything else checked out:
I wasn't able to execute |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
The gh install switched from apt to a pinned release tarball, so the apt-get update -y that used to prep the archive indices for it has no consumer left in Track A. PowerShell's install already runs its own apt-get update -y after adding the Microsoft repo, which is the one that actually needs to see fresh indices. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPLatLkg4329L8eyfxhuMa
Lane claim —
|
Lane release —
|
| Commit | Author | GitHub user | Signature |
|---|---|---|---|
7537a4dc |
Claude <ksextonloops@outlook.com> |
none — unattributed | unverified (reason=no_user) |
56492969 |
Claude <noreply@anthropic.com> |
claude |
verified |
Org ruleset 17988999 sets require_extra_approval_for_unattributed_changes: true; ruleset 17989003 sets required_signatures. There are zero approving reviews (both reviews are COMMENTED).
Control check — every recently merged PR here (#525, #528, #530, #531, #532) merged with zero approving reviews and with every commit attributed to kyle-sexton and verified. So zero approvals is normal on this base and is not the hold; the unattributed, unverified 7537a4dc is.
Why the lane cannot clear it
Both remedies are outside this lane's authority:
- Re-authoring and re-signing
7537a4dcrequires a force-push, forbidden by a cross-tier invariant in every tier including autopilot. - Manufacturing the extra approval is not available either: GitHub does not permit self-approval, and the PR author is the lane identity.
Branch freshness was assessed and deliberately left alone: diverged, ahead 2 / behind 7, but strict_required_status_checks_policy: false on this base, so being behind is not the hold. Refreshing would re-run 43 lanes without touching the actual blocker.
Incidental: the pin in this PR re-validated independently
Downloaded gh_2.98.0_linux_amd64.tar.gz fresh in this session; sha256sum returns 3b8ac6b30336802fc1a858d7c084e11cdf24ac1a761ca90b68022d7d729208de, matching this PR's GH_SHA256 and ci-runner's ARG GH_SHA256 exactly, and the extracted binary reports gh version 2.98.0 (2026-08-20). The residual 403 risk the PR body flags for cli/cli release assets did not materialize from this fleet.
Operator action required
One of:
- Force-push
fix/cloud-gh-version-paritywith7537a4dcre-authored to an attributed identity and signed with a key linked to that account, or - Submit an approving review from a second identity to satisfy
require_extra_approval_for_unattributed_changes.
Either clears the last hold; nothing else on this PR is outstanding.
Generated by Claude Code
Resolve the only conflict against main (SCRIPT_VERSION) so the pinned upstream gh install lands on top of the fleet plugin list and later setup.sh work, without regressing SCRIPT_VERSION behind 2026-09-06.2. Co-authored-by: ksextonmelodic <ksextonmelodic@gmail.com>
|
Merged The Claude review finding on the leftover Waiting on |
…n floor (#3772) No related issue: infrastructure parity found during PR-merge-lane operation. ## Summary The org runs `gh` in three lanes. Two pin it; one did not. | Lane | Source | Version | | --- | --- | --- | | Local dev machines | `melodic-software/dotfiles` → mise | 2.98.0 | | Self-hosted CI runner | `melodic-software/ci-runner` `Dockerfile` | 2.98.0 | | Claude Code cloud sessions | standards `components/cloud-environment/setup.sh`, `apt-get install -y gh` | **2.45.0** | A live cloud session on this fleet reports `gh version 2.45.0 (2025-07-18 Ubuntu 2.45.0-1ubuntu0.3)` — 53 minor versions behind the other two lanes. The several `source-control`, `guardrails`, and `work-items` suites that shell out to `gh` were running against a different CLI depending on where they ran. The fix belongs upstream and is in [melodic-software/standards#533](melodic-software/standards#533), which replaces the apt install with the pinned, checksum-verified `linux_amd64` release tarball at 2.98.0. This PR is the docs half: this guide is where the fleet's install method and its verification checklist are written down, and both had gone stale. Worth naming the second-order finding: step 1 of the verification checklist ran `gh --version` and asserted nothing about the number it printed, so the drift passed verification every single time it was run. A presence check on a tool whose *version* is the thing under contract cannot detect the failure it exists to detect. ## Fix Two edits to `docs/CLOUD-FLEET-SETUP.md`: - **"What the canonical script does"** — `gh` is no longer described as an apt install. It now names the pinned, checksum-verified `linux_amd64` release tarball from `github.com/cli/cli`, at the same version and SHA-256 the CI runner image and dotfiles' mise pin carry, and says why (Ubuntu's archive `gh` is years stale). PowerShell is still apt and still described that way. - **Verification checklist, step 1** — `gh --version` gets a floor instead of a presence check: expect **2.98.0 or newer**, matching the other two lanes. The step also says what a `2.45.x` reading means (the pinned-tarball step failed and the session fell back to Ubuntu's archive `gh`), and where to look for the cause (`grep gh /var/log/melodic-env-setup.log` for the `WARN` line the standards script logs on every failure path). The rest of step 1 — `pwsh`, `dotnet --list-sdks`, `node --version`, `check-tools` — is unchanged. No behavior change here; the install itself lives in standards. ## Verification - `scripts/affected-tests.sh --run docs/CLOUD-FLEET-SETUP.md`: the file is a recorded no-suite class in `scripts/affected-tests-no-suite.txt` (a non-shell CI lane covers it); exit 0, no suites selected. - `markdownlint-cli2 --config .markdownlint-cli2.jsonc docs/CLOUD-FLEET-SETUP.md`: 0 issues. - The 2.98.0 floor is not asserted from memory. Downloaded `https://github.com/cli/cli/releases/download/v2.98.0/gh_2.98.0_linux_amd64.tar.gz` from a live cloud session: `sha256sum` returns `3b8ac6b30336802fc1a858d7c084e11cdf24ac1a761ca90b68022d7d729208de`, matching `ci-runner`'s `ARG GH_SHA256` exactly, and the extracted binary reports `gh version 2.98.0 (2026-08-20)`. The same session's PATH `gh` reports 2.45.0 — the drift this documents, observed directly rather than inferred. Sequencing: the standards PR should merge first, and the environment needs a cache rebuild (any trivial edit to the setup-script field) before a session picks up the new `gh`. Until then a session will still read 2.45.0 and step 1 will correctly fail — which is the point of adding the floor. ## Related - [melodic-software/standards#533](melodic-software/standards#533) — the install change this documents. - `melodic-software/ci-runner` `Dockerfile` — `ARG GH_VERSION` / `ARG GH_SHA256`, the pinned pair both lanes now share. - `melodic-software/dotfiles` `.chezmoidata/packages.yaml` and `dot_config/mise/create_mise.lock` — the local-machine lane at the same version. - [#2654](#2654) — the cloud-environment blockers whose network findings the standards change reuses. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01VPLatLkg4329L8eyfxhuMa --- _Generated by [Claude Code](https://claude.ai/code/session_01VPLatLkg4329L8eyfxhuMa)_ --------- Co-authored-by: Claude <ksextonloops@outlook.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
No related issue: infrastructure parity found during PR-merge-lane operation.
Summary
The org runs
ghin three lanes, and only two of them pin it:melodic-software/dotfiles→ mise (dot_config/mise/create_mise.lock)melodic-software/ci-runnerDockerfile(ARG GH_VERSION/ARG GH_SHA256)setup.sh,apt-get install -y ghapt-get install -y ghtakes whatever Ubuntu's archive ships. In a live cloudsession on this fleet that is
gh version 2.45.0 (2025-07-18 Ubuntu 2.45.0-1ubuntu0.3)— 53 minor versions behind the other two lanes. Everyscript and hook that shells out to
ghtherefore ran against a different CLIdepending on where it ran, and a cloud session was the one place that gap was
invisible.
The comment the apt install carried named
cli.github.com, the newer upstreamapt repo, as the reason: it is not on the platform's default allowlist. That is
still true, and this change does not touch it — a release asset from
github.comis not an apt repo, andgithub.comis on the default allowlist.Fix
components/cloud-environment/setup.shnow installs the same checksummedrelease asset the CI runner image does, in the same style:
GH_VERSION/GH_SHA256declared next to the other fleet pins, with acomment naming the two lanes they must stay in lockstep with.
curl --fail --location --proto '=https' --tlsv1.2forgh_2.98.0_linux_amd64.tar.gz,sha256sum --check --strictagainst the pin,tar --strip-components=2ofgh_2.98.0_linux_amd64/bin/ghinto/usr/local/bin(where the script already symlinksdotnet),chmod 0755,then the tarball removed — inline and again in the script's end-of-run temp
sweep.
ci-runner's Dockerfile: the pin is the hash of thatone asset, and a non-
x86_64VM takes a loggedWARNskip rather than anunverified download.
a
WARNline to the track log, no step is fail-closed, and the script stillexits 0.
SCRIPT_VERSIONbumped to2026-09-05.1so the completion stampidentifies the new build.
README.mdgains a "Theghpin" section (why not apt, the three-lanelockstep, the amd64 and best-effort caveats) and an update-lifecycle bullet
noting that, unlike .NET and Node,
ghis not a warm cache — no repobootstrap reinstalls it, so this script is the only thing holding cloud
sessions at the fleet version.
setup.test.shgains six assertions: noapt-get install -y gh(regressionguard),
GH_VERSIONdeclared,GH_SHA256declared as 64 hex characters, thefetch URL is the pinned
cli/clirelease asset, the asset is checksum-verifiedbefore install, and the README documents the same version the script installs.
Verification
shellcheck --rcfile .shellcheckrconsetup.shandsetup.test.sh: clean.bash harness/shell/run-tests.sh components/cloud-environment/setup.test.sh components/cloud-bootstrap/cloud-bootstrap.test.sh: 2 passed, 0 failed, 0skipped — 17 assertions, including the 6 new ones.
npm run lint:md: 0 issues in 122 files.shfmt -d,typos,editorconfig-checker: clean. The full lefthookpre-commit set (editorconfig, typos, markdownlint, shellcheck, gitleaks) ran
green on the commit.
https://github.com/cli/cli/releases/download/v2.98.0/gh_2.98.0_linux_amd64.tar.gzfrom a live cloud session:
sha256sumreturns3b8ac6b30336802fc1a858d7c084e11cdf24ac1a761ca90b68022d7d729208de, matchingci-runner'sARG GH_SHA256exactly, and the extracted binary reportsgh version 2.98.0 (2026-08-20).Network risk, checked rather than guessed
The blocker the old comment named is about
cli.github.com's apt repo, notabout raw release downloads, so it does not apply here. Two independent pieces
of evidence say the raw download works in this execution context:
(
.claude/cloud-bootstrap.shinclaude-code-plugins) already fetchesshellcheck, actionlint, typos, editorconfig-checker, gitleaks, and shfmt
from
/releases/download/URLs with pinned SHA-256s, and has done so frominside the cache build.
The residual risk is narrow and worth stating: the GitHub proxy's repository
scope can return
403for release assets from repositories not attached to asession, and that applies at every network access level.
cli/cliis not anattached repository. If a future cache build hits that, the step logs
WARN gh 2.98.0 download failed, the build still exits 0, and the verificationchecklist catches the missing binary — the same failure mode the apt install
already had, minus the silent wrong version. Both the script header and the
README record this so the next reader does not have to re-derive it.
Related
melodic-software/ci-runnerDockerfile— theARG GH_VERSION/ARG GH_SHA256pair this change matches.melodic-software/dotfiles.chezmoidata/packages.yamlanddot_config/mise/create_mise.lock— the local-machine lane at the sameversion.
melodic-software/claude-code-pluginsdocs/CLOUD-FLEET-SETUP.md— thefleet guide's install description and verification checklist are updated in a
companion PR to match this install method and to assert a minimum
ghversion instead of mere presence.
melodic-software/claude-code-plugins#2654— the cloud-environment blockerswhose network findings this change reuses.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VPLatLkg4329L8eyfxhuMa
Generated by Claude Code