From 455917a8704cf2abd32dcd844ea931176bf0d801 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Mon, 10 Aug 2026 16:17:41 +0800 Subject: [PATCH] ops: keep production SSH sessions alive --- .gitea/workflows/deploy-production.yml | 2 +- .gitea/workflows/migrate-production-database.yml | 2 +- frontend/tests/staging-backend-workflows.test.ts | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-production.yml b/.gitea/workflows/deploy-production.yml index 8979b1e7..1a97ed24 100644 --- a/.gitea/workflows/deploy-production.yml +++ b/.gitea/workflows/deploy-production.yml @@ -322,7 +322,7 @@ jobs: printf '%s\n' "$PRODUCTION_KNOWN_HOSTS" | tr -d '\r' > "$known_hosts_path" chmod 600 "$key_path" "$known_hosts_path" ssh-keygen -y -f "$key_path" >/dev/null - ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") + ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") remote="$DEPLOY_USER@$DEPLOY_HOST" require_current_release_heads() { [[ "$ALLOW_ROLLBACK" == true ]] && return diff --git a/.gitea/workflows/migrate-production-database.yml b/.gitea/workflows/migrate-production-database.yml index 1ff7c1c9..38cef122 100644 --- a/.gitea/workflows/migrate-production-database.yml +++ b/.gitea/workflows/migrate-production-database.yml @@ -302,7 +302,7 @@ jobs: printf '%s\n' "$PRODUCTION_KNOWN_HOSTS" | tr -d '\r' > "$known_hosts_path" chmod 600 "$key_path" "$known_hosts_path" ssh-keygen -y -f "$key_path" >/dev/null - ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") + ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") remote="$DEPLOY_USER@$DEPLOY_HOST" require_current_release_heads() { current_staging="$(curl --fail --silent --show-error --connect-timeout 15 --max-time 60 --retry 3 --retry-all-errors \ diff --git a/frontend/tests/staging-backend-workflows.test.ts b/frontend/tests/staging-backend-workflows.test.ts index f0d06c8c..2c5fd760 100644 --- a/frontend/tests/staging-backend-workflows.test.ts +++ b/frontend/tests/staging-backend-workflows.test.ts @@ -967,6 +967,7 @@ test("Gitea production deploy consumes only gate-attested digests under manual c assert.match(workflow, /bash '\$incoming\/deploy\/run-production-deploy\.sh'/); assert.match(workflow, /docker ps -aq[^\n]*com\.docker\.compose\.service=web/); assert.match(workflow, /state-present-without-container/); + assert.match(workflow, /ServerAliveInterval=15.*ServerAliveCountMax=4/); assert.doesNotMatch(workflow, /then cat \"\\\$state\\\"/); assert.doesNotMatch(workflow, /docker compose[^\n]*build|db:migrate/); }); @@ -1045,6 +1046,7 @@ test("Gitea production schema migration is exact-SHA gated and isolated from ETL assert.match(workflow, /run-production-migration\.sh/); assert.match(workflow, /docker ps -aq[^\n]*com\.docker\.compose\.service=web/); assert.match(workflow, /state-present-without-container/); + assert.match(workflow, /ServerAliveInterval=15.*ServerAliveCountMax=4/); assert.doesNotMatch(workflow, /then cat "\\\$state\\"/); assert.doesNotMatch(workflow, /migrate-supabase-production|run-production-deploy|verification_mode|PRODUCTION_URL|CADDY/);