Repository navigation
fix(helm): check the index against tags, retry tagging and keep charts independent - #65
Merged
tim-thacker-nullify merged 2 commits intoSep 15, 2026
Conversation
…hen publishing - Refuse to build when a <chart>-v<version> tag (or legacy collector tag v0.2.0) has no version in the fetched index; recover those versions from their GitHub release assets only with HELM_REPO_RECOVER_FROM_RELEASES=true, digest-checked against the asset's recorded sha256. - Fetch index.yaml with a cache-busting query and Cache-Control: no-cache. - Write release.txt with every chart version at HEAD the site serves, so tagging no longer depends on the version being new to the live index. - Skip a chart that fails its tests or changes an already-published version, with an ::error:: annotation and skipped.txt, instead of failing every chart; PUBLISH_STRICT=true keeps the hard failure for per-chart validation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… per chart - release runs only on refs/heads/main in the github-pages environment; dispatches from other refs run the dry run instead. - Workflow-level concurrency no longer groups non-PR runs; release uses its own pages group with cancel-in-progress false. - release runs when a single chart's validate leg fails; the publish script re-tests each chart and skips only the failing one, and the job still fails at the end listing skipped charts. - validate checks that a chart's published version is unchanged or bumped. - Tagging creates any missing tag, release or release asset for every published chart version at HEAD, so a re-run after a failed tag step finishes the job. - workflow_dispatch input recover_from_releases. - Pin every action by commit SHA; pass matrix.chart through env. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Sep 14, 2026
Closed
tim-thacker-nullify
merged commit Sep 15, 2026
41e78ca
into
fix/helm-publish-every-version
4 checks passed
Member
Author
tim-thacker-nullify
added a commit
that referenced
this pull request
Sep 17, 2026
…nning (#61) * feat(helm): add nullify-k8s-readonly-access chart for managed EKS scanning New chart nullify-k8s-readonly-access 0.1.0: a ClusterRole with list only on the 26 kinds the managed EKS scanner lists, bound to a Group (default nullify-readonly). Renders fail for an empty or system: group and for non-read extraRules verbs. grantSecretsRead and grantConfigMapsRead default to true because the strict scanner fails the cluster without them today. manifests/nullify-readonly-rbac.yaml is the default render without Helm's bookkeeping labels, and a CI job diffs the two. The chart README covers Helm, Flux and kubectl installs, impersonation-based verification, and why AmazonEKSAdminViewPolicy and AmazonEKSViewPolicy are not the recommended path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci(helm): fail the RBAC manifest check when either side normalises to nothing Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): reject system subjects of every kind and non-read-only extra rules - extraSubjects: any name starting "system:" (trimmed, case-insensitive) fails whatever its kind; kinds are limited to User, Group and ServiceAccount; ServiceAccounts in kube-system, kube-public and kube-node-lease fail. - extraRules: reject wildcard apiGroups or resources, the exec, attach, portforward, proxy and log subresources, and nonResourceURLs other than /version. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): grant get on /version to the managed scan's read-only role The strict managed scan records a ServerVersion() failure and fails the cluster, so a cluster without the default system:public-info-viewer binding could not be scanned. The raw manifest carries the same rule, and the manifest check fails if either side drops it. NOTES lists the egress IPs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(helm): correct Helm adoption, list egress IPs and drop the collector Namespace - Helm 3.2+ adopts the manifest's objects once they carry Helm ownership metadata, so moving to Helm no longer needs a delete and a scan outage. - List Nullify egress IPs per region for the EKS public endpoint. - The collector no longer creates a Namespace (#63). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci(helm): gate publishing the readonly-access chart on the RBAC manifest check helm-charts/nullify-k8s-readonly-access/ci/pre-publish.sh runs scripts/check-rbac-manifest.sh. The #65 follow-up's publish script runs a chart's pre-publish hook before packaging it and skips the chart when the hook fails, so manifest drift blocks the release and its tag whatever the release job's needs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): allow only status and scale subresources and render the trimmed group - extraRules resources: any subresource other than status and scale is rejected, so CRD subresources such as KubeVirt's virtualmachineinstances/console and /vnc/screenshot no longer render. New must-fail cases cover both. - The ClusterRoleBinding subject and NOTES use the trimmed groupName the guard checks, not the raw value. - The Helm adoption steps take the release name and storage namespace as variables, with the Flux HelmRelease values (flux-system unless storageNamespace is set) alongside the Helm CLI ones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): keep ci/ out of the readonly-access chart package - .helmignore excludes ci/, so editing the pre-publish hook or a CI values file no longer changes the packaged contents of a published version (which forced a version bump) and the hook script is not shipped to users. - scripts/test-helm-charts.sh reads ci/*.yaml from the chart directory, so lint and render coverage is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): grant list on batch/jobs in the readonly access chart The managed EKS scan now lists Jobs to attribute CronJob-run pods to their CronJob. Without the grant the list is skipped and those pods key on the Job. - ClusterRole and the rendered manifest gain a batch/jobs list rule (kept identical, as check-rbac-manifest.sh requires). - README kinds table and verify loop include jobs; note that a denied Jobs list is skipped rather than failing the scan. - values.yaml extraRules example uses cronjobs, since jobs is now granted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(helm): state 27 kinds for the readonly access grant - Manifest header, chart README and root README said 26 kinds; batch/jobs makes it 27. CI's manifest check ignores comments, so it did not catch the header. - ci/customised.yaml extraRules adds only cronjobs; jobs is now a default grant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(helm): list-only extraRules and binding seatbelts Co-authored-by: Cursor <cursoragent@cursor.com> * test(helm): reject aggregate-to-view/edit/admin labels Co-authored-by: Cursor <cursoragent@cursor.com> * fix(helm): never grant list on secrets list returns Secret values, so the chart rejects grantSecretsRead and extraRules that name secrets. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(helm): document Table-API secrets and drop the cross-chart release gate The managed scan stores name, type, key count and age, and collectSecrets already exists, so the chart must not claim values leak or that the option is unshipped. Release stays per-chart via the pre-publish hook. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The #60 publisher trusts whatever index it fetches, cannot retry tagging, and lets one chart block all charts. Stacked on #60.
Merge order: this into #60, then #60 before #58, #59 and #63. Any of those merging first runs the old workflow and unpublishes collector 0.2.0 (F60-1). Backup:
nullify-k8s-collector-0.2.0.tgzis attached to releasev0.2.0(sha25619feed16…, same as the live index).<chart>-v<version>tag or legacyv0.2.0is missing from the fetched index.recover_from_releases=trueto restore those versions from their release assets, checked against the asset sha256 andChart.yaml.?run=$GITHUB_RUN_IDandCache-Control: no-cache.release.txt(every served version at HEAD) and creates any missing tag, release or asset, so a re-run completes it.::error::,skipped.txt); others publish, thenreleasefails.validatefails only that chart's leg.releaseonly onrefs/heads/main, inenvironment: github-pages; other refs get the dry run.releasehas its ownpagesgroup,cancel-in-progress: false. GitHub still replaces an older pending run; its versions publish next run only if still at HEAD.matrix.chartviaenv.v0.1.2is not checked: its tree holds chart 0.2.0.For the reviewer:
github-pagesrequires a reviewer, so each release now waits for approval. Dropenvironment:if unwanted.helm-release.ymlafter this lands: pin itsrbac-manifestactions, addrbac-manifesttoreleaseneeds, and requireneeds.rbac-manifest.result == 'success'in itsif.Nothing run locally; this PR's CI runs
validateand the dry run against the live index and tags.🤖 Generated with Claude Code