diff --git a/.gitea/workflows/chart-release.yml b/.gitea/workflows/chart-release.yml index fe11a36..979b337 100644 --- a/.gitea/workflows/chart-release.yml +++ b/.gitea/workflows/chart-release.yml @@ -126,20 +126,36 @@ jobs: # github.server_url is this Gitea instance, so the registry # host needs no variable of its own and cannot drift from it. REGISTRY: ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/helm/api/charts + # The same pair server-deploy.yml uses for `docker login`. + # RELEASE_TOKEN, not REGISTRY_PASSWORD: the latter is named in + # the docs but set by no workflow, and an unset secret becomes + # an empty password, which Gitea reports as "Failed to + # authenticate user" rather than as a missing credential. REGISTRY_USER: ${{ secrets.REGISTRY_USER }} - REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} + REGISTRY_TOKEN: ${{ secrets.RELEASE_TOKEN }} CHART_VERSION: ${{ steps.chart.outputs.version }} run: | set -eu PKG="dist/vantage-${CHART_VERSION}.tgz" test -f "$PKG" + # Checked explicitly, because the failure it prevents is a + # 401 that looks like a permissions problem on the token that + # was never sent. + if [ -z "${REGISTRY_USER}" ] || [ -z "${REGISTRY_TOKEN}" ]; then + echo "REGISTRY_USER or RELEASE_TOKEN is not set on this repository." + echo "RELEASE_TOKEN needs the write:package scope to publish a chart." + exit 1 + fi + + echo "publishing to ${REGISTRY} as ${REGISTRY_USER}" + # --fail-with-body so an HTTP error is a failed step with the # server's explanation, rather than a green run that published # nothing. A repeated version is rejected by the registry; # that is the intended behaviour, not something to retry past. curl --fail-with-body -sS \ - --user "${REGISTRY_USER}:${REGISTRY_PASSWORD}" \ + --user "${REGISTRY_USER}:${REGISTRY_TOKEN}" \ -X POST \ --upload-file "$PKG" \ "$REGISTRY" diff --git a/claude.md b/claude.md index 4a6ab4e..b06d1a3 100644 --- a/claude.md +++ b/claude.md @@ -730,7 +730,7 @@ Two jobs' worth of work in one, split by trigger. Any push or PR touching `deplo Publishing runs only on a `chart/v*` tag, to the Gitea Helm registry at `/api/packages//helm/api/charts`. **`Chart.yaml` is the source of truth for the version**; the tag only selects which one to publish, and a tag that disagrees with `Chart.yaml` fails rather than stamping over it — the alternative leaves the repository disagreeing with what shipped. A version already in the registry is rejected by Gitea, which is intended: published chart versions are immutable. -The registry host comes from `github.server_url`, so it cannot drift from the instance the workflow is running on, and it reuses `REGISTRY_USER` / `REGISTRY_PASSWORD` — the same `write:packages` token the images use. +The registry host comes from `github.server_url`, so it cannot drift from the instance the workflow is running on. It authenticates with `REGISTRY_USER` + **`RELEASE_TOKEN`** — the pair `server-deploy.yml` actually uses for `docker login`. `REGISTRY_PASSWORD` is listed in the secrets table below but set by no workflow; passing an unset secret yields an empty password and Gitea answers `401 Failed to authenticate user`, which reads like a scope problem on a token that was never sent. The publish step therefore checks both are non-empty before it calls curl. `RELEASE_TOKEN` needs `write:package` in addition to `write:release`. ```bash helm repo add vantage https://gitea.hostxtra.co.uk/api/packages/mrhid6/helm @@ -749,9 +749,9 @@ git push origin main # server + web deploy | Name | Type | Value | | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `RELEASE_TOKEN` | Secret | Gitea API token, `write:release` | -| `REGISTRY_USER` | Secret | Gitea username | -| `REGISTRY_PASSWORD` | Secret | Gitea token, `write:packages` | +| `RELEASE_TOKEN` | Secret | Gitea API token. Needs `write:release` (agent releases), `write:package` (container images and the Helm chart). **This is the only token any workflow authenticates with** — `docker login` and the chart publish both pair it with `REGISTRY_USER` | +| `REGISTRY_USER` | Secret | Gitea username. Must own `RELEASE_TOKEN`, or basic auth is rejected | +| ~~`REGISTRY_PASSWORD`~~ | — | **Not used.** Named here historically; no workflow reads it. Referencing an unset secret yields an empty password and a `401 Failed to authenticate user` that looks like a token scope problem. Use `RELEASE_TOKEN` | | `DOCKER_HOST` | Variable | registry host used for image tags | | `API_URL` | **not** a CI variable | `web` reads it at **runtime**, from the container environment — `next.config.ts` is evaluated when `server.js` boots in standalone mode, and the rewrites it feeds are server-side, never browser-side. Default `http://localhost:8080`; compose sets `http://server:8080`. `NEXT_PUBLIC_API_URL` is still honoured as a fallback for existing deployments. | | `SITE_API_URL` | Variable | **browser-reachable** sitesvc URL, baked into the `site` image. Required — if empty, both forms report "not connected" and submit nowhere. Must also be in sitesvc's `SITE_ORIGIN`. |