diff --git a/.github/workflows/update-devpanel-cli.yml b/.github/workflows/update-devpanel-cli.yml index 31f18068..9074acec 100644 --- a/.github/workflows/update-devpanel-cli.yml +++ b/.github/workflows/update-devpanel-cli.yml @@ -7,9 +7,10 @@ name: Update DevPanel CLI binaries # Run it manually. The Actions cache records the latest commit that changed # cmd/devpanel-client. Delete that cache entry to rebuild the same commit. # -# devpanel/cli is cloned under RUNNER_TEMP, outside this repository. -# GHCR_TOKEN must be able to read devpanel/cli. The workflow token commits -# the binaries. +# The plan job reads the latest cmd/devpanel-client commit from the API. +# The build clones devpanel/cli under RUNNER_TEMP, outside this repository. +# GHCR_TOKEN must be able to read that repository. GHCR_USER is the username +# that owns the token. The workflow token commits the binaries. on: workflow_dispatch: @@ -29,32 +30,47 @@ jobs: sha: ${{ steps.upstream.outputs.sha }} changed: ${{ steps.decision.outputs.changed }} steps: - - name: Require GHCR_TOKEN + - name: Require GHCR credentials env: GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} + GHCR_USER: ${{ vars.GHCR_USER }} run: | if [[ -z "${GHCR_TOKEN}" ]]; then echo "::error::GHCR_TOKEN is required to read devpanel/cli." exit 1 fi + if [[ -z "${GHCR_USER}" ]]; then + echo "::error::GHCR_USER is required. Set it to the username that owns GHCR_TOKEN." + exit 1 + fi - name: Resolve latest cmd/devpanel-client commit id: upstream env: GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} - GIT_TERMINAL_PROMPT: "0" + GHCR_USER: ${{ vars.GHCR_USER }} run: | set -euo pipefail - dest="${RUNNER_TEMP}/devpanel-cli-history" - rm -rf "$dest" - git -c "http.extraheader=AUTHORIZATION: bearer ${GHCR_TOKEN}" \ - clone --filter=blob:none --no-checkout \ - https://github.com/devpanel/cli.git "$dest" - sha=$(git -C "$dest" log -1 --format=%H -- cmd/devpanel-client) + body=$(mktemp) + code=$( + curl -sS \ + -u "${GHCR_USER}:${GHCR_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + -o "$body" \ + -w "%{http_code}" \ + "https://api.github.com/repos/devpanel/cli/commits?path=cmd/devpanel-client&per_page=1" \ + || true + ) + if [[ "$code" != "200" ]]; then + echo "::error::Unable to read cmd/devpanel-client history (HTTP ${code:-unknown})." + jq -r '.message // empty' "$body" >&2 || true + exit 1 + fi + sha=$(jq -r '.[0].sha // empty' "$body") + rm -f "$body" if [[ ! "$sha" =~ ^[0-9a-f]{40}$ ]]; then echo "::error::No commit on the default branch changes cmd/devpanel-client." - echo "Entries under cmd/:" >&2 - git -C "$dest" ls-tree --name-only HEAD cmd >&2 || true exit 1 fi echo "sha=${sha}" >> "$GITHUB_OUTPUT" @@ -104,14 +120,17 @@ jobs: - name: Clone devpanel/cli env: GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} + GHCR_USER: ${{ vars.GHCR_USER }} UPSTREAM_SHA: ${{ needs.plan.outputs.sha }} + GIT_TERMINAL_PROMPT: "0" run: | set -euo pipefail dest="${RUNNER_TEMP}/devpanel-cli" mkdir "$dest" + auth=$(printf '%s:%s' "${GHCR_USER}" "${GHCR_TOKEN}" | base64 -w0) git -C "$dest" init git -C "$dest" remote add origin https://github.com/devpanel/cli.git - git -C "$dest" -c "http.extraheader=AUTHORIZATION: bearer ${GHCR_TOKEN}" \ + git -C "$dest" -c "http.extraheader=AUTHORIZATION: basic ${auth}" \ fetch --depth 1 origin "$UPSTREAM_SHA" git -C "$dest" checkout --detach FETCH_HEAD @@ -124,11 +143,10 @@ jobs: - name: Build native binary env: GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} + GHCR_USER: ${{ vars.GHCR_USER }} run: | set -euo pipefail - if [[ -n "${GHCR_TOKEN}" ]]; then - git config --global url."https://x-access-token:${GHCR_TOKEN}@github.com/".insteadOf "https://github.com/" - fi + git config --global url."https://${GHCR_USER}:${GHCR_TOKEN}@github.com/".insteadOf "https://github.com/" dest="${RUNNER_TEMP}/devpanel-${{ matrix.arch }}" ( cd "${RUNNER_TEMP}/devpanel-cli" diff --git a/AGENTS.md b/AGENTS.md index 292b2654..1b51e905 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -132,7 +132,7 @@ Baseline JSON files in `tests/baselines/` track pre-existing lint violations per - **`update-devpanel-cli.yml`** — manual `workflow_dispatch`. Builds `base/bin/devpanel-amd64` and `base/bin/devpanel-arm64` from the latest `devpanel/cli` commit that changed `cmd/devpanel-client`, when the Actions cache does not already contain that commit. A new run cancels one already in progress. The workflow token commits the binaries. - **`test.yml`** — runs YAML, shell, and Dockerfile linting plus build/run tests on pushes and pull requests. - Production images are tagged without suffix (e.g. `devpanel/php:8.3-base`); `develop` branch builds use the `-rc` suffix. -- Required repository secrets: `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`. Optional: `GHCR_TOKEN` (falls back to `GITHUB_TOKEN` for GHCR pushes). `update-devpanel-cli.yml` requires `GHCR_TOKEN` with access to `devpanel/cli`. +- Required repository secrets: `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`. Optional: `GHCR_TOKEN` (falls back to `GITHUB_TOKEN` for GHCR pushes). `update-devpanel-cli.yml` requires `GHCR_TOKEN` with access to `devpanel/cli`, and the `GHCR_USER` repository variable set to the username that owns that token. ## Environment Variables (base images) diff --git a/TODO.md b/TODO.md index 09aeb4f7..0d6826c4 100644 --- a/TODO.md +++ b/TODO.md @@ -114,11 +114,13 @@ Use this file to track work that needs to be done. Lint scripts automatically ap ## Definition of Done - A cache miss builds both binaries on `ubuntu-26.04` and `ubuntu-26.04-arm` and commits `base/bin/devpanel-amd64` and `base/bin/devpanel-arm64`. -# Task: Find the latest cmd/devpanel-client commit with git +# Task: Authenticate to devpanel/cli with GHCR_USER ## Steps -- [x] Stop using the commits API result that reported no history for that path. -- [x] Read the latest commit that changes `cmd/devpanel-client` from a clone of the default branch. +- [x] Require the `GHCR_USER` repository variable with `GHCR_TOKEN`. +- [x] Read the latest `cmd/devpanel-client` commit from the commits API as that user. +- [x] Clone and fetch `devpanel/cli` for the build with Basic auth for that username and token. ## Definition of Done -- The plan job records the commit `git log` reports for `cmd/devpanel-client`. +- The plan job records the commit the API returns for `cmd/devpanel-client`. +- The build job authenticates to `devpanel/cli` as `vars.GHCR_USER`.