fix(ci): authenticate registry push with package-scoped REGISTRY_TOKEN
Validate Flux manifests / kustomize-build (pull_request) Successful in 22s
Validate Flux manifests / kustomize-build (pull_request) Successful in 22s
The auto GITEA_TOKEN has no package-registry scope, so docker login to gitea.leeworks.dev returned 'unauthorized'. Use a dedicated PAT (REGISTRY_TOKEN, write:package) with the token-owner username. Helper script now mints both SIBLING_REPOS_TOKEN and REGISTRY_TOKEN from one password prompt.
This commit is contained in:
@@ -98,9 +98,14 @@ jobs:
|
|||||||
# Use Gitea's built-in container registry (gitea.leeworks.dev), which
|
# Use Gitea's built-in container registry (gitea.leeworks.dev), which
|
||||||
# has a valid Let's Encrypt cert. The standalone registry.leeworks.dev
|
# has a valid Let's Encrypt cert. The standalone registry.leeworks.dev
|
||||||
# serves Traefik's default self-signed cert and fails TLS verification.
|
# serves Traefik's default self-signed cert and fails TLS verification.
|
||||||
|
#
|
||||||
|
# Auth uses REGISTRY_TOKEN, NOT the auto GITEA_TOKEN: the auto token has
|
||||||
|
# no package-registry scope, and the registry requires the username to
|
||||||
|
# match the token owner. REGISTRY_TOKEN must be a PAT (owner: 0xWheatyz)
|
||||||
|
# with write:package + read:package scope.
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.GITEA_TOKEN }}" | docker login gitea.leeworks.dev \
|
echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.leeworks.dev \
|
||||||
-u ${{ gitea.actor }} --password-stdin
|
-u 0xWheatyz --password-stdin
|
||||||
|
|
||||||
- name: Build and push docs-site image
|
- name: Build and push docs-site image
|
||||||
working-directory: api-company/docs-site
|
working-directory: api-company/docs-site
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Create a Gitea PAT with read access to the sibling API repos and store it as
|
# Create the Gitea PATs the build-docs workflow needs and store them as action
|
||||||
# the SIBLING_REPOS_TOKEN action secret on leeworks-agents/api-company.
|
# secrets on leeworks-agents/api-company:
|
||||||
|
# - SIBLING_REPOS_TOKEN : read:repository (clone the sibling API repos)
|
||||||
|
# - REGISTRY_TOKEN : write:package + read:package
|
||||||
|
# (push the docs-site image to gitea.leeworks.dev)
|
||||||
#
|
#
|
||||||
# Why this script exists:
|
# Why this script exists:
|
||||||
# - Gitea's build-docs workflow checks out sibling repos. The auto-injected
|
# - The auto-injected GITEA_TOKEN is scoped to THIS repo only (can't read
|
||||||
# GITEA_TOKEN is scoped to THIS repo only and cannot read them, and
|
# sibling repos) and has no package-registry scope (can't push images).
|
||||||
# GITEA_TOKEN is a reserved secret name that cannot be overridden.
|
# GITEA_TOKEN is also a reserved secret name that cannot be overridden.
|
||||||
# - `tea` cannot CREATE a PAT (no such command), and Gitea's token-creation
|
# - `tea` cannot CREATE a PAT (no such command), and Gitea's token-creation
|
||||||
# API requires BASIC AUTH (your password) — a token cannot mint a token.
|
# API requires BASIC AUTH (your password) — a token cannot mint a token.
|
||||||
# - `tea` CAN set the action secret using its existing login.
|
# - `tea` CAN set the action secrets using its existing login.
|
||||||
#
|
#
|
||||||
# So: this prompts for your password ONCE, mints the PAT via the API, and pipes
|
# So: this prompts for your password ONCE, mints both PATs via the API, and
|
||||||
# it straight into `tea` as the secret. The PAT value is never written to disk.
|
# pipes each straight into `tea`. Token values are never written to disk.
|
||||||
#
|
#
|
||||||
# Usage: bash scripts/setup-sibling-repos-token.sh
|
# Usage: bash scripts/setup-sibling-repos-token.sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -19,8 +22,7 @@ set -euo pipefail
|
|||||||
GITEA_URL="https://gitea.leeworks.dev"
|
GITEA_URL="https://gitea.leeworks.dev"
|
||||||
GITEA_USER="0xWheatyz"
|
GITEA_USER="0xWheatyz"
|
||||||
REPO="leeworks-agents/api-company"
|
REPO="leeworks-agents/api-company"
|
||||||
SECRET_NAME="SIBLING_REPOS_TOKEN"
|
STAMP="$(date +%Y%m%d)"
|
||||||
TOKEN_NAME="sibling-repos-readonly-$(date +%Y%m%d)"
|
|
||||||
|
|
||||||
command -v curl >/dev/null || { echo "curl required"; exit 1; }
|
command -v curl >/dev/null || { echo "curl required"; exit 1; }
|
||||||
command -v tea >/dev/null || { echo "tea required"; exit 1; }
|
command -v tea >/dev/null || { echo "tea required"; exit 1; }
|
||||||
@@ -30,26 +32,26 @@ echo "Gitea user: $GITEA_USER ($GITEA_URL)"
|
|||||||
read -r -s -p "Gitea password (for $GITEA_USER): " GITEA_PASS
|
read -r -s -p "Gitea password (for $GITEA_USER): " GITEA_PASS
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Create a read-only PAT. scope read:repository lets the build-docs workflow
|
# mint_token <token-name> <json-scopes-array> <secret-name>
|
||||||
# clone the sibling repos. Adjust scopes here if your Gitea version differs.
|
mint_token() {
|
||||||
resp="$(curl -fsS -X POST \
|
local token_name="$1" scopes="$2" secret_name="$3" resp pat
|
||||||
-u "${GITEA_USER}:${GITEA_PASS}" \
|
resp="$(curl -fsS -X POST \
|
||||||
-H 'Content-Type: application/json' \
|
-u "${GITEA_USER}:${GITEA_PASS}" \
|
||||||
-d "{\"name\":\"${TOKEN_NAME}\",\"scopes\":[\"read:repository\"]}" \
|
-H 'Content-Type: application/json' \
|
||||||
"${GITEA_URL}/api/v1/users/${GITEA_USER}/tokens")" || {
|
-d "{\"name\":\"${token_name}\",\"scopes\":${scopes}}" \
|
||||||
echo "Token creation failed. Check password / 2FA (2FA blocks basic-auth token creation)." >&2
|
"${GITEA_URL}/api/v1/users/${GITEA_USER}/tokens")" || {
|
||||||
exit 1
|
echo "Token '${token_name}' creation failed. Check password / 2FA (2FA blocks basic-auth token creation)." >&2
|
||||||
}
|
return 1
|
||||||
|
}
|
||||||
|
pat="$(printf '%s' "$resp" | python3 -c 'import sys,json; print(json.load(sys.stdin)["sha1"])')"
|
||||||
|
[ -n "$pat" ] || { echo "Could not parse token from: $resp" >&2; return 1; }
|
||||||
|
printf '%s' "$pat" | tea actions secrets create "$secret_name" --repo "$REPO" --stdin
|
||||||
|
echo " ✓ ${secret_name} set (PAT '${token_name}')"
|
||||||
|
}
|
||||||
|
|
||||||
|
mint_token "sibling-repos-readonly-${STAMP}" '["read:repository"]' "SIBLING_REPOS_TOKEN"
|
||||||
|
mint_token "docs-registry-${STAMP}" '["write:package","read:package"]' "REGISTRY_TOKEN"
|
||||||
|
|
||||||
unset GITEA_PASS
|
unset GITEA_PASS
|
||||||
|
echo "Done. Verify: tea actions secrets list --repo ${REPO}"
|
||||||
PAT="$(printf '%s' "$resp" | python3 -c 'import sys,json; print(json.load(sys.stdin)["sha1"])')"
|
echo "Then re-run build-docs (push to main, or: tea actions workflows dispatch build-docs.yaml)"
|
||||||
[ -n "$PAT" ] || { echo "Could not parse token from response: $resp" >&2; exit 1; }
|
|
||||||
echo "PAT '${TOKEN_NAME}' created."
|
|
||||||
|
|
||||||
# Store it as the action secret via tea (overwrites if it already exists).
|
|
||||||
printf '%s' "$PAT" | tea actions secrets create "$SECRET_NAME" --repo "$REPO" --stdin
|
|
||||||
unset PAT
|
|
||||||
|
|
||||||
echo "Secret '${SECRET_NAME}' set on ${REPO}."
|
|
||||||
echo "Verify: tea actions secrets list --repo ${REPO}"
|
|
||||||
echo "Then re-run build-docs: tea actions runs ... (or push to main / workflow_dispatch)"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user