diff --git a/.gitea/workflows/build-docs.yaml b/.gitea/workflows/build-docs.yaml index 66e24ce..4a03e70 100644 --- a/.gitea/workflows/build-docs.yaml +++ b/.gitea/workflows/build-docs.yaml @@ -98,9 +98,14 @@ jobs: # Use Gitea's built-in container registry (gitea.leeworks.dev), which # has a valid Let's Encrypt cert. The standalone registry.leeworks.dev # 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: | - echo "${{ secrets.GITEA_TOKEN }}" | docker login gitea.leeworks.dev \ - -u ${{ gitea.actor }} --password-stdin + echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.leeworks.dev \ + -u 0xWheatyz --password-stdin - name: Build and push docs-site image working-directory: api-company/docs-site diff --git a/scripts/setup-sibling-repos-token.sh b/scripts/setup-sibling-repos-token.sh index 5aadd94..b80dd6a 100755 --- a/scripts/setup-sibling-repos-token.sh +++ b/scripts/setup-sibling-repos-token.sh @@ -1,17 +1,20 @@ #!/usr/bin/env bash -# Create a Gitea PAT with read access to the sibling API repos and store it as -# the SIBLING_REPOS_TOKEN action secret on leeworks-agents/api-company. +# Create the Gitea PATs the build-docs workflow needs and store them as action +# 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: -# - Gitea's build-docs workflow checks out sibling repos. The auto-injected -# GITEA_TOKEN is scoped to THIS repo only and cannot read them, and -# GITEA_TOKEN is a reserved secret name that cannot be overridden. +# - The auto-injected GITEA_TOKEN is scoped to THIS repo only (can't read +# sibling repos) and has no package-registry scope (can't push images). +# 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 # 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 -# it straight into `tea` as the secret. The PAT value is never written to disk. +# So: this prompts for your password ONCE, mints both PATs via the API, and +# pipes each straight into `tea`. Token values are never written to disk. # # Usage: bash scripts/setup-sibling-repos-token.sh set -euo pipefail @@ -19,8 +22,7 @@ set -euo pipefail GITEA_URL="https://gitea.leeworks.dev" GITEA_USER="0xWheatyz" REPO="leeworks-agents/api-company" -SECRET_NAME="SIBLING_REPOS_TOKEN" -TOKEN_NAME="sibling-repos-readonly-$(date +%Y%m%d)" +STAMP="$(date +%Y%m%d)" command -v curl >/dev/null || { echo "curl 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 echo -# Create a read-only PAT. scope read:repository lets the build-docs workflow -# clone the sibling repos. Adjust scopes here if your Gitea version differs. -resp="$(curl -fsS -X POST \ - -u "${GITEA_USER}:${GITEA_PASS}" \ - -H 'Content-Type: application/json' \ - -d "{\"name\":\"${TOKEN_NAME}\",\"scopes\":[\"read:repository\"]}" \ - "${GITEA_URL}/api/v1/users/${GITEA_USER}/tokens")" || { - echo "Token creation failed. Check password / 2FA (2FA blocks basic-auth token creation)." >&2 - exit 1 - } +# mint_token +mint_token() { + local token_name="$1" scopes="$2" secret_name="$3" resp pat + resp="$(curl -fsS -X POST \ + -u "${GITEA_USER}:${GITEA_PASS}" \ + -H 'Content-Type: application/json' \ + -d "{\"name\":\"${token_name}\",\"scopes\":${scopes}}" \ + "${GITEA_URL}/api/v1/users/${GITEA_USER}/tokens")" || { + 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 - -PAT="$(printf '%s' "$resp" | python3 -c 'import sys,json; print(json.load(sys.stdin)["sha1"])')" -[ -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)" +echo "Done. Verify: tea actions secrets list --repo ${REPO}" +echo "Then re-run build-docs (push to main, or: tea actions workflows dispatch build-docs.yaml)"