diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bb4954579..39c418f68 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -212,7 +212,11 @@ jobs: run: | set -euo pipefail - required_client_id="$EXPECTED_CLIENT_ID" + configured_expected_client_id="${EXPECTED_CLIENT_ID:-}" + if [ -z "$configured_expected_client_id" ]; then + echo "::error::Missing required secret WEBAPP_EXPECTED_CLIENT_ID" + exit 1 + fi base_url=$(node -e 'const u = new URL(process.env.WEBHOOK_URL); console.log(`${u.protocol}//${u.host}`)') auth_url="${base_url}/api/auth/discord" auth_config_url="${base_url}/api/health/auth-config" @@ -248,20 +252,21 @@ jobs: ' )" - expected_client_id="$(echo "$expected_values" | sed -n '1p')" + auth_config_client_id="$(echo "$expected_values" | sed -n '1p')" expected_redirect_uri="$(echo "$expected_values" | sed -n '2p')" - if [ -z "$expected_client_id" ] || [ -z "$expected_redirect_uri" ]; then + if [ -z "$auth_config_client_id" ] || [ -z "$expected_redirect_uri" ]; then echo "::error::Unable to derive OAuth expectations from auth-config payload" exit 1 fi - if [ "$expected_client_id" != "$required_client_id" ]; then - echo "::error::Auth-config client_id does not match WEBAPP_EXPECTED_CLIENT_ID" - echo "::error::expected=$required_client_id actual=$expected_client_id" + if [ "$auth_config_client_id" != "$configured_expected_client_id" ]; then + echo "::error::Auth-config client_id (${auth_config_client_id}) does not match WEBAPP_EXPECTED_CLIENT_ID secret" exit 1 fi + expected_client_id="$configured_expected_client_id" + echo "==> Running OAuth redirect contract smoke check: $auth_url" for attempt in $(seq 1 18); do diff --git a/CHANGELOG.md b/CHANGELOG.md index f968828b0..d41c7fbd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - GitGuardian incident hardening: removed hardcoded compose PostgreSQL password fallbacks, enforced secret-managed expected client-id checks in deploy OAuth smoke validation, and replaced secret-like literals in test/example fixtures +- Deploy workflow OAuth smoke now fails fast when + `WEBAPP_EXPECTED_CLIENT_ID` is missing and reports explicit auth-config + client-id mismatches. - Bundle-size CI workflow now exports `YOUTUBE_DL_SKIP_DOWNLOAD=true` (with workflow token) so `youtube-dl-exec` postinstall no longer fails on anonymous GitHub API rate limits during `npm ci` diff --git a/README.md b/README.md index 01e88ec54..49738365a 100644 --- a/README.md +++ b/README.md @@ -349,9 +349,9 @@ See `.env.example` for all available options. Key variables: | `REDIS_HOST` | No | Redis host (default: localhost) | | `WEBAPP_ENABLED` | No | Enable web dashboard (default: false) | | `WEBAPP_SESSION_SECRET` | No | Session encryption key | -| `WEBAPP_REDIRECT_URI` | No | Explicit Discord OAuth callback URL (must match Discord app settings and deploy smoke contract); fallback callback source when `WEBAPP_BACKEND_URL` is unset | -| `WEBAPP_EXPECTED_CLIENT_ID` | No | Expected Discord app client id for `/api/health/auth-config` mismatch detection when explicitly set | -| `WEBAPP_BACKEND_URL` | No | Public backend/API origin used as canonical host for backend links and bot Last.fm connect links (must be an absolute HTTP(S) URL; recommended production canonical: `https://lucky-api.lucassantana.tech`) | +| `WEBAPP_REDIRECT_URI` | No | Explicit Discord OAuth callback URL (must match Discord app settings and deploy smoke contract) | +| `WEBAPP_EXPECTED_CLIENT_ID` | No | Expected Discord app client id for `/api/health/auth-config` mismatch detection when explicitly set (recommended via deployment secret) | +| `WEBAPP_BACKEND_URL` | No | Public backend/API origin used for backend links and bot Last.fm connect links (must be an absolute HTTP(S) URL; recommended: `https://lucky-api.lucassantana.tech`) | | `CLIENT_SECRET` | No | Discord OAuth secret (for dashboard) | | `SENTRY_DSN` | No | Error tracking |