Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions .github/workflows/release-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
# summary: ${{ inputs.summary }}
# images: ghcr.io/cshuttle/topology
# runner: arc-topology
# secrets:
# # Only if the repo pushes with a classic PAT — see the secret's
# # description. Omit and GITHUB_TOKEN is used.
# ghcr-token: ${{ secrets.GHCR_WRITE_TOKEN }}
#
# NOT covered: repos whose artifact is a compiled binary rather than an image.
# There is exactly one of those (chrome-exporter) and its build is nothing like
Expand Down Expand Up @@ -111,6 +115,17 @@ on:
type: string
default: v0.21.7
required: false
secrets:
ghcr-token:
description: >-
Classic PAT with write:packages, for a package the repo-scoped
GITHUB_TOKEN cannot touch. `cshuttle` is a personal account, so a
package bootstrapped by a manual push is USER-owned: GITHUB_TOKEN 403s
on it — including on reads — unless that package grants this repo
access under Package settings -> Manage Actions access. Repos that
push with a classic PAT must pass the same one here, or the promote
step reports the image as missing when it is really unreadable.
required: false
outputs:
tag:
description: The git tag created.
Expand Down Expand Up @@ -182,7 +197,18 @@ jobs:
/tmp/crane version

- name: log in to ghcr
run: echo "${{ github.token }}" | /tmp/crane auth login ghcr.io -u "${{ github.actor }}" --password-stdin
env:
GHCR_TOKEN: ${{ secrets.ghcr-token }}
GHCR_USER: ${{ github.repository_owner }}
run: |
set -eu
if [ -n "${GHCR_TOKEN:-}" ]; then
printf '%s' "$GHCR_TOKEN" | /tmp/crane auth login ghcr.io -u "$GHCR_USER" --password-stdin
echo "authenticated to ghcr as $GHCR_USER with the supplied token"
else
printf '%s' "${{ github.token }}" | /tmp/crane auth login ghcr.io -u "${{ github.actor }}" --password-stdin
echo "authenticated to ghcr with GITHUB_TOKEN"
fi

# The heart of it: work out which commit the image actually came from,
# prove it belongs to this branch, then move the version tag onto that
Expand Down Expand Up @@ -211,8 +237,12 @@ jobs:

for img in $IMAGES; do
echo "── $img"
if ! digest="$(/tmp/crane digest "$img:$SOURCE_TAG" 2>/dev/null)"; then
echo "::error::$img:$SOURCE_TAG does not exist — nothing to promote."
if ! digest="$(/tmp/crane digest "$img:$SOURCE_TAG" 2>&1)"; then
echo "::error::cannot read $img:$SOURCE_TAG — crane said: $digest"
echo "::error::If the tag plainly exists, this is almost certainly AUTH, not absence:"
echo "::error::a user-owned ghcr package returns the same 'not found' for an unauthorised"
echo "::error::read. Pass the repo's classic PAT as the ghcr-token secret, or grant this"
echo "::error::repo access under the package's Manage Actions access settings."
exit 1
fi
echo " $SOURCE_TAG = $digest"
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ jobs:
summary: ${{ inputs.summary }}
images: ghcr.io/cshuttle/topology
runner: arc-<repo>
secrets:
# Only for a package GITHUB_TOKEN cannot read — see below. Omit otherwise.
ghcr-token: ${{ secrets.GHCR_WRITE_TOKEN }}
```

- **Promotes, never rebuilds.** A rebuild on the tag produces a second digest
Expand All @@ -223,6 +226,12 @@ jobs:
the image tag: `/` is not legal in a docker tag.
- Notes are always GitHub-generated; `summary` is pre-pended when supplied, and
the promoted digests are listed under it.
- **`ghcr-token` when the package is user-owned.** On a personal account a
package bootstrapped by a manual push is owned by the user, not the repo, and
`GITHUB_TOKEN` gets 403 on it — including on reads, which the registry reports
as a plain "not found". A repo that pushes with a classic PAT must pass the
same PAT here. The alternative is granting the repo access under the package's
*Manage Actions access* settings, after which the secret can be dropped.

## Git hooks

Expand Down