Skip to content

ci(helm-release): revive a workflow that has never once started (17/17 startup_failure) - #1098

Open
mdheller wants to merge 1 commit into
mainfrom
fix/helm-release-chart-releaser-blocked
Open

ci(helm-release): revive a workflow that has never once started (17/17 startup_failure)#1098
mdheller wants to merge 1 commit into
mainfrom
fix/helm-release-chart-releaser-blocked

Conversation

@mdheller

@mdheller mdheller commented Jul 30, 2026

Copy link
Copy Markdown
Member

All 17 runs of helm-release.yml (2026-06-23 → 2026-07-29) are startup_failure. It has never once succeeded — never once started. The run is rejected at creation, before any job exists, so there are no logs to point at the cause.

$ gh api .../workflows/helm-release.yml/runs --jq '.total_count, (…group_by(.conclusion))'
17
{"startup_failure":17}

Root cause

helm/chart-releaser-action@v1.6.0.

The repo sets allowed_actions: selected:

{"github_owned_allowed":true,"verified_allowed":true,
 "patterns_allowed":["dtolnay/*","Swatinem/*","oven-sh/*","tauri-apps/*"]}

The action is on the Marketplacehttps://github.com/marketplace/actions/helm-chart-releaser returns 200 — which is what makes this one easy to get wrong. But verified_allowed gates on the publisher's verified-creator badge, not on Marketplace presence, and the publisher helm has none. Fetching the listing finds zero Verified< markers, against 2 for azure/login. It is not github-owned and matches no pattern.

Isolated by elimination — every other action in the file demonstrably runs today:

action in helm-release.yml status evidence
actions/checkout@v4 allowed github-owned
azure/setup-helm@v4 allowed verified; deploy-tests.yml = 88 successes
google-github-actions/auth@v2 allowed verified; provision-secrets.yml succeeds
helm/chart-releaser-action@v1.6.0 blocked Marketplace 200, 0 Verified markers

The fix — option 1, for consistency

Replaced with a pinned, checksum-verified install of the cr binary (scripts/ci/install-chart-releaser.sh) plus the three cr calls the action wrapped (scripts/ci/release-charts.sh). This matches scripts/ci/install-opentofu.sh from #1090 / #1097 — same shape: committed sha256, hard refusal on an unpinned version, hard failure on checksum mismatch.

The committed checksums were verified by downloading both linux artifacts and recomputing:

834046b27b00cd6ba451326875c1937d4f2b671063c2053e031434ade73002b5  linux_amd64
03811896f65f73faffa63aa24f54ac4fed73e088418d0582723917b69c2a280b  linux_arm64

cr is pinned at v1.8.1 rather than the v1.6.0 the action defaulted to. There is no behaviour to preserve — the step has never executed once.

