From 27f04f1073aa716487d5e3f8e12d350ee1185626 Mon Sep 17 00:00:00 2001 From: Ricardo Mancinas Date: Thu, 30 Jul 2026 14:24:43 -0700 Subject: [PATCH] fix(deploy): preflight missing secrets instead of failing opaquely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first deploy attempt (run 705) died on "Input required and not supplied: token", which names the action's input rather than the secret that was unset — the repo had only REGISTRY_USERNAME and REGISTRY_PASSWORD, so every deploy secret was missing on both workflows. That is also why the endpoint_id / pull_image input-name bug had gone unnoticed: neither workflow had ever got far enough to use them. Both workflows now check their required secrets up front and fail listing the ones that are empty. The scope=full-only secrets are only required when the dispatch is actually scope=full. Co-Authored-By: Claude Opus 5 --- .gitea/workflows/deploy-galactus.yml | 45 ++++++++++++++++++++++++++++ .gitea/workflows/deploy.yml | 42 ++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/.gitea/workflows/deploy-galactus.yml b/.gitea/workflows/deploy-galactus.yml index 243ee92..78d180e 100644 --- a/.gitea/workflows/deploy-galactus.yml +++ b/.gitea/workflows/deploy-galactus.yml @@ -95,6 +95,51 @@ jobs: - uses: actions/checkout@v4 + # An unset secret arrives as an empty string, and the deploy action then + # fails with "Input required and not supplied: token" — which names the + # action's input, not the secret you forgot. Check them up front and say + # exactly which ones are missing. + - name: Preflight — required secrets + env: + PORTAINER_URL_GALACTUS: ${{ secrets.PORTAINER_URL_GALACTUS }} + PORTAINER_API_KEY_GALACTUS: ${{ secrets.PORTAINER_API_KEY_GALACTUS }} + PORTAINER_ENDPOINT_ID_GALACTUS: ${{ secrets.PORTAINER_ENDPOINT_ID_GALACTUS }} + PORTAINER_APP_STACK_NAME_GALACTUS: ${{ secrets.PORTAINER_APP_STACK_NAME_GALACTUS }} + PORTAINER_DB_STACK_NAME_GALACTUS: ${{ secrets.PORTAINER_DB_STACK_NAME_GALACTUS }} + PORTAINER_MINIO_STACK_NAME_GALACTUS: ${{ secrets.PORTAINER_MINIO_STACK_NAME_GALACTUS }} + DATABASE_URL_GALACTUS: ${{ secrets.DATABASE_URL_GALACTUS }} + SESSION_SECRET_GALACTUS: ${{ secrets.SESSION_SECRET_GALACTUS }} + APP_API_ORIGIN_GALACTUS: ${{ secrets.APP_API_ORIGIN_GALACTUS }} + APP_WEB_ORIGIN_GALACTUS: ${{ secrets.APP_WEB_ORIGIN_GALACTUS }} + APP_S3_ENDPOINT_GALACTUS: ${{ secrets.APP_S3_ENDPOINT_GALACTUS }} + MINIO_ROOT_USER: ${{ secrets.MINIO_ROOT_USER }} + MINIO_ROOT_PASSWORD: ${{ secrets.MINIO_ROOT_PASSWORD }} + MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }} + MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }} + SCOPE: ${{ github.event.inputs.scope }} + run: | + REQUIRED="PORTAINER_URL_GALACTUS PORTAINER_API_KEY_GALACTUS + PORTAINER_ENDPOINT_ID_GALACTUS PORTAINER_APP_STACK_NAME_GALACTUS + DATABASE_URL_GALACTUS SESSION_SECRET_GALACTUS + APP_API_ORIGIN_GALACTUS APP_WEB_ORIGIN_GALACTUS + APP_S3_ENDPOINT_GALACTUS MINIO_ROOT_USER MINIO_ROOT_PASSWORD" + if [ "$SCOPE" = "full" ]; then + REQUIRED="$REQUIRED PORTAINER_DB_STACK_NAME_GALACTUS + PORTAINER_MINIO_STACK_NAME_GALACTUS + MYSQL_PASSWORD MYSQL_ROOT_PASSWORD" + fi + missing="" + for name in $REQUIRED; do + eval "value=\${$name}" + [ -z "$value" ] && missing="$missing $name" + done + if [ -n "$missing" ]; then + echo "::error::missing repo secrets:$missing" + echo "::error::set them under Settings > Actions > Secrets" + exit 1 + fi + echo "all required secrets present for scope=$SCOPE" + # --- full only: database --------------------------------------------- - name: Deploy database stack if: ${{ github.event.inputs.scope == 'full' }} diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 9db7bfa..c301e52 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -101,6 +101,48 @@ jobs: - uses: actions/checkout@v4 + # An unset secret arrives as an empty string, and the deploy action then + # fails with "Input required and not supplied: token" — which names the + # action's input, not the secret you forgot. + - name: Preflight — required secrets + env: + PORTAINER_URL: ${{ secrets.PORTAINER_URL }} + PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }} + PORTAINER_ENDPOINT_ID: ${{ secrets.PORTAINER_ENDPOINT_ID }} + PORTAINER_APP_STACK_NAME: ${{ secrets.PORTAINER_APP_STACK_NAME }} + PORTAINER_DB_STACK_NAME: ${{ secrets.PORTAINER_DB_STACK_NAME }} + PORTAINER_MINIO_STACK_NAME: ${{ secrets.PORTAINER_MINIO_STACK_NAME }} + DATABASE_URL: ${{ secrets.DATABASE_URL }} + SESSION_SECRET: ${{ secrets.SESSION_SECRET }} + APP_API_ORIGIN: ${{ secrets.APP_API_ORIGIN }} + APP_WEB_ORIGIN: ${{ secrets.APP_WEB_ORIGIN }} + APP_S3_ENDPOINT: ${{ secrets.APP_S3_ENDPOINT }} + MINIO_ROOT_USER: ${{ secrets.MINIO_ROOT_USER }} + MINIO_ROOT_PASSWORD: ${{ secrets.MINIO_ROOT_PASSWORD }} + MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }} + MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }} + SCOPE: ${{ github.event.inputs.scope }} + run: | + REQUIRED="PORTAINER_URL PORTAINER_API_KEY PORTAINER_ENDPOINT_ID + PORTAINER_APP_STACK_NAME DATABASE_URL SESSION_SECRET + APP_API_ORIGIN APP_WEB_ORIGIN APP_S3_ENDPOINT + MINIO_ROOT_USER MINIO_ROOT_PASSWORD" + if [ "$SCOPE" = "full" ]; then + REQUIRED="$REQUIRED PORTAINER_DB_STACK_NAME PORTAINER_MINIO_STACK_NAME + MYSQL_PASSWORD MYSQL_ROOT_PASSWORD" + fi + missing="" + for name in $REQUIRED; do + eval "value=\${$name}" + [ -z "$value" ] && missing="$missing $name" + done + if [ -n "$missing" ]; then + echo "::error::missing repo secrets:$missing" + echo "::error::set them under Settings > Actions > Secrets" + exit 1 + fi + echo "all required secrets present for scope=$SCOPE" + # --- full only: database --------------------------------------------- - name: Deploy database stack if: ${{ github.event.inputs.scope == 'full' }}