From 377d312a843f26fb2d8ce702cd6df5edaf77d239 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 11:21:43 +0530 Subject: [PATCH 1/7] ci: fix VPS deploy guard and fingerprint config --- .github/workflows/deploy-vps.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index 911622500..f42e3d7bc 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -19,6 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Verify SHA is current tip of main + id: verify_sha env: GH_TOKEN: ${{ github.token }} run: | @@ -26,17 +27,21 @@ jobs: MAIN_SHA=$(gh api repos/${{ github.repository }}/git/ref/heads/main --jq '.object.sha') if [ "$DEPLOY_SHA" != "$MAIN_SHA" ]; then echo "Skipping: CI SHA $DEPLOY_SHA is not the current tip of main ($MAIN_SHA). Likely a stale rerun." + echo "should_deploy=false" >> "$GITHUB_OUTPUT" exit 0 fi echo "SHA verified: $DEPLOY_SHA is the current tip of main." + echo "should_deploy=true" >> "$GITHUB_OUTPUT" - name: Deploy via SSH + if: steps.verify_sha.outputs.should_deploy == 'true' uses: appleboy/ssh-action@v1.2.2 with: host: ${{ secrets.VPS_HOST }} username: root key: ${{ secrets.VPS_SSH_KEY }} - fingerprint: SHA256:Yat7fObKrTBZGxr0HGlN40oWhC/LlLN9SpjzPifsLzw + # Optional: set VPS_HOST_FINGERPRINT to enforce host key pinning. + fingerprint: ${{ secrets.VPS_HOST_FINGERPRINT }} script: | set -e DEPLOY_SHA="${{ github.event.workflow_run.head_sha }}" From 42866c6a0e33f16e2936e356a495906cdb9062e5 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:13:39 +0530 Subject: [PATCH 2/7] ci: add manual VPS deploy trigger for branch testing --- .github/workflows/deploy-vps.yml | 46 +++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index f42e3d7bc..653ddc8b2 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -1,6 +1,12 @@ name: Deploy to VPS on: + workflow_dispatch: + inputs: + deploy_sha: + description: Optional exact commit SHA to deploy. Defaults to the head of the dispatched ref. + required: false + type: string workflow_run: workflows: [CI] types: [completed] @@ -13,28 +19,47 @@ concurrency: jobs: deploy: if: >- - github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.event == 'push' && - github.event.workflow_run.head_branch == 'main' + github.event_name == 'workflow_dispatch' || + ( + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + github.event.workflow_run.head_branch == 'main' + ) runs-on: ubuntu-latest steps: - - name: Verify SHA is current tip of main - id: verify_sha + - name: Resolve deploy target + id: resolve_deploy env: GH_TOKEN: ${{ github.token }} run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + DEPLOY_SHA="${{ inputs.deploy_sha }}" + if [ -z "$DEPLOY_SHA" ]; then + DEPLOY_SHA="${GITHUB_SHA}" + fi + echo "Manual dispatch: deploying SHA $DEPLOY_SHA from ref ${GITHUB_REF_NAME}." + echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" + echo "fetch_ref=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + echo "should_deploy=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + DEPLOY_SHA="${{ github.event.workflow_run.head_sha }}" MAIN_SHA=$(gh api repos/${{ github.repository }}/git/ref/heads/main --jq '.object.sha') if [ "$DEPLOY_SHA" != "$MAIN_SHA" ]; then echo "Skipping: CI SHA $DEPLOY_SHA is not the current tip of main ($MAIN_SHA). Likely a stale rerun." + echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" + echo "fetch_ref=main" >> "$GITHUB_OUTPUT" echo "should_deploy=false" >> "$GITHUB_OUTPUT" exit 0 fi echo "SHA verified: $DEPLOY_SHA is the current tip of main." + echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" + echo "fetch_ref=main" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" - name: Deploy via SSH - if: steps.verify_sha.outputs.should_deploy == 'true' + if: steps.resolve_deploy.outputs.should_deploy == 'true' uses: appleboy/ssh-action@v1.2.2 with: host: ${{ secrets.VPS_HOST }} @@ -44,12 +69,13 @@ jobs: fingerprint: ${{ secrets.VPS_HOST_FINGERPRINT }} script: | set -e - DEPLOY_SHA="${{ github.event.workflow_run.head_sha }}" + DEPLOY_SHA="${{ steps.resolve_deploy.outputs.deploy_sha }}" + FETCH_REF="${{ steps.resolve_deploy.outputs.fetch_ref }}" cd /root/agent-orchestrator - echo "==> Fetching latest changes..." - git fetch origin main + echo "==> Fetching latest changes for $FETCH_REF..." + git fetch origin "$FETCH_REF" echo "==> Current: $(git rev-parse --short HEAD)" - echo "==> Deploying CI-passed SHA: ${DEPLOY_SHA:0:7}" + echo "==> Deploying target SHA: ${DEPLOY_SHA:0:7}" git checkout "$DEPLOY_SHA" echo "==> Updated: $(git rev-parse --short HEAD)" echo "==> Installing dependencies..." From 2a77fcd0dd65ef2a9ed46831c8594249f27cf881 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:21:00 +0530 Subject: [PATCH 3/7] ci: force full checkout on VPS deploy --- .github/workflows/deploy-vps.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index 653ddc8b2..fd1ec1855 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -72,12 +72,17 @@ jobs: DEPLOY_SHA="${{ steps.resolve_deploy.outputs.deploy_sha }}" FETCH_REF="${{ steps.resolve_deploy.outputs.fetch_ref }}" cd /root/agent-orchestrator + echo "==> Ensuring full worktree..." + if [ "$(git config --bool core.sparseCheckout || echo false)" = "true" ]; then + git sparse-checkout disable + fi echo "==> Fetching latest changes for $FETCH_REF..." git fetch origin "$FETCH_REF" echo "==> Current: $(git rev-parse --short HEAD)" echo "==> Deploying target SHA: ${DEPLOY_SHA:0:7}" - git checkout "$DEPLOY_SHA" + git checkout --force "$DEPLOY_SHA" echo "==> Updated: $(git rev-parse --short HEAD)" + test -f packages/web/server/start-all.ts echo "==> Installing dependencies..." pnpm install --frozen-lockfile echo "==> Building..." From 1c1e7e08b1b6fd14fa20716d0f0b94fb71a0bbdd Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:38:10 +0530 Subject: [PATCH 4/7] ci: add temporary VPS fingerprint helper --- .github/workflows/vps-host-fingerprint.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/vps-host-fingerprint.yml diff --git a/.github/workflows/vps-host-fingerprint.yml b/.github/workflows/vps-host-fingerprint.yml new file mode 100644 index 000000000..8e19bdd20 --- /dev/null +++ b/.github/workflows/vps-host-fingerprint.yml @@ -0,0 +1,18 @@ +name: VPS Host Fingerprint + +on: + workflow_dispatch: + +jobs: + fingerprint: + runs-on: ubuntu-latest + steps: + - name: Read VPS RSA host fingerprint + uses: appleboy/ssh-action@v1.2.2 + with: + host: ${{ secrets.VPS_HOST }} + username: root + key: ${{ secrets.VPS_SSH_KEY }} + script: | + set -e + ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub -E sha256 | awk '{print $2}' From 65e971349a4bdc489c055fae2524e2089b02d7e0 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:39:56 +0530 Subject: [PATCH 5/7] ci: add temporary deploy fingerprint recovery mode --- .github/workflows/deploy-vps.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index fd1ec1855..4cd2a5294 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -7,6 +7,11 @@ on: description: Optional exact commit SHA to deploy. Defaults to the head of the dispatched ref. required: false type: string + print_host_rsa_fingerprint: + description: Temporary recovery mode to print the VPS RSA host fingerprint and exit. + required: false + default: false + type: boolean workflow_run: workflows: [CI] types: [completed] @@ -33,11 +38,17 @@ jobs: GH_TOKEN: ${{ github.token }} run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + if [ "${{ inputs.print_host_rsa_fingerprint }}" = "true" ]; then + echo "print_host_rsa_fingerprint=true" >> "$GITHUB_OUTPUT" + echo "should_deploy=false" >> "$GITHUB_OUTPUT" + exit 0 + fi DEPLOY_SHA="${{ inputs.deploy_sha }}" if [ -z "$DEPLOY_SHA" ]; then DEPLOY_SHA="${GITHUB_SHA}" fi echo "Manual dispatch: deploying SHA $DEPLOY_SHA from ref ${GITHUB_REF_NAME}." + echo "print_host_rsa_fingerprint=false" >> "$GITHUB_OUTPUT" echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" echo "fetch_ref=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" @@ -54,10 +65,22 @@ jobs: exit 0 fi echo "SHA verified: $DEPLOY_SHA is the current tip of main." + echo "print_host_rsa_fingerprint=false" >> "$GITHUB_OUTPUT" echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" echo "fetch_ref=main" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" + - name: Read VPS RSA host fingerprint + if: steps.resolve_deploy.outputs.print_host_rsa_fingerprint == 'true' + uses: appleboy/ssh-action@v1.2.2 + with: + host: ${{ secrets.VPS_HOST }} + username: root + key: ${{ secrets.VPS_SSH_KEY }} + script: | + set -e + ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub -E sha256 | awk '{print $2}' + - name: Deploy via SSH if: steps.resolve_deploy.outputs.should_deploy == 'true' uses: appleboy/ssh-action@v1.2.2 From d0983913fc68fdb8ee570ec6987ae3e013eabafa Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:41:56 +0530 Subject: [PATCH 6/7] ci: print runner-visible VPS host fingerprints --- .github/workflows/deploy-vps.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index 4cd2a5294..fa7d35d85 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -70,16 +70,16 @@ jobs: echo "fetch_ref=main" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" - - name: Read VPS RSA host fingerprint + - name: Read runner-visible VPS host fingerprints if: steps.resolve_deploy.outputs.print_host_rsa_fingerprint == 'true' - uses: appleboy/ssh-action@v1.2.2 - with: - host: ${{ secrets.VPS_HOST }} - username: root - key: ${{ secrets.VPS_SSH_KEY }} - script: | - set -e - ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub -E sha256 | awk '{print $2}' + env: + VPS_HOST: ${{ secrets.VPS_HOST }} + run: | + set -e + for type in rsa ecdsa ed25519; do + echo "==> $type" + ssh-keyscan -T 10 -t "$type" "$VPS_HOST" 2>/dev/null | ssh-keygen -lf - -E sha256 + done - name: Deploy via SSH if: steps.resolve_deploy.outputs.should_deploy == 'true' From 1d8ed3ef8ee387159074c42e4731f5fd2f5aa656 Mon Sep 17 00:00:00 2001 From: Dhruv Sharma Date: Thu, 2 Apr 2026 12:44:50 +0530 Subject: [PATCH 7/7] ci: harden VPS deploy workflow --- .github/workflows/deploy-vps.yml | 39 +++++++++------------- .github/workflows/vps-host-fingerprint.yml | 18 ---------- 2 files changed, 16 insertions(+), 41 deletions(-) delete mode 100644 .github/workflows/vps-host-fingerprint.yml diff --git a/.github/workflows/deploy-vps.yml b/.github/workflows/deploy-vps.yml index fa7d35d85..0127041be 100644 --- a/.github/workflows/deploy-vps.yml +++ b/.github/workflows/deploy-vps.yml @@ -7,11 +7,6 @@ on: description: Optional exact commit SHA to deploy. Defaults to the head of the dispatched ref. required: false type: string - print_host_rsa_fingerprint: - description: Temporary recovery mode to print the VPS RSA host fingerprint and exit. - required: false - default: false - type: boolean workflow_run: workflows: [CI] types: [completed] @@ -36,19 +31,18 @@ jobs: id: resolve_deploy env: GH_TOKEN: ${{ github.token }} + DEPLOY_SHA_INPUT: ${{ inputs.deploy_sha }} run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - if [ "${{ inputs.print_host_rsa_fingerprint }}" = "true" ]; then - echo "print_host_rsa_fingerprint=true" >> "$GITHUB_OUTPUT" - echo "should_deploy=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - DEPLOY_SHA="${{ inputs.deploy_sha }}" + DEPLOY_SHA="$DEPLOY_SHA_INPUT" if [ -z "$DEPLOY_SHA" ]; then DEPLOY_SHA="${GITHUB_SHA}" fi + if ! printf '%s' "$DEPLOY_SHA" | grep -Eq '^[0-9a-f]{40}$'; then + echo "Invalid deploy_sha: expected a 40-character lowercase hex SHA, got '$DEPLOY_SHA'." >&2 + exit 1 + fi echo "Manual dispatch: deploying SHA $DEPLOY_SHA from ref ${GITHUB_REF_NAME}." - echo "print_host_rsa_fingerprint=false" >> "$GITHUB_OUTPUT" echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" echo "fetch_ref=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" @@ -65,35 +59,34 @@ jobs: exit 0 fi echo "SHA verified: $DEPLOY_SHA is the current tip of main." - echo "print_host_rsa_fingerprint=false" >> "$GITHUB_OUTPUT" echo "deploy_sha=$DEPLOY_SHA" >> "$GITHUB_OUTPUT" echo "fetch_ref=main" >> "$GITHUB_OUTPUT" echo "should_deploy=true" >> "$GITHUB_OUTPUT" - - name: Read runner-visible VPS host fingerprints - if: steps.resolve_deploy.outputs.print_host_rsa_fingerprint == 'true' + - name: Require VPS host fingerprint env: - VPS_HOST: ${{ secrets.VPS_HOST }} + VPS_HOST_FINGERPRINT: ${{ secrets.VPS_HOST_FINGERPRINT }} run: | set -e - for type in rsa ecdsa ed25519; do - echo "==> $type" - ssh-keyscan -T 10 -t "$type" "$VPS_HOST" 2>/dev/null | ssh-keygen -lf - -E sha256 - done + if [ -z "$VPS_HOST_FINGERPRINT" ]; then + echo "VPS_HOST_FINGERPRINT secret is required for host key verification." >&2 + exit 1 + fi - name: Deploy via SSH if: steps.resolve_deploy.outputs.should_deploy == 'true' + env: + DEPLOY_SHA: ${{ steps.resolve_deploy.outputs.deploy_sha }} + FETCH_REF: ${{ steps.resolve_deploy.outputs.fetch_ref }} uses: appleboy/ssh-action@v1.2.2 with: host: ${{ secrets.VPS_HOST }} username: root key: ${{ secrets.VPS_SSH_KEY }} - # Optional: set VPS_HOST_FINGERPRINT to enforce host key pinning. fingerprint: ${{ secrets.VPS_HOST_FINGERPRINT }} + envs: DEPLOY_SHA,FETCH_REF script: | set -e - DEPLOY_SHA="${{ steps.resolve_deploy.outputs.deploy_sha }}" - FETCH_REF="${{ steps.resolve_deploy.outputs.fetch_ref }}" cd /root/agent-orchestrator echo "==> Ensuring full worktree..." if [ "$(git config --bool core.sparseCheckout || echo false)" = "true" ]; then diff --git a/.github/workflows/vps-host-fingerprint.yml b/.github/workflows/vps-host-fingerprint.yml deleted file mode 100644 index 8e19bdd20..000000000 --- a/.github/workflows/vps-host-fingerprint.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: VPS Host Fingerprint - -on: - workflow_dispatch: - -jobs: - fingerprint: - runs-on: ubuntu-latest - steps: - - name: Read VPS RSA host fingerprint - uses: appleboy/ssh-action@v1.2.2 - with: - host: ${{ secrets.VPS_HOST }} - username: root - key: ${{ secrets.VPS_SSH_KEY }} - script: | - set -e - ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub -E sha256 | awk '{print $2}'