Option 2 — an admin adds helm/* to patterns_allowed — would also work. Not done deliberately: it is a settings change with no diff to review, and it was rejected for the OpenTofu case for that reason. Noting it so the choice reads as deliberate rather than overlooked.

Deliberate behaviour differences from the action

  • Every chart is packaged; cr upload --skip-existing drops the already-released ones. The action diffed charts against the latest tag. Same outcome, no dependence on tag history being intact, and re-running is a no-op rather than a failure.
  • gh-pages is bootstrapped if absent. cr index --push publishes via git worktree add --detach <dir> origin/gh-pages, so the branch must already exist. gh-pages does not exist in this repo (git ls-remote --heads origin gh-pages is empty), so even with the policy fixed the first run would have died on a prerequisite nobody is watching for. Creating it empty is the one-time manual setup chart-releaser documents; it is guarded by ls-remote, so it happens at most once.

Making the fix verifiable pre-merge

The workflow had no pull_request trigger at all — only push: branches:[main] and workflow_dispatch. A PR touching it could not run it. That is the same blind spot #1097 closed for tofu-plan.yml, and it is a large part of why 17 consecutive failures went unnoticed.

It now triggers on itself and on the two scripts, and splits into two jobs:

  • package — runs on pull_request, permissions: contents: read. Installs the pinned cr, packages every chart, publishes nothing.
  • releaseif: github.event_name != 'pull_request'. Cuts releases, pushes gh-pages, pushes OCI.

The policy check is whole-file at run creation, so a PR-time run that reaches its steps proves every uses: in the file is permitted — including google-github-actions/auth@v2, which only the skipped release job uses.

Verified locally before pushing:

behaviour result
valid version, real tarball downloads, checksum OK, installs
tampered committed sha256 FAILED / did NOT match, exit 1, nothing installed
CR_VERSION=9.9.9 refuses, prints the checksums.txt URL, exit 1
release-charts.sh --package-only packages all 4 charts, exit 0
missing CR_TOKEN refuses to publish

This is the third instance — and there is a fourth

infra-drift-detect (26 startup_failure), tofu-plan.yml (25), helm-release.yml (17). I enumerated every uses: across the repo — all 104 files in .github/workflows/, plus a whole-tree sweep confirming there are no composite actions (.github/actions/ is empty, no action.yml exists anywhere) — and checked each against the policy — github-owned, publisher verified-creator badge (fetched and counted, not assumed from Marketplace presence, which is exactly what fooled this case), or pattern match.

Blocked

action why workflows observed
helm/chart-releaser-action@v1.6.0 Marketplace 200, 0 Verified helm-release.yml 17/17 startup_failure
opentofu/setup-opentofu@v1, @9d84900f not Marketplace-listed (404) tofu-plan.yml, infra-drift-detect.yml 25 + 26 startup_failure
peter-evans/create-pull-request@v6 Marketplace 200, 0 Verified search-orchestrator-image-pin.yml 9/9 startup_failure since 2026-07-03

The fourth is search-orchestrator-image-pin.yml. It last succeeded 2026-04-26; every run from 2026-07-03 onward is a startup_failure. It is workflow_run-triggered off the image build, so it fires rarely and fails invisibly — the automated image-digest pinning it exists to do has not happened in nearly four months. Same root cause, same failure mode. Not fixed here — it needs its own PR, since create-pull-request has no one-line run: equivalent (likely gh pr create).

Allowed — verified, no action needed

azure/setup-helm@v4, azure/login, azure/setup-kubectl@v3, docker/login-action@v3, docker/setup-buildx-action@v3, docker/build-push-action@v5,v6, hashicorp/setup-terraform@v3, aws-actions/configure-aws-credentials, google-github-actions/auth@v2, google-github-actions/get-gke-credentials@v2 — all show 2 Verified< markers, and all but azure/login and aws-actions/* are independently confirmed by live successful runs. SocioProphet/.github/.github/workflows/build-image.yml@main is a same-org reusable workflow (images.yml, 68 successes). All actions/* are github-owned.

Worth noting: none of the four allowlisted patterns is used by any workflow in this repo. dtolnay/*, Swatinem/*, oven-sh/*, tauri-apps/* are Rust/Tauri patterns belonging to Noetica and BearBrowser. The pattern allowlist is dead weight here.

Recommendation: make this mechanical

Four workflows have now been silently dead for weeks to months on the same policy, and the failure mode is specifically one that produces nothing to read — no logs, no annotation, and a paths: filter that often means no PR can surface it either. Manual discovery does not scale.

A check should fail a PR when a workflow references an action the policy cannot run. Sketch:

  1. Read the live policy from GET /repos/{owner}/{repo}/actions/permissions/selected-actions.
  2. Parse every uses: under .github/workflows/.
  3. Allow: actions/* and github/* when github_owned_allowed; same-repo / same-org reusable workflows; anything matching patterns_allowed.
  4. Otherwise, when verified_allowed, resolve the action's Marketplace listing and require the verified-creator badge — not merely a 200. Fetching the listing and getting 200 is precisely what makes this bug look fine.
  5. Fail with the action, the workflow, and which of the three gates it missed.

Natural home: tools/check_workflow_path_filters.py, run by ci-path-filter-audit.yml. That workflow already triggers on .github/workflows/**, already parses every workflow file, and is already framed around exactly this doctrine — "a wrong promise is worse than no filter, because the validator stops running pre-merge and nobody notices." A policy-blocked action is the same failure with a harsher edge: the validator does not merely stop being asked, it is rejected outright. (The sibling scripts/verify_workflow_branches.py in socioprophet is the other candidate, but it is in the wrong repo and does not already read this repo's workflows.)

Step 4 needs a network call, which that tool deliberately does not make today — so it wants either a committed, reviewed allowlist of verified publishers or an --offline mode. That is a real design question, which is why it is not built in this PR. Proposing it here rather than bundling it.

Not touched

.cr-release-packages/ and .cr-index/ are runner-local build output and are not in .gitignore. Nothing commits from the main worktree — cr index --push operates in its own temp worktree — so this is cosmetic. Left alone to keep the diff inside helm-release.yml + scripts/ci/.

Verification status

See the first comment below for whether the package job actually reached its steps. A workflow that merely parses proves nothing here — the entire defect is rejection before startup.

🤖 Generated with Claude Code

All 17 runs of helm-release.yml (2026-06-23 -> 2026-07-29) are
`startup_failure`. The run is rejected at creation, before any job
starts, so there is nothing in the logs to point at the cause.

`helm/chart-releaser-action@v1.6.0` is the reason. This repo sets
`allowed_actions: selected` with github_owned_allowed + verified_allowed
+ patterns_allowed (dtolnay/*, Swatinem/*, oven-sh/*, tauri-apps/*). The
action is on the Marketplace, which is what makes this one easy to get
wrong -- but `verified_allowed` gates on the publisher's verified-creator
badge, and `helm` has none. Fetching the listing finds zero `Verified<`
markers, against 2 for azure/login. It matches no pattern either.

Isolated by elimination: every other action in the file demonstrably runs
today. azure/setup-helm@v4 succeeds in deploy-tests.yml (88 successes),
google-github-actions/auth@v2 in provision-secrets.yml, and actions/* are
github-owned.

Replaced with a pinned, checksum-verified install of the `cr` binary plus
the three `cr` calls the action wrapped, matching the direction already
taken for opentofu/setup-opentofu in #1090 and #1097. Adding `helm/*` to
patterns_allowed would also work, but that is a settings change with no
diff to review, and it was rejected for the OpenTofu case.

The workflow had no pull_request trigger, so a PR touching it could not
run it -- the same blind spot #1097 closed for tofu-plan.yml. It now
triggers on itself and on the scripts, and splits into two jobs: a
read-only `package` job that runs on pull_request, and the publishing
`release` job that does not. The policy check is whole-file at run
creation, so the PR-time run reaching its steps proves every `uses:` in
the file is permitted, including the one only the release job uses.

Verified locally: checksum mismatch and unknown version both fail hard
and install nothing; --package-only packages all four charts and exits 0;
a missing CR_TOKEN refuses to publish.
Copilot AI review requested due to automatic review settings July 30, 2026 04:31
@mdheller

Copy link
Copy Markdown
Member Author

Verification: the run is no longer rejected at creation

Total run count went 17 → 18, and run 18 was accepted.

The defect was rejection before startup, so the thing that had to be proven is admission, not a green tick. Here is the contrast:

17 historical runs this PR's run (30514099102)
conclusion startup_failure ×17 not startup_failure
created_at vs updated_at identical, to the second still open
jobs registered 0 1Package charts (no publish)
run 30430117995 (2026-07-29 startup_failure): jobs=0   created==updated==07:01:06Z
run 30403908784 (2026-07-28 startup_failure): jobs=0   created==updated==22:15:53Z

run 30514099102 (this PR, pull_request):      jobs=1   "Package charts (no publish)"

A startup_failure here terminated in the same second it was created and never built a job graph at all. This run survived admission and registered its job. That is the fix working: the actions policy no longer rejects the file. And because the policy check is whole-file at run creation, this also clears google-github-actions/auth@v2 in the release job, which never executes on a PR.

It also confirms the trigger change did its job — before this PR the workflow had no pull_request trigger, so no PR could have produced this run at all.

What is not yet verified

Whether the steps pass. The run is sitting in a deep queue — 343 queued, 5 in progress repo-wide at the time of writing. It is ubuntu-latest, so it does not need the (absent) self-hosted runners and will drain eventually, but I am not going to claim a green run I have not seen.

Specifically still unproven end-to-end on a real runner:

  • scripts/ci/install-chart-releaser.sh downloading and checksumming the linux/amd64 artifact. Locally I could only exercise linux/arm64 (this is an arm64 Mac) with a sha256sumshasum shim; the amd64 checksum was verified by downloading the artifact and recomputing, but not by running the script on amd64.
  • cr package under the runner's environment. Locally it packaged all 4 charts with the darwin build of cr v1.8.1.

Not exercised by this PR at all, and only reachable on main after merge:

  • cr upload / cr index --push, and the gh-pages bootstrap. The release job is if: github.event_name != 'pull_request' by design — a PR must not cut releases. Note gh-pages does not exist yet, so the bootstrap path will run on first merge to main.

I will not infer success from valid YAML. The admission claim above is evidenced; the step-level claim is not, yet.

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

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Revives the helm-release.yml workflow by removing a GitHub Actions policy-blocked third-party action and replacing it with pinned, checksum-verified installation plus local scripts so the workflow can actually start and be validated on PRs.

Changes:

  • Replace helm/chart-releaser-action with scripts/ci/install-chart-releaser.sh (pinned + sha256-verified) and scripts/ci/release-charts.sh.
  • Split workflow into a PR-safe package job and a gated release job, and add pull_request triggers for workflow/script changes.
  • Bootstrap gh-pages on first publish so initial releases don’t fail on a missing branch.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
scripts/ci/release-charts.sh Implements packaging + publishing logic previously wrapped by the blocked action, including gh-pages bootstrap.
scripts/ci/install-chart-releaser.sh Installs cr from upstream releases with pinned version + committed checksums.
.github/workflows/helm-release.yml Adds PR trigger + a read-only packaging job; switches publish job to run the new scripts.

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

Comment on lines +66 to +75
echo "Branch '${PAGES_BRANCH}' does not exist yet; creating it with an empty index."
wt="$(mktemp -d)/${PAGES_BRANCH}"
git worktree add --detach "$wt"
git -C "$wt" checkout --orphan "$PAGES_BRANCH"
git -C "$wt" rm -rq --cached . || true
find "$wt" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
: > "$wt/index.yaml"
git -C "$wt" add index.yaml
git -C "$wt" commit -m "chore(charts): initialise Helm chart repository index"
git -C "$wt" push origin "$PAGES_BRANCH"
Comment on lines +89 to +96
cr index \
--owner "$OWNER" \
--git-repo "$REPO" \
--package-path "$PKG_DIR" \
--pages-branch "$PAGES_BRANCH" \
--index-path .cr-index/index.yaml \
--token "$CR_TOKEN" \
--push
Comment on lines +57 to +58
tar -xzf "${TMP}/${TGZ}" -C "$TMP" cr
install -m 0755 "${TMP}/cr" "${DEST}/cr"
steps:
- uses: actions/checkout@v4

- uses: azure/setup-helm@v4
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