Skip to content

Publish the chart and its images from ACR - #38

Merged
MarceloRGonc merged 7 commits into
mg/OPS-4456from
chore/publish-chart-and-images-to-acr
Sep 10, 2026
Merged

Publish the chart and its images from ACR#38
MarceloRGonc merged 7 commits into
mg/OPS-4456from
chore/publish-chart-and-images-to-acr

Conversation

@MarceloRGonc

@MarceloRGonc MarceloRGonc commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Part of OPS-4817

Moves the chart itself and every image it references off Amazon ECR, and removes the CronJob that existed only because ECR credentials expire. Based on mg/OPS-4456, for the 0.6.26-draft release.

Completes the chart side of the migration. Follows openops-cloud/openops#2489, openops-cloud/devops#281 / #282 / #283 / #284.

⚠️ Three prerequisites, and one blocks this PR's own CI

0. helm-e2e will fail on this PR until openops releases. That workflow builds a kind cluster and runs helm upgrade --install -f chart/values.ci.yaml --wait, and values.ci.yaml pins global.version: "latest" — so it pulls openops.azurecr.io/openops-app:latest, which does not exist. latest is written by openops' release when github_release is true, so e2e can only go green after that release. tables and analytics will pull fine; app and worker are what fail.

Two prerequisites before releasing

1. openops must release 0.6.26 first. release.yml rewrites global.version, which is the app and worker image tag — so a 0.6.26-draft chart pulls openops.azurecr.io/openops-app:0.6.26. There is no 0.6.26 tag in openops and no openops-app in the public ACR at all today:

openops.azurecr.io  →  openops-analytics 0.14.8
                       openops-tables    0.2.22

So: run openops' release for 0.6.26, then release this chart. Note that openops' trigger-helm-chart-release passes -f draft=false, so a draft has to be dispatched by hand.

2. openops-cloud/devops#285 must be merged and applied — this repository has no federated credential yet, so azure/login fails without it. That credential's subject is refs/heads/main, so a release dispatched from mg/OPS-4456 will fail; release from main after merging, or say so and I'll add the branch as a second subject.

release.yml

Publishes to oci://openops.azurecr.io/helm with OIDC instead of a static ECR key.

az acr login --expose-token rather than a plain az acr login — the latter writes Docker's credential store, which helm does not read. Helm needs its own helm registry login.

Image references

Before After
image.repository public.ecr.aws/openops openops.azurecr.io
tables …/openops-tables:0.2.21 openops.azurecr.io/openops-tables:0.2.22
analytics …/openops-analytics:0.14.7 openops.azurecr.io/openops-analytics:0.14.8
OPS_SUBAGENT_RUNNER_IMAGE a private ECR path ""

The tables and analytics versions move because 0.2.21 and 0.14.7 don't exist in the ACR public registry — 0.2.22 and 0.14.8 are what those repositories published when they migrated. So the shipped stack picks up newer Baserow and Superset builds; worth a smoke test of a full install.

OPS_SUBAGENT_RUNNER_IMAGE is emptied, not repointed. Subagents are an enterprise feature configured on internal deployments, so the public chart had no business carrying a hardcoded reference to a private registry nobody installing this chart can pull from. Every other value for that feature — OPS_SUBAGENT_S3_* — is already empty by default, so this makes it consistent. It also removes an AWS account ID from a public repository. The real reference now lives only in devops' values files (openops-cloud/devops#284).

The CronJob is deleted

cronjob-ecr-credential-refresh.yaml — 184 lines of ServiceAccount, Role, RoleBinding, CronJob and one-shot Job — plus its values block and README section.

Its own comment gave the reason to remove it: "Required when AKS or non-AWS clusters need to pull from private ECR". That is precisely the problem this migration solves. It also could not have been ported: it runs aws ecr get-login-password and cannot mint an ACR token, so it was AWS-specific machinery for a registry the images have left.

What remains general is global.imagePullSecrets, which eight templates already consume, so anyone mirroring images elsewhere still has the hook.

The README section is replaced, not dropped — the capability isn't lost, so "Private ECR access from non-AWS clusters" becomes "Pulling from a private registry", explaining that release images need no credentials and that on AKS the kubelet identity replaces the secret. The EKS guides keep working: public images need no pull secret.

Verified by rendering, not by reading values

chart defaults      openops.azurecr.io/openops-app:0.6.26
                    openops.azurecr.io/openops-worker:0.6.26
                    openops.azurecr.io/openops-tables:0.2.22
                    openops.azurecr.io/openops-analytics:0.14.8

deploy-helm --set   openopsprivate.azurecr.io/openops-app:<sha>
                    openopsprivate.azurecr.io/openops-worker:<sha>
                    openops.azurecr.io/openops-tables:0.2.22
                    openops.azurecr.io/openops-analytics:0.14.8

Both paths correct: our own deployments take app and worker from the private registry by SHA via deploy-helm's --set, while tables and analytics come from the public one by version in both cases. helm lint passes and no ecr-credential-refresh objects render.

Also in here

  • values.ci.yaml's comment explained the version override by saying the default "does not exist in ECR" — the registry was beside the point, 0.0.1-dev is a placeholder release.yml rewrites and is never published anywhere.
  • AGENTS.md claimed draft versions are overwritable while final versions are immutable. That was a property of ECR Public, not of this release process. ACR does not enforce tag immutability unless configured, so a released chart version can now be overwritten by a later push of the same version. Worth deciding whether to turn that on; the -draft suffix is a naming convention either way.
  • The two remaining ECR mentions, in docs/DEPLOY_TO_AWS_EKS.md, are advice about ECR permissions and ECR image scanning for someone running on EKS with their own registry. They stay.

