Repository navigation
ci: add deterministic Helm chart publication - #46
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2f0eff6. Configure here.
|
|
||
| publish: | ||
| name: Publish immutable chart | ||
| if: inputs.publish |
There was a problem hiding this comment.
Manual runs always enter publish
High Severity
if: inputs.publish does not treat workflow_dispatch booleans as booleans. Unchecked publish arrives as the string false, which is truthy, so the publish job still starts and waits on the release environment even when the run was validation-only.
Reviewed by Cursor Bugbot for commit 2f0eff6. Configure here.
There was a problem hiding this comment.
Resolved by requiring the reusable-workflow boolean to equal true explicitly. Manual dispatch has no publication input and remains validation-only.
| go run "${REPO_ROOT}/.scripts/chart-artifact.go" verify-index "${index_dir}/index.yaml" \ | ||
| "${CHART_VERSION}" "${digest}" "${REPOSITORY_URL}/${ARTIFACT_NAME}" | ||
| gcloud storage cp "${index_dir}/index.yaml" "gs://${CHART_BUCKET}/index.yaml" \ | ||
| --if-generation-match="${index_generation}" --content-type=application/yaml |
There was a problem hiding this comment.
Index precondition uses a stale snapshot
Medium Severity
publish_chart downloads index.yaml over HTTP first, then later reads the GCS generation and uploads a merge of that earlier snapshot with --if-generation-match. A newer index written in between still matches the observed generation, so the upload can overwrite it and drop entries.
Reviewed by Cursor Bugbot for commit 2f0eff6. Configure here.
There was a problem hiding this comment.
Resolved. Publication now reads index.yaml directly from GCS at the exact generation later used by the upload precondition; it no longer merges a public HTTP snapshot. The integration fixture also exercises a concurrent generation change.


Summary
External configuration completed
Webhook-Relay-Operator-Chartreleaseenvironment with independent reviewer and tag/branch policygithub-operator-chartsservice accountValidation
go test ./.scriptsmake chart-release-test HELM_BIN=helmmake chart-package HELM_BIN=helmmake chart-release-check HELM_BIN=helmhelm lint/helm templatego test ./...Note
Medium Risk
Changes production chart delivery (GCS/index writes) and release automation; mitigations include gated publish, OIDC, immutability checks, and no overwrite of existing chart bytes.
Overview
Replaces Cloud Build and ad-hoc Helm packaging with a deterministic, collision-safe chart release pipeline on GitHub Actions.
A new reusable
Helm Chart Releaseworkflow packages the chart (Go-based reproducible.tgz, SHA-256, metadata), runs remote verification, uploads a candidate artifact, and optionally publishes togs://charts.webhookrelay.combehind the protectedreleaseenvironment using Workload Identity (no stored GCP keys). Publication uses generation preconditions on chart objects andindex.yaml, refuses byte-level overwrites of existing versions, and re-validates the published artifact and index.CI now runs
go test ./.scripts,make chart-package,chart-release-check, andchart-release-testalongside lint/render. Makefile exposes the same targets locally;.test/chart-release.shexercises retry and collision behavior against a local HTTP repo.Chart versions move to 0.7.0 (chart) / 0.8.0 (operator image defaults); e2e expects
webhookrelay-operator-0.7.0.tgz. Legacy scripts (repo_sync.sh,gen_packages.sh,cloudbuild.yaml, etc.) are removed.docs/releasing.mdand README/modernization-plan updates document immutable 0.5.0 / 0.6.0 charts and the maintainer release boundary.Reviewed by Cursor Bugbot for commit 2f0eff6. Configure here.