fix(ci): harden deploy SSH verification
Validators (Pushes and Pull Requests) / validate-core (push) Failing after 0s
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 12s

This commit is contained in:
2026-07-12 22:40:28 +09:00
parent 0c37bfa13c
commit 9c01c60f7c
+43 -48
View File
@@ -21,6 +21,7 @@ env:
DEPLOY_PORT: 22 DEPLOY_PORT: 22
SERVICE_NAME: quantengine SERVICE_NAME: quantengine
REPO: kjh2064/QuantEngineByItz REPO: kjh2064/QuantEngineByItz
SSH_KNOWN_HOSTS: ~/.ssh/known_hosts
jobs: jobs:
deploy: deploy:
@@ -36,19 +37,18 @@ jobs:
steps: steps:
- name: Verify SSH Key and Secrets - name: Verify SSH Key and Secrets
run: | run: |
# SSH_PRIVATE_KEY is the actual secret name registered in this repo set -euo pipefail
# (verified via GET /repos/{r}/actions/secrets -- DEPLOY_SSH_KEY_B64 /
# DEPLOY_SSH_KEY were never actually created despite CLAUDE.md
# claiming so; kept as fallback names in case they're added later).
SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}" SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}"
SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}" TOKEN="${{ secrets.GITEA_TOKEN }}"
SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}" if [ -z "$SSH_KEY" ]; then
if [ -z "$SSH_KEY" ] && [ -z "$SSH_KEY_B64" ] && [ -z "$SSH_KEY_RAW" ]; then echo "ERROR: SSH_PRIVATE_KEY secret not configured"
echo "ERROR: No SSH key secret configured (checked SSH_PRIVATE_KEY, DEPLOY_SSH_KEY_B64, DEPLOY_SSH_KEY)"
exit 1 exit 1
fi fi
[ -z "${{ secrets.GITEA_TOKEN }}" ] && { echo "ERROR: GITEA_TOKEN not configured"; exit 1; } if [ -z "$TOKEN" ]; then
echo "✓ SSH key and GITEA_TOKEN configured" echo "ERROR: GITEA_TOKEN not configured"
exit 1
fi
echo "✓ Required deployment secrets configured"
- name: Fetch Release Info - name: Fetch Release Info
id: fetch id: fetch
@@ -116,51 +116,44 @@ jobs:
- name: Setup SSH - name: Setup SSH
run: | run: |
set -euo pipefail
mkdir -p ~/.ssh mkdir -p ~/.ssh
SSH_KNOWN_HOSTS="$HOME/.ssh/known_hosts"
SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}" SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}"
SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}" if [ -z "$SSH_KEY" ]; then
SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}" echo "ERROR: SSH_PRIVATE_KEY not configured"
write_key() {
# $1 = raw secret value; auto-detects PEM vs base64
if printf '%s' "$1" | grep -q 'BEGIN.*PRIVATE KEY'; then
printf '%b\n' "$1" > ~/.ssh/deploy_key
else
printf '%s' "$1" | base64 -d > ~/.ssh/deploy_key
fi
}
if [ -n "$SSH_KEY" ]; then
write_key "$SSH_KEY"
elif [ -n "$SSH_KEY_B64" ]; then
printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/deploy_key
elif [ -n "$SSH_KEY_RAW" ]; then
write_key "$SSH_KEY_RAW"
else
echo "ERROR: No SSH key configured"
exit 1 exit 1
fi fi
if printf '%s' "$SSH_KEY" | grep -q 'BEGIN.*PRIVATE KEY'; then
printf '%b\n' "$SSH_KEY" > ~/.ssh/deploy_key
else
printf '%s' "$SSH_KEY" | base64 -d > ~/.ssh/deploy_key
fi
sed -i 's/\r$//' ~/.ssh/deploy_key sed -i 's/\r$//' ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key
ssh-keyscan -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true ssh-keyscan -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_HOST }} > "$SSH_KNOWN_HOSTS" 2>/dev/null || true
echo "✓ SSH configured" echo "✓ SSH configured"
- name: Upload Release Artifact - name: Upload Release Artifact
run: | run: |
SSH_KNOWN_HOSTS="$HOME/.ssh/known_hosts"
ARTIFACT="${{ steps.fetch.outputs.artifact }}" ARTIFACT="${{ steps.fetch.outputs.artifact }}"
echo "Uploading: $ARTIFACT" echo "Uploading: $ARTIFACT"
ls -lh "$ARTIFACT" ls -lh "$ARTIFACT"
scp -i ~/.ssh/deploy_key \ scp -i ~/.ssh/deploy_key \
-P ${{ env.DEPLOY_PORT }} \ -P ${{ env.DEPLOY_PORT }} \
-o StrictHostKeyChecking=accept-new \ -o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="${SSH_KNOWN_HOSTS}" \
-o ConnectTimeout=10 \ -o ConnectTimeout=10 \
"$ARTIFACT" ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/ "$ARTIFACT" ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }}:/tmp/
echo "✓ Release artifact uploaded" echo "✓ Release artifact uploaded"
- name: Deploy & Verify - name: Deploy & Verify
run: | run: |
SSH_KNOWN_HOSTS="$HOME/.ssh/known_hosts"
ARTIFACT="${{ steps.fetch.outputs.artifact }}" ARTIFACT="${{ steps.fetch.outputs.artifact }}"
RELEASE_TAG="${{ steps.fetch.outputs.tag }}" RELEASE_TAG="${{ steps.fetch.outputs.tag }}"
COMMIT="${{ steps.fetch.outputs.commit }}" COMMIT="${{ steps.fetch.outputs.commit }}"
@@ -178,7 +171,9 @@ jobs:
# remote script's environment. # remote script's environment.
ssh -i ~/.ssh/deploy_key \ ssh -i ~/.ssh/deploy_key \
-p ${{ env.DEPLOY_PORT }} \ -p ${{ env.DEPLOY_PORT }} \
-o StrictHostKeyChecking=accept-new \ -o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="${SSH_KNOWN_HOSTS}" \
-o ConnectTimeout=10 \ -o ConnectTimeout=10 \
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} \ ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} \
"ARTIFACT='$ARTIFACT' RELEASE_TAG='$RELEASE_TAG' COMMIT='$COMMIT' SERVICE_NAME='$SERVICE_NAME' bash -s" << 'REMOTE' "ARTIFACT='$ARTIFACT' RELEASE_TAG='$RELEASE_TAG' COMMIT='$COMMIT' SERVICE_NAME='$SERVICE_NAME' bash -s" << 'REMOTE'
@@ -234,28 +229,26 @@ jobs:
steps: steps:
- name: Setup SSH (for service check) - name: Setup SSH (for service check)
run: | run: |
set -euo pipefail
mkdir -p ~/.ssh mkdir -p ~/.ssh
SSH_KNOWN_HOSTS="$HOME/.ssh/known_hosts"
SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}" SSH_KEY="${{ secrets.SSH_PRIVATE_KEY }}"
SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}" if [ -z "$SSH_KEY" ]; then
SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}" echo "ERROR: SSH_PRIVATE_KEY not configured"
exit 1
if [ -n "$SSH_KEY" ]; then fi
if printf '%s' "$SSH_KEY" | grep -q 'BEGIN.*PRIVATE KEY'; then if printf '%s' "$SSH_KEY" | grep -q 'BEGIN.*PRIVATE KEY'; then
printf '%b\n' "$SSH_KEY" > ~/.ssh/deploy_key printf '%b\n' "$SSH_KEY" > ~/.ssh/deploy_key
else else
printf '%s' "$SSH_KEY" | base64 -d > ~/.ssh/deploy_key printf '%s' "$SSH_KEY" | base64 -d > ~/.ssh/deploy_key
fi
elif [ -n "$SSH_KEY_B64" ]; then
printf '%s' "$SSH_KEY_B64" | base64 -d > ~/.ssh/deploy_key
elif [ -n "$SSH_KEY_RAW" ]; then
printf '%s' "$SSH_KEY_RAW" | base64 -d > ~/.ssh/deploy_key
fi fi
chmod 600 ~/.ssh/deploy_key 2>/dev/null || true chmod 600 ~/.ssh/deploy_key 2>/dev/null || true
ssh-keyscan -p 22 ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || true ssh-keyscan -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_HOST }} > "$SSH_KNOWN_HOSTS" 2>/dev/null || true
- name: Health Check - name: Health Check
run: | run: |
SSH_KNOWN_HOSTS="$HOME/.ssh/known_hosts"
# IMPORTANT: quantengine.service binds ASPNETCORE_URLS to # IMPORTANT: quantengine.service binds ASPNETCORE_URLS to
# http://127.0.0.1:5000 (loopback only) -- Nginx is the only # http://127.0.0.1:5000 (loopback only) -- Nginx is the only
# thing that reaches it from outside, via quant.taxbaik.com. # thing that reaches it from outside, via quant.taxbaik.com.
@@ -272,7 +265,9 @@ jobs:
# checks already correctly do via SSH. # checks already correctly do via SSH.
ssh -i ~/.ssh/deploy_key \ ssh -i ~/.ssh/deploy_key \
-p ${{ env.DEPLOY_PORT }} \ -p ${{ env.DEPLOY_PORT }} \
-o StrictHostKeyChecking=accept-new \ -o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile="${SSH_KNOWN_HOSTS}" \
-o ConnectTimeout=10 \ -o ConnectTimeout=10 \
${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} bash -s << 'REMOTE' ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} bash -s << 'REMOTE'
set -e set -e