Test plan

  • devops#285 merged and applied, so azure/login works here
  • openops released at 0.6.26, so its images exist in the public ACR
  • Chart release 0.6.26-draft from main pushes to oci://openops.azurecr.io/helm
  • helm install from that chart on a clean cluster with no imagePullSecrets
  • A deployment to a subagents-enabled environment (staging) still resolves its runner image from devops values

🤖 Generated with Claude Code

Moves the chart itself and every image it references off Amazon ECR, and
removes the CronJob that existed only because ECR credentials expire.

release.yml:

Publishes to oci://openops.azurecr.io/helm using GitHub OIDC rather than a
static ECR key. `az acr login --expose-token` rather than a plain `az acr
login`, because the latter writes Docker's credential store and helm does not
read it - helm needs its own registry login.

chart/values.yaml:

  image.repository        public.ecr.aws/openops -> openops.azurecr.io
  tables.repository/tag   -> openops.azurecr.io, 0.2.22
  analytics.repository    -> openops.azurecr.io, 0.14.8
  OPS_SUBAGENT_RUNNER_IMAGE -> ""

The tables and analytics versions move because 0.2.21 and 0.14.7 do not exist
in the ACR public registry - 0.2.22 and 0.14.8 are what those repositories
published when they migrated.

OPS_SUBAGENT_RUNNER_IMAGE is emptied rather than repointed. Subagents are an
enterprise feature configured on internal deployments, so the public chart
had no business carrying a hardcoded reference to a private registry that no
one installing this chart can pull from - and every other value for that
feature, OPS_SUBAGENT_S3_* included, is already empty by default. It also
took an AWS account ID out of a public repository.

cronjob-ecr-credential-refresh.yaml is deleted:

It minted a 12-hour ECR token into an imagePullSecret every six hours, and
its own comment gave the reason - "Required when AKS or non-AWS clusters need
to pull from private ECR". That is precisely the problem this migration
solves. It could not have been ported either: it runs `aws ecr
get-login-password` and cannot mint an ACR token, so it was AWS-specific
machinery for a registry the images have left. What remains general is
global.imagePullSecrets, which eight templates already consume, so anyone
mirroring images elsewhere still has the hook.

The README section it served is replaced rather than dropped, because the
capability is not lost - release images need no credentials at all now, and
on AKS the kubelet's own identity replaces the secret.

Verified by rendering both paths:

  chart defaults        openops.azurecr.io/openops-{app,worker}:0.6.26
  deploy-helm --set     openopsprivate.azurecr.io/openops-{app,worker}:<sha>

with tables and analytics on the public registry by version in both.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@linear

linear Bot commented Sep 9, 2026

Copy link
Copy Markdown

OPS-4817

MarceloRGonc and others added 6 commits September 9, 2026 17:13
The section is documentation for people installing the chart, and what the
chart used to do two versions ago is not something they need to carry. The
reasoning belongs in the commit that removed it, which is where it is.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
values.ci.yaml explained the CI version override by saying the repo default
does not exist in ECR. The registry is beside the point - 0.0.1-dev is a
placeholder release.yml rewrites, so it is never published anywhere.

AGENTS.md claimed draft chart versions are overwritable while final versions
are immutable. That was a property of ECR Public, not of the release process:
ACR does not enforce tag immutability unless it is configured on the
registry, so a released chart version can now be overwritten by a later push
of the same version. Worth deciding whether to configure immutability there;
the -draft suffix is a naming convention either way.

The two remaining ECR mentions are in docs/DEPLOY_TO_AWS_EKS.md, about ECR
permissions and ECR image scanning. Both are advice for someone running on
EKS with their own registry, so they stay.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The images dropped their path segment when they moved: openops/ was ECR's
registry namespace, and ACR puts the organisation in the hostname, so
openops-tables and the rest sit at the root. The chart kept a helm/ segment
and was the only thing left nested.

  oci://openops.azurecr.io/helm/openops  ->  oci://openops.azurecr.io/openops

No collision with the image repositories: they are openops-app,
openops-worker, openops-tables, openops-analytics, openops-mcp and
subagent-runner, and the chart is named openops.

Anything already installed from the ECR path keeps working - that registry
still holds the old chart versions - but an upgrade has to use the new
reference, which is why NOTES.txt prints it after every install.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This reverts commit 9db57e8.

The chart stays at oci://openops.azurecr.io/helm, so it keeps a path of its
own rather than sitting alongside the image repositories at the root.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The chart push moves off github-actions-acr-push, which CI shares and which
any pull request in six repositories can assume, onto
github-actions-acr-release - whose credentials are scoped to the release
environment and which holds nothing CI can reach.

environment: release is not optional. The credential's subject is
repo:openops-cloud/helm-chart:environment:release, so without the
environment the subject does not match and azure/login fails. It is also
branch-agnostic, which is what lets this release run from mg/OPS-4456 rather
than only from main.

Requires openops-cloud/devops#287 applied, the organisation secret
AZURE_ACR_RELEASE_CLIENT_ID set, and a release environment on this
repository.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every run currently warns that actions/checkout@v4, actions/cache@v4,
azure/setup-helm@v4 and helm/kind-action@v1.9.0 target a runtime the runners
are dropping, and are being forced onto Node 24 anyway. Same bump the other
repositories got.

Inputs are unchanged across all five: kind-action still takes cluster_name and
wait, setup-helm still takes version, cache still takes path/key/restore-keys,
and action-gh-release still takes files/tag_name/name/body/draft.

Part of OPS-4817

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@MarceloRGonc
MarceloRGonc merged commit 70da0d4 into mg/OPS-4456 Sep 10, 2026
2 of 3 checks passed
@MarceloRGonc
MarceloRGonc deleted the chore/publish-chart-and-images-to-acr branch September 10, 2026 08:07
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.

1 participant