From 59eedaf2e699517b424f2a116425f7c73f18e587 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 6 Nov 2026 03:38:10 +0000 Subject: [PATCH 1/2] Authenticate to devpanel/cli with GHCR_USER Classic PATs need the owning username for git HTTPS. Use the GHCR_USER repository variable with GHCR_TOKEN for clone, fetch, and Go modules. Co-authored-by: Darren Oh --- .github/workflows/update-devpanel-cli.yml | 25 +++++++++++++++-------- AGENTS.md | 2 +- TODO.md | 9 ++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/update-devpanel-cli.yml b/.github/workflows/update-devpanel-cli.yml index 31f18068..45f9eef9 100644 --- a/.github/workflows/update-devpanel-cli.yml +++ b/.github/workflows/update-devpanel-cli.yml @@ -8,8 +8,8 @@ name: Update DevPanel CLI binaries # 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. +# 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,25 +29,32 @@ 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 }} + GHCR_USER: ${{ vars.GHCR_USER }} GIT_TERMINAL_PROMPT: "0" run: | set -euo pipefail dest="${RUNNER_TEMP}/devpanel-cli-history" rm -rf "$dest" - git -c "http.extraheader=AUTHORIZATION: bearer ${GHCR_TOKEN}" \ + auth=$(printf '%s:%s' "${GHCR_USER}" "${GHCR_TOKEN}" | base64 -w0) + git -c "http.extraheader=AUTHORIZATION: basic ${auth}" \ clone --filter=blob:none --no-checkout \ https://github.com/devpanel/cli.git "$dest" sha=$(git -C "$dest" log -1 --format=%H -- cmd/devpanel-client) @@ -104,14 +111,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 +134,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..93cd8424 100644 --- a/TODO.md +++ b/TODO.md @@ -122,3 +122,12 @@ Use this file to track work that needs to be done. Lint scripts automatically ap ## Definition of Done - The plan job records the commit `git log` reports for `cmd/devpanel-client`. + +# Task: Authenticate to devpanel/cli with GHCR_USER + +## Steps +- [x] Require the `GHCR_USER` repository variable with `GHCR_TOKEN`. +- [x] Clone and fetch `devpanel/cli` with Basic auth for that username and token. + +## Definition of Done +- The plan and build jobs authenticate to `devpanel/cli` as `vars.GHCR_USER`. From c5669181880c4028a5e9200142931e7dc4be06e5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 6 Nov 2026 03:39:16 +0000 Subject: [PATCH 2/2] Read the devpanel-client commit from the API Authenticate as GHCR_USER and ask the commits API for the latest cmd/devpanel-client commit. Clone the repository only to build it. Co-authored-by: Darren Oh --- .github/workflows/update-devpanel-cli.yml | 31 +++++++++++++++-------- TODO.md | 15 +++-------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/workflows/update-devpanel-cli.yml b/.github/workflows/update-devpanel-cli.yml index 45f9eef9..9074acec 100644 --- a/.github/workflows/update-devpanel-cli.yml +++ b/.github/workflows/update-devpanel-cli.yml @@ -7,7 +7,8 @@ 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. +# 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. @@ -48,20 +49,28 @@ jobs: env: GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} GHCR_USER: ${{ vars.GHCR_USER }} - GIT_TERMINAL_PROMPT: "0" run: | set -euo pipefail - dest="${RUNNER_TEMP}/devpanel-cli-history" - rm -rf "$dest" - auth=$(printf '%s:%s' "${GHCR_USER}" "${GHCR_TOKEN}" | base64 -w0) - git -c "http.extraheader=AUTHORIZATION: basic ${auth}" \ - 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" diff --git a/TODO.md b/TODO.md index 93cd8424..0d6826c4 100644 --- a/TODO.md +++ b/TODO.md @@ -114,20 +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 - -## 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. - -## Definition of Done -- The plan job records the commit `git log` reports for `cmd/devpanel-client`. - # Task: Authenticate to devpanel/cli with GHCR_USER ## Steps - [x] Require the `GHCR_USER` repository variable with `GHCR_TOKEN`. -- [x] Clone and fetch `devpanel/cli` with Basic auth for that username and 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 and build jobs authenticate to `devpanel/cli` as `vars.GHCR_USER`. +- The plan job records the commit the API returns for `cmd/devpanel-client`. +- The build job authenticates to `devpanel/cli` as `vars.GHCR_USER`.