From 453ceb002365bfa5b56229bc64fb8dec77bf31ba Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 13:40:04 -0500 Subject: [PATCH 01/10] ci: migrate staging secrets to GitHub Environment Adds `environment: Staging` to the deploy job and removes all `STAGING_` prefixes from secrets and variables, relying on environment-level scoping instead of naming conventions. Also updates docs/CI-CD/workflows.md to document the split between repository-level secrets (DockerHub) and Staging environment secrets. Closes #1767 Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/deploy-staging.yml | 27 ++++++++++++----------- docs/CI-CD/workflows.md | 32 ++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 38059a08f..af0ba2e92 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -21,26 +21,27 @@ jobs: deploy: name: Deploy release to staging runs-on: ubuntu-latest + environment: Staging steps: - name: Deploy release to staging env: # Non-sensitive - BACKEND_API_URL: ${{ vars.STAGING_BACKEND_API_URL }} - FRONTEND_URL: ${{ vars.STAGING_FRONTEND_URL }} - GOOGLE_CLIENT_ID: ${{ vars.STAGING_GOOGLE_CLIENT_ID }} + BACKEND_API_URL: ${{ vars.BACKEND_API_URL }} + FRONTEND_URL: ${{ vars.FRONTEND_URL }} + GOOGLE_CLIENT_ID: ${{ vars.GOOGLE_CLIENT_ID }} RELEASE_TAG: ${{ inputs.tag }} - SSH_USER: ${{ vars.STAGING_SSH_USER }} - SSH_HOST: ${{ vars.STAGING_SSH_HOST }} + SSH_USER: ${{ vars.SSH_USER }} + SSH_HOST: ${{ vars.SSH_HOST }} # Sensitive - COMPASS_SYNC_TOKEN: ${{ secrets.STAGING_COMPASS_SYNC_TOKEN }} - GCAL_NOTIFICATION_TOKEN: ${{ secrets.STAGING_GCAL_NOTIFICATION_TOKEN }} - GOOGLE_CLIENT_SECRET: ${{ secrets.STAGING_GOOGLE_CLIENT_SECRET }} - MONGO_PASSWORD: ${{ secrets.STAGING_MONGO_PASSWORD }} - MONGO_REPLICA_SET_KEY: ${{ secrets.STAGING_MONGO_REPLICA_SET_KEY }} - SSH_KEY: ${{ secrets.STAGING_SSH_KEY }} - SUPERTOKENS_KEY: ${{ secrets.STAGING_SUPERTOKENS_KEY }} - SUPERTOKENS_POSTGRES_PASSWORD: ${{ secrets.STAGING_SUPERTOKENS_POSTGRES_PASSWORD }} + COMPASS_SYNC_TOKEN: ${{ secrets.COMPASS_SYNC_TOKEN }} + GCAL_NOTIFICATION_TOKEN: ${{ secrets.GCAL_NOTIFICATION_TOKEN }} + GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }} + MONGO_PASSWORD: ${{ secrets.MONGO_PASSWORD }} + MONGO_REPLICA_SET_KEY: ${{ secrets.MONGO_REPLICA_SET_KEY }} + SSH_KEY: ${{ secrets.SSH_KEY }} + SUPERTOKENS_KEY: ${{ secrets.SUPERTOKENS_KEY }} + SUPERTOKENS_POSTGRES_PASSWORD: ${{ secrets.SUPERTOKENS_POSTGRES_PASSWORD }} run: | # Strip 'v' prefix for Docker image tags (v0.5.18 -> 0.5.18) IMAGE_VERSION="${RELEASE_TAG#v}" diff --git a/docs/CI-CD/workflows.md b/docs/CI-CD/workflows.md index aa9b88a2a..519268b3a 100644 --- a/docs/CI-CD/workflows.md +++ b/docs/CI-CD/workflows.md @@ -80,14 +80,34 @@ show which release triggered or motivated the deploy. Manual staging redeploys do not rebuild images. Run `Deploy staging` with an existing tag after confirming the desired image tags already exist on Docker Hub. -### Required secrets +### Required secrets and variables -All secrets go in **GitHub → Settings → Secrets and variables → Actions**: +Secrets and variables are split between repository level (shared across workflows) and the `Staging` GitHub Environment (scoped to the deploy job). -| Secret | Value | +**Repository-level** — GitHub → Settings → Secrets and variables → Actions: + +| Name | Value | |---|---| | `DOCKERHUB_USERNAME` | Docker Hub username for the `switchbacktech` org | | `DOCKERHUB_TOKEN` | Docker Hub personal access token (Read & Write) | -| `STAGING_SSH_HOST` | VPS IP address or hostname | -| `STAGING_SSH_USER` | Linux user on the VPS that owns `~/compass` | -| `STAGING_SSH_KEY` | Private key from the deploy keypair (the `compass-staging-deploy` file, not `.pub`) | + +**`Staging` environment** — GitHub → Settings → Environments → Staging: + +| Secret | Value | +|---|---| +| `SSH_KEY` | Private key from the deploy keypair (the `compass-staging-deploy` file, not `.pub`) | +| `COMPASS_SYNC_TOKEN` | Token for compass sync | +| `GCAL_NOTIFICATION_TOKEN` | Google Calendar notification token | +| `GOOGLE_CLIENT_SECRET` | OAuth client secret | +| `MONGO_PASSWORD` | MongoDB compass user password | +| `MONGO_REPLICA_SET_KEY` | MongoDB replica set key | +| `SUPERTOKENS_KEY` | SuperTokens API key | +| `SUPERTOKENS_POSTGRES_PASSWORD` | SuperTokens PostgreSQL password | + +| Variable | Value | +|---|---| +| `SSH_HOST` | VPS IP address or hostname | +| `SSH_USER` | Linux user on the VPS that owns `~/compass` | +| `BACKEND_API_URL` | Staging backend API URL | +| `FRONTEND_URL` | Staging frontend URL | +| `GOOGLE_CLIENT_ID` | OAuth client ID | From 5c1e4ac35b375f6482acc052b30b50a38c0abf4d Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 13:46:29 -0500 Subject: [PATCH 02/10] debug: add SSH auth diagnostics to staging deploy --- .github/workflows/deploy-staging.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index af0ba2e92..0abc713bd 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -50,6 +50,16 @@ jobs: echo "$SSH_KEY" > ~/.ssh/staging_key chmod 600 ~/.ssh/staging_key ssh-keyscan -H "$SSH_HOST" >> ~/.ssh/known_hosts + + # DEBUG - remove before merge + echo "=== DEBUG ===" + echo "SSH_USER: '${SSH_USER}'" + echo "SSH_HOST: '${SSH_HOST}'" + head -1 ~/.ssh/staging_key + tail -1 ~/.ssh/staging_key + wc -l ~/.ssh/staging_key + ssh -v -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" echo ok 2>&1 | grep -E "Offering|Authentications|denied|identity|key_load|Will attempt|publickey" + echo "=== END DEBUG ===" printf '%s\n' \ 'compose:' \ " version: \"${IMAGE_VERSION}\"" \ From 90a6ddaaa75568f33b542d5e6d70065058a7df78 Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 13:47:34 -0500 Subject: [PATCH 03/10] debug: print derived public key for authorized_keys comparison --- .github/workflows/deploy-staging.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 0abc713bd..1855c34f1 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -59,6 +59,8 @@ jobs: tail -1 ~/.ssh/staging_key wc -l ~/.ssh/staging_key ssh -v -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" echo ok 2>&1 | grep -E "Offering|Authentications|denied|identity|key_load|Will attempt|publickey" + echo "Public key being offered (paste this into authorized_keys on the server):" + ssh-keygen -y -f ~/.ssh/staging_key echo "=== END DEBUG ===" printf '%s\n' \ 'compose:' \ From bdf5065c850c8d99bb6546fe76679f814b1709bf Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 13:49:33 -0500 Subject: [PATCH 04/10] debug: remove SSH diagnostics --- .github/workflows/deploy-staging.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 1855c34f1..af0ba2e92 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -50,18 +50,6 @@ jobs: echo "$SSH_KEY" > ~/.ssh/staging_key chmod 600 ~/.ssh/staging_key ssh-keyscan -H "$SSH_HOST" >> ~/.ssh/known_hosts - - # DEBUG - remove before merge - echo "=== DEBUG ===" - echo "SSH_USER: '${SSH_USER}'" - echo "SSH_HOST: '${SSH_HOST}'" - head -1 ~/.ssh/staging_key - tail -1 ~/.ssh/staging_key - wc -l ~/.ssh/staging_key - ssh -v -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" echo ok 2>&1 | grep -E "Offering|Authentications|denied|identity|key_load|Will attempt|publickey" - echo "Public key being offered (paste this into authorized_keys on the server):" - ssh-keygen -y -f ~/.ssh/staging_key - echo "=== END DEBUG ===" printf '%s\n' \ 'compose:' \ " version: \"${IMAGE_VERSION}\"" \ From a5a1ae1eb57c2980d03e0398abb85dbcc4b0677e Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 13:51:40 -0500 Subject: [PATCH 05/10] debug: capture supertokens container logs on deploy failure --- .github/workflows/deploy-staging.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index af0ba2e92..aa885e52f 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -85,4 +85,10 @@ jobs: "umask 077 && mkdir -p ~/compass && cat > ~/compass/compass.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compose.yaml -o ~/compass/compose.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compass -o ~/compass/compass && chmod +x ~/compass/compass" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" || { + echo "--- supertokens logs ---" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-1 2>&1 | tail -40" || true + echo "--- supertokens-db logs ---" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-db-1 2>&1 | tail -20" || true + exit 1 + } From 1415c6d7f3365b09cb66dd249355a605007f0c28 Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 14:03:50 -0500 Subject: [PATCH 06/10] debug: add mongo log capture on failure --- .github/workflows/deploy-staging.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index aa885e52f..c3534926f 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -90,5 +90,7 @@ jobs: ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-1 2>&1 | tail -40" || true echo "--- supertokens-db logs ---" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-db-1 2>&1 | tail -20" || true + echo "--- mongo logs ---" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-mongo-1 2>&1 | tail -40" || true exit 1 } From d398939e6120a6aa0b03e2760adba15a296e003b Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 14:06:50 -0500 Subject: [PATCH 07/10] debug: add backend log capture on failure --- .github/workflows/deploy-staging.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index c3534926f..2518991e9 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -92,5 +92,7 @@ jobs: ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-db-1 2>&1 | tail -20" || true echo "--- mongo logs ---" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-mongo-1 2>&1 | tail -40" || true + echo "--- backend logs ---" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-backend-1 2>&1 | tail -60" || true exit 1 } From c1d13ae1ed2fa3b4510cbe57f1e7faf5f336650e Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 14:08:10 -0500 Subject: [PATCH 08/10] fix: chmod 644 compass.yaml so backend container can read it --- .github/workflows/deploy-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 2518991e9..49fbecea5 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -82,7 +82,7 @@ jobs: " clientSecret: \"${GOOGLE_CLIENT_SECRET}\"" \ " notificationToken: \"${GCAL_NOTIFICATION_TOKEN}\"" \ | ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" \ - "umask 077 && mkdir -p ~/compass && cat > ~/compass/compass.yaml" + "umask 077 && mkdir -p ~/compass && cat > ~/compass/compass.yaml && chmod 644 ~/compass/compass.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compose.yaml -o ~/compass/compose.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compass -o ~/compass/compass && chmod +x ~/compass/compass" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" || { From a4f29f9e7c64049cb08c33d53fec8da82ca661d0 Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 14:10:00 -0500 Subject: [PATCH 09/10] debug: verify compass.yaml permissions and backend volume mount --- .github/workflows/deploy-staging.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 49fbecea5..bcb237371 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -83,6 +83,7 @@ jobs: " notificationToken: \"${GCAL_NOTIFICATION_TOKEN}\"" \ | ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" \ "umask 077 && mkdir -p ~/compass && cat > ~/compass/compass.yaml && chmod 644 ~/compass/compass.yaml" + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "ls -la ~/compass/compass.yaml && docker inspect compass-backend-1 --format '{{json .Mounts}}' 2>/dev/null || true" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compose.yaml -o ~/compass/compose.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compass -o ~/compass/compass && chmod +x ~/compass/compass" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" || { From 5374581fb567744f21f45856bee51fde1b4b752c Mon Sep 17 00:00:00 2001 From: Tyler Dane Date: Sat, 16 May 2026 14:10:52 -0500 Subject: [PATCH 10/10] debug: remove all diagnostic steps --- .github/workflows/deploy-staging.yml | 13 +------------ docs/CI-CD/workflows.md | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index bcb237371..7ef32e8a0 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -83,17 +83,6 @@ jobs: " notificationToken: \"${GCAL_NOTIFICATION_TOKEN}\"" \ | ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" \ "umask 077 && mkdir -p ~/compass && cat > ~/compass/compass.yaml && chmod 644 ~/compass/compass.yaml" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "ls -la ~/compass/compass.yaml && docker inspect compass-backend-1 --format '{{json .Mounts}}' 2>/dev/null || true" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compose.yaml -o ~/compass/compose.yaml" ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "curl -fsSL https://raw.githubusercontent.com/SwitchbackTech/compass/${RELEASE_TAG}/self-host/compass -o ~/compass/compass && chmod +x ~/compass/compass" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" || { - echo "--- supertokens logs ---" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-1 2>&1 | tail -40" || true - echo "--- supertokens-db logs ---" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-supertokens-db-1 2>&1 | tail -20" || true - echo "--- mongo logs ---" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-mongo-1 2>&1 | tail -40" || true - echo "--- backend logs ---" - ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "docker logs compass-backend-1 2>&1 | tail -60" || true - exit 1 - } + ssh -i ~/.ssh/staging_key "$SSH_USER@$SSH_HOST" "cd ~/compass && ./compass update" diff --git a/docs/CI-CD/workflows.md b/docs/CI-CD/workflows.md index 519268b3a..d381c92bc 100644 --- a/docs/CI-CD/workflows.md +++ b/docs/CI-CD/workflows.md @@ -95,7 +95,7 @@ Secrets and variables are split between repository level (shared across workflow | Secret | Value | |---|---| -| `SSH_KEY` | Private key from the deploy keypair (the `compass-staging-deploy` file, not `.pub`) | +| `SSH_KEY` | Private key from the deploy keypair | | `COMPASS_SYNC_TOKEN` | Token for compass sync | | `GCAL_NOTIFICATION_TOKEN` | Google Calendar notification token | | `GOOGLE_CLIENT_SECRET` | OAuth client secret |