Skip to content

fix: avoid ssh-compute key parsing in deploy workflow #77

fix: avoid ssh-compute key parsing in deploy workflow

fix: avoid ssh-compute key parsing in deploy workflow #77

Workflow file for this run

name: Deploy and Keep Active
on:
push:
branches: [ main ]
# Runs automatically every day at 0:00 UTC (8:00 AM Beijing Time)
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
env:
GCE_USER: ${{ secrets.GCE_USER || 'zwlddx0815' }}
GCE_INSTANCE_NAME: ${{ secrets.GCE_INSTANCE_NAME || 'interactive-brokers-quant-instance' }}
GCE_ZONE: ${{ secrets.GCE_ZONE || 'us-east1-c' }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH || '/home/zwlddx0815/ib-docker' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v3
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v3
with:
project_id: ${{ steps.auth.outputs.project_id }}
version: '>= 416.0.0'
- name: Prepare SSH key and deployment files
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
TWS_USERID: ${{ secrets.TWS_USERID }}
TWS_PASSWORD: ${{ secrets.TWS_PASSWORD }}
TOTP_SECRET: ${{ secrets.TOTP_SECRET }}
VNC_SERVER_PASSWORD: ${{ secrets.VNC_SERVER_PASSWORD }}
TRADING_MODE: ${{ secrets.TRADING_MODE }}
ACCEPT_API_FROM_IP: ${{ secrets.ACCEPT_API_FROM_IP || '10.8.0.0/28' }}
ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY: ${{ secrets.ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY || 'no' }}
run: |
set -euo pipefail
install -d -m 700 "$RUNNER_TEMP/ssh"
SSH_KEY_FILE="$RUNNER_TEMP/ssh/google_compute_engine"
printf '%s\n' "$SSH_PRIVATE_KEY" | tr -d '\r' > "$SSH_KEY_FILE"
chmod 600 "$SSH_KEY_FILE"
echo "SSH_KEY_FILE=$SSH_KEY_FILE" >> "$GITHUB_ENV"
ENV_FILE="$RUNNER_TEMP/ibkr-gateway.env"
export ENV_FILE
python3 - <<'PY'
import os
env_file = os.environ["ENV_FILE"]
keys = [
"TWS_USERID",
"TWS_PASSWORD",
"TOTP_SECRET",
"VNC_SERVER_PASSWORD",
"TRADING_MODE",
"ACCEPT_API_FROM_IP",
"ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY",
]
def quote(value: str) -> str:
return "'" + value.replace("'", "'\"'\"'") + "'"
with open(env_file, "w", encoding="utf-8") as fh:
for key in keys:
fh.write(f"{key}={quote(os.environ[key])}\n")
PY
echo "ENV_FILE=$ENV_FILE" >> "$GITHUB_ENV"
DEPLOY_SCRIPT="$RUNNER_TEMP/ibkr-gateway-deploy.sh"
cat > "$DEPLOY_SCRIPT" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
cd "${DEPLOY_PATH}"
sudo docker compose build
sudo docker compose down
sudo docker compose up -d
echo "Waiting for container to stabilize..."
sleep 30
sudo bash ./scripts/install_2fa_bot_watcher.sh
sleep 5
sudo systemctl status ibkr-2fa-bot.timer --no-pager
echo "Deployment complete. Bot is monitoring the login window."
echo "Run 'docker exec ib-gateway tail -f /home/ibgateway/2fa.log' for real-time status."
EOF
chmod 700 "$DEPLOY_SCRIPT"
echo "DEPLOY_SCRIPT=$DEPLOY_SCRIPT" >> "$GITHUB_ENV"
- name: Deploy and Log Setup
run: |
set -euo pipefail
REMOTE_TARGET="${GCE_USER}@${GCE_INSTANCE_NAME}"
REMOTE_SYNC_COMMAND=$(cat <<EOF
set -euo pipefail
sudo mkdir -p '${DEPLOY_PATH}'
sudo chown -R '${GCE_USER}':'${GCE_USER}' '${DEPLOY_PATH}'
if [ -d '${DEPLOY_PATH}/.git' ]; then
cd '${DEPLOY_PATH}'
git fetch --all
git reset --hard origin/main
else
rm -rf '${DEPLOY_PATH}'
git clone 'https://github.com/${{ github.repository }}.git' '${DEPLOY_PATH}'
fi
EOF
)
gcloud compute ssh "${REMOTE_TARGET}" \
--project "${{ steps.auth.outputs.project_id }}" \
--zone "${GCE_ZONE}" \
--quiet \
--tunnel-through-iap \
--ssh-key-file "${SSH_KEY_FILE}" \
--command "${REMOTE_SYNC_COMMAND}"
gcloud compute scp "${ENV_FILE}" "${REMOTE_TARGET}:${DEPLOY_PATH}/.env" \
--project "${{ steps.auth.outputs.project_id }}" \
--zone "${GCE_ZONE}" \
--quiet \
--tunnel-through-iap \
--ssh-key-file "${SSH_KEY_FILE}"
gcloud compute scp "${DEPLOY_SCRIPT}" "${REMOTE_TARGET}:${DEPLOY_PATH}/ibkr-gateway-deploy.sh" \
--project "${{ steps.auth.outputs.project_id }}" \
--zone "${GCE_ZONE}" \
--quiet \
--tunnel-through-iap \
--ssh-key-file "${SSH_KEY_FILE}"
gcloud compute ssh "${REMOTE_TARGET}" \
--project "${{ steps.auth.outputs.project_id }}" \
--zone "${GCE_ZONE}" \
--quiet \
--tunnel-through-iap \
--ssh-key-file "${SSH_KEY_FILE}" \
--command "export DEPLOY_PATH='${DEPLOY_PATH}' && bash '${DEPLOY_PATH}/ibkr-gateway-deploy.sh' && rm -f '${DEPLOY_PATH}/ibkr-gateway-deploy.sh'"