Skip to content

fix(ci): verify-index must read the authoritative index, not the raw CDN - #497

Merged
LukasWodka merged 2 commits into
developfrom
fix/verify-index-authoritative-read
Jul 30, 2026
Merged

fix(ci): verify-index must read the authoritative index, not the raw CDN#497
LukasWodka merged 2 commits into
developfrom
fix/verify-index-authoritative-read

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Bugbot flagged this on the staging -> main promotion (client#495) and it's a fair hit on a guard I added yesterday in #467 — the finding is that the guard can pass while the thing it guards is already broken.

The problem

verify-index ran:

curl -fsSL "https://raw.githubusercontent.com/$GITHUB_REPOSITORY/gh-pages/index.yaml?nocache=$GITHUB_RUN_ID"

raw.githubusercontent.com is CDN-fronted and serves a stale copy for some time after a gh-pages push, and a ?nocache= query parameter does not reliably bust it. This job runs seconds after the release job may have pushed, so it could read a pre-push index, see no prerelease versions, and go green while the customer-facing index was already polluted — precisely the leak it was written to catch (the 1.9.7-rc published-as-stable incident).

The fix

Read the blob through the contents API at ?ref=gh-pages, which is read-after-write consistent for a ref rather than CDN-cached:

idx=$(gh api "repos/$GITHUB_REPOSITORY/contents/index.yaml?ref=gh-pages" \
        -H "Accept: application/vnd.github.raw+json")

Plus an explicit empty-read guard: an unreadable index now fails the job instead of letting the invariant checks trivially "hold" against no data. That is the same failure shape as the empty-index commit I made during the gh-pages surgery — a critical read that silently returns nothing must never look like success.

Adds a job-scoped permissions: contents: read.

Verification

  • actionlint + shellcheck at CI-pinned versions: 6 findings before, 6 after — my change adds none (all six are pre-existing, in unrelated steps).
  • Exercised the new read against the live repo: the API returns the index with 36 chart versions and 0 prerelease-shaped entries, matching the current CDN copy (they agree when there has been no recent push — the divergence only appears in the window this job actually runs in).

Note on the promotion

client was correctly held out of today's prod hop by this finding. It should stay held until the 1.9.8 chart bump reaches staging: promoting now would put 17 commits of chart changes on main while Chart.yaml still reads 1.9.7, so main would no longer match the published 1.9.7 artifact. With this fix plus the bump on staging, the next prod hop promotes and cuts v1.9.8 with content that matches its version.


Note

Low Risk
CI-only change to a release guard; no runtime or customer install path behavior changes beyond making the backstop read the current index.

Overview
The post-publish verify-index job no longer fetches index.yaml from raw.githubusercontent.com (CDN can lag right after gh-pages pushes, so checks could pass on a stale file while the public index was already wrong). It now loads the blob with gh api on contents/index.yaml?ref=gh-pages, which is treated as authoritative for that ref.

The job also fails if the read is empty instead of running invariant grep on no data, and grants contents: read for that API call. Workflow error annotations stay on stdout so Actions surfaces them reliably.

Reviewed by Cursor Bugbot for commit 0b1bf13. Bugbot is set up for automated code reviews on this repo. Configure here.

verify-index fetched index.yaml from raw.githubusercontent.com seconds
after the release job may have pushed gh-pages. raw.* is CDN-fronted and
serves a stale copy for a while after a push, and ?nocache= does not
reliably bust it -- so the job could read a clean index while the
customer-facing one was already polluted, greening the exact backstop it
exists to be.

Now read through the contents API at ?ref=gh-pages, which is
read-after-write consistent for a ref, and fail loudly on an empty read
rather than reporting the invariants as holding on no data.

Found by Bugbot on the staging->main promotion (client#495).
@LukasWodka
LukasWodka requested a review from saadqbal as a code owner July 30, 2026 12:45
@LukasWodka LukasWodka self-assigned this Jul 30, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

@LukasWodka

Copy link
Copy Markdown
Contributor Author

👋 Heads-up — Code review queue is at 34 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c60167a. Configure here.

Comment thread .github/workflows/release-helm-chart.yaml Outdated
Actions parses workflow commands from stdout only, so an ::error:: sent to
stderr fails the step with no annotation. Every sibling ::error:: in this
file already uses stdout (Bugbot, client#497).
@LukasWodka
LukasWodka merged commit 3849690 into develop Jul 30, 2026
9 checks passed
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.

3 participants