Publish the SDKs with a token that can write packages
build / build (push) Has been cancelled

The SDK job reached `npm publish` and got E401. The token Actions injects is
real and valid -- 40 characters, `GET /api/v1/user` returns 200, and it reads
the package registry as the repository owner -- but every *write* to the
registry is refused:

    npm PUT (bearer, as npm)   -> 401
    npm PUT (basic)            -> 401

Both schemes, so this is authority and not `_authToken` sending Bearer. Adding
`permissions: packages: write` to the workflow changed nothing either.

So the four publish steps now take PACKAGES_TOKEN, a repository secret holding
an access token scoped to `write:package`. goreleaser keeps the injected token:
it creates the release and uploads binaries, which is repository write, and
that half has always worked.

This is why v0.1.0's packages had to be published by hand -- the SDK job has
never once run to completion.
This commit is contained in:
max-voitcov
2026-08-26 10:33:49 +03:00
parent 9c3b595b7e
commit 398dc2cfb4
+12 -40
View File
@@ -27,12 +27,12 @@ env:
GITEA_HOST: gitea.coolify.vojtkov.dev
GITEA_OWNER: usr_unknown
# The token Actions injects can read the package registry but not write to
# it: a publish comes back 401 under both Bearer and Basic. Ask for one that
# can.
permissions:
contents: write
packages: write
# Publishing to the package registries needs its own token. The one Actions
# injects authenticates fine -- it reads the registry and the API as the repo
# owner -- but every write comes back 401, under Bearer and Basic alike, and
# `permissions: packages: write` does not change that. So PACKAGES_TOKEN is a
# repository secret holding an access token with the `write:package` scope.
# Everything else here still uses the injected token.
jobs:
# The plugin binaries. Pulumi resolves them from this release via the
@@ -79,6 +79,8 @@ jobs:
args: release --clean --parallelism 1
workdir: pulumi-dokploy
env:
# goreleaser creates the release and uploads binaries: repository
# write, which the injected token already has. Not a package write.
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GOGC: "50"
@@ -98,36 +100,6 @@ jobs:
# Needed for the tag lookup below.
fetch-depth: 0
# TEMPORARY: triage for the npm E401 on publish. Prints lengths and
# status codes only, never a token value.
- name: Triage the publish token
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
run: |
echo "token length: ${#TOKEN}"
echo -n "GET /api/v1/user -> "
curl -s -o /dev/null -w '%{http_code}\n' \
-H "Authorization: token $TOKEN" "https://${GITEA_HOST}/api/v1/user"
echo -n "GET /api/v1/packages/owner -> "
curl -s -o /dev/null -w '%{http_code}\n' \
-H "Authorization: token $TOKEN" "https://${GITEA_HOST}/api/v1/packages/${GITEA_OWNER}?limit=1"
echo -n "npm registry GET (basic) -> "
curl -s -o /dev/null -w '%{http_code}\n' \
-u "${GITEA_OWNER}:$TOKEN" \
"https://${GITEA_HOST}/api/packages/${GITEA_OWNER}/npm/@maxvojtkov%2Fpulumi-dokploy"
# A write with a deliberately empty body: 401 means the credentials
# were refused, anything else means they were accepted and only the
# payload was rejected. That is what separates "wrong token" from
# "wrong auth scheme".
echo -n "npm PUT (bearer, as npm) -> "
curl -s -o /dev/null -w '%{http_code}\n' -X PUT \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{}' "https://${GITEA_HOST}/api/packages/${GITEA_OWNER}/npm/@maxvojtkov%2Fpulumi-dokploy"
echo -n "npm PUT (basic) -> "
curl -s -o /dev/null -w '%{http_code}\n' -X PUT \
-u "${GITEA_OWNER}:$TOKEN" -H 'Content-Type: application/json' \
-d '{}' "https://${GITEA_HOST}/api/packages/${GITEA_OWNER}/npm/@maxvojtkov%2Fpulumi-dokploy"
- uses: actions/checkout@v4
with:
repository: ${{ env.UPSTREAM_REPO }}
@@ -176,7 +148,7 @@ jobs:
- name: Publish to the Gitea npm registry
working-directory: pulumi-dokploy/sdk/nodejs/bin
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
TOKEN: ${{ secrets.PACKAGES_TOKEN }}
run: |
cat > .npmrc <<EOF
@maxvojtkov:registry=https://${GITEA_HOST}/api/packages/${GITEA_OWNER}/npm/
@@ -188,7 +160,7 @@ jobs:
working-directory: pulumi-dokploy/sdk/python
env:
TWINE_USERNAME: ${{ env.GITEA_OWNER }}
TWINE_PASSWORD: ${{ secrets.GITEA_TOKEN }}
TWINE_PASSWORD: ${{ secrets.PACKAGES_TOKEN }}
run: |
python -m pip install --upgrade build twine
python -m build
@@ -199,7 +171,7 @@ jobs:
- name: Publish to the Gitea NuGet registry
working-directory: pulumi-dokploy/sdk/dotnet
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
TOKEN: ${{ secrets.PACKAGES_TOKEN }}
run: |
dotnet pack --configuration Release --output ./nupkg
dotnet nuget push ./nupkg/*.nupkg \
@@ -216,7 +188,7 @@ jobs:
- name: Publish the Go SDK to the Gitea Go registry
working-directory: pulumi-dokploy
env:
TOKEN: ${{ secrets.GITEA_TOKEN }}
TOKEN: ${{ secrets.PACKAGES_TOKEN }}
run: |
set -euo pipefail
MODULE=github.com/maxvojtkov/pulumi-dokploy/sdk