Skip to main content
Every release publishes four artifacts from one commit, all sharing a single version number: The application source is proprietary and is not published. Images carry no org.opencontainers.image.source label, and the chart references only the documentation site and the images, so no public artifact points at the private repository.

Version coupling

The chart’s version and appVersion are stamped from the release tag, and image.tag and workspaceImage.tag default to empty. When empty, the chart resolves images from its own appVersion. This means installing chart 0.3.0 runs the images built for 0.3.0, with no way for the chart and its images to drift apart. Overriding a tag is an explicit opt-out:

Cutting a release

1

Make sure main is green

CI runs formatting, lint, typecheck, unit tests, database tests, a build, chart lint and render, and a build of both images on every push and pull request.
2

Tag the commit

The tag drives the version; the working Chart.yaml does not need editing.
3

The release workflow runs

In order: resolve and validate the version, build and push both images, package and push the OCI chart, then publish the Helm repository to charts.r5d.dev.
4

Verify the published artifacts

You can also run the workflow manually from the Actions tab with an explicit version, which is useful for re-publishing after an infrastructure failure.

Where the Helm repository lives

charts.r5d.dev is a Cloudflare R2 bucket served through a custom domain. The release workflow uploads with scripts/r2-sync.ts, a small SigV4 client so that publishing needs nothing beyond Bun. Upload order matters and is deliberate: chart archives are uploaded first and index.yaml last, so the index never advertises a version that cannot yet be downloaded. Archives are cached immutably; index.yaml is cached for one minute so a new release becomes visible quickly.

What the workflow guarantees

The version must match semver, optionally with a prerelease suffix. An invalid tag fails before anything is published.
The chart job depends on the image job, so a chart version never references images that do not exist.
Images are pushed with build provenance and an SBOM for supply-chain verification.
The publish step downloads the existing index and its packages, merges the new version, and republishes. Previously released versions stay installable, so rollbacks keep working.
The workflow asserts the new version appears in index.yaml with its .tgz, then adds the live repository and resolves the new version through helm show chart before reporting success.

Consuming releases

latest is published for convenience but should not be deployed. It makes rollbacks ambiguous and causes pods to change behavior on an unrelated restart. Always pin a version.

Publishing requirements

Publishing depends on repository secrets for the Helm repository bucket:
  • R2_ACCOUNT_ID, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY.
  • The R2 token is scoped to object read/write on the charts bucket only.
  • The workflow requests packages: write for GHCR; no personal access token is required.

Package visibility

New GHCR packages are private by default. All three published packages are public so that a self-hosted installation needs no credentials:
  • r5d-chat-control-plane
  • r5d-chat-workspace
  • charts/r5d-chat
A newly created package reverts to private, so after the first release that creates charts/r5d-chat, set it to public under its package settings on GitHub. Otherwise helm install from the OCI reference fails for anonymous users while the charts.r5d.dev repository keeps working.