NEXT_PUBLIC_CLOUDINARY_API_KEY and NEXT_PUBLIC_IMAGE_PROCESSING_API_URL are
NEXT_PUBLIC_* vars that must be baked in at build time — added as ARG/ENV in
admin Dockerfile and as --build-arg in the workflow build step.
CLOUDINARY_API_SECRET is a server-side secret — added to the deploy step's
env block, written to /opt/staging/.env via printf, and exposed to the admin
container via compose.yml environment block.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add --force-recreate to podman compose up so stale containers are never
reused across deploys when the image tag (staging) is reused
- Inject CLERK_SECRET_KEY and ADMIN_CLERK_SECRET_KEY from Gitea secrets into
~/staging/.env on the VPS via printf (variables expand on the runner before
SSH, so secrets never touch VPS shell history; file gets chmod 600)
- Update compose.yml: storefront gets CLERK_SECRET_KEY, admin gets
CLERK_SECRET_KEY mapped from ADMIN_CLERK_SECRET_KEY
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The compose file was written via a bash << 'COMPOSE' heredoc nested inside
the YAML run: | block scalar. Lines like "name: petloft-staging" at column 0
cause the YAML parser to break out of the block scalar early, making the
entire workflow file invalid YAML — Gitea silently drops invalid workflows,
so no jobs triggered at all.
Fix: move compose.yml to deploy/staging/compose.yml in the repo, substitute
${REGISTRY} on the runner, base64-encode the result, and decode it on the VPS
inside the SSH session. No inner heredoc needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>