ci: require valid DEPLOY_SSH_KEY_B64 and decode robustly #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to server | |
| on: | |
| push: | |
| branches: ["main"] | |
| workflow_dispatch: {} | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: deploy-thingspanel-adapter-http | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-deploy: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| - name: Build | |
| run: | | |
| set -e | |
| go mod tidy | |
| mkdir -p dist | |
| CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/thingspanel-adapter-http ./cmd | |
| ./dist/thingspanel-adapter-http --help >/dev/null 2>&1 || true | |
| - name: Prepare SSH key | |
| env: | |
| DEPLOY_SSH_KEY_B64: ${{ secrets.DEPLOY_SSH_KEY_B64 }} | |
| DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} | |
| run: | | |
| set -euo pipefail | |
| umask 077 | |
| mkdir -p ~/.ssh | |
| chmod 700 ~/.ssh | |
| # Create file with safe permissions first (prevents OpenSSH "bad permissions") | |
| install -m 600 /dev/null ~/.ssh/id_ed25519 | |
| if [ -n "${DEPLOY_SSH_KEY_B64:-}" ]; then | |
| # Secrets can sometimes pick up whitespace/newlines; sanitize before decoding. | |
| b64_clean="$(printf "%s" "$DEPLOY_SSH_KEY_B64" | tr -d '\r\n ' )" | |
| # Decode (fail hard with a clear message; avoids silently using a broken fallback) | |
| if ! printf "%s" "$b64_clean" | base64 --decode > ~/.ssh/id_ed25519; then | |
| echo "ERROR: DEPLOY_SSH_KEY_B64 is not valid base64. Recreate it with: base64 -w0 /root/.ssh/<your_keyfile>" >&2 | |
| exit 1 | |
| fi | |
| else | |
| echo "ERROR: DEPLOY_SSH_KEY_B64 secret is empty/missing" >&2 | |
| exit 1 | |
| fi | |
| chmod 600 ~/.ssh/id_ed25519 | |
| ssh-keygen -lf ~/.ssh/id_ed25519 >/dev/null | |
| - name: Upload binary + default config to /tmp (scp) | |
| env: | |
| DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} | |
| DEPLOY_USER: ${{ secrets.DEPLOY_USER }} | |
| DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || 22 }} | |
| run: | | |
| set -euo pipefail | |
| ssh -p "$DEPLOY_PORT" -o StrictHostKeyChecking=no "$DEPLOY_USER@$DEPLOY_HOST" "mkdir -p /tmp/thingspanel-adapter-http" | |
| scp -P "$DEPLOY_PORT" -o StrictHostKeyChecking=no dist/thingspanel-adapter-http "$DEPLOY_USER@$DEPLOY_HOST:/tmp/thingspanel-adapter-http/thingspanel-adapter-http" | |
| # Upload default config from repo (will only be installed on server if missing) | |
| scp -P "$DEPLOY_PORT" -o StrictHostKeyChecking=no configs/config.yaml "$DEPLOY_USER@$DEPLOY_HOST:/tmp/thingspanel-adapter-http/config.yaml" | |
| - name: Ensure service + restart (sudo) | |
| env: | |
| DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} | |
| DEPLOY_USER: ${{ secrets.DEPLOY_USER }} | |
| DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || 22 }} | |
| run: | | |
| set -euo pipefail | |
| ssh -p "$DEPLOY_PORT" -o StrictHostKeyChecking=no "$DEPLOY_USER@$DEPLOY_HOST" 'set -e | |
| sudo install -d /opt/thingspanel/bin | |
| sudo install -m 0755 /tmp/thingspanel-adapter-http/thingspanel-adapter-http /opt/thingspanel/bin/thingspanel-adapter-http | |
| # Ensure runtime directory exists (for configs/logs). We do NOT overwrite configs here. | |
| sudo install -d /opt/thingspanel/thingspanel-adapter-http | |
| sudo install -d /opt/thingspanel/thingspanel-adapter-http/configs | |
| # Install default config on first deploy only (do not overwrite user config) | |
| if [ ! -f /opt/thingspanel/thingspanel-adapter-http/configs/config.yaml ]; then | |
| sudo install -m 0644 /tmp/thingspanel-adapter-http/config.yaml /opt/thingspanel/thingspanel-adapter-http/configs/config.yaml | |
| fi | |
| if [ ! -f /etc/systemd/system/thingspanel-adapter-http.service ]; then | |
| sudo tee /etc/systemd/system/thingspanel-adapter-http.service >/dev/null <<"EOF" | |
| [Unit] | |
| Description=ThingsPanel Adapter HTTP | |
| After=network-online.target | |
| Wants=network-online.target | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=/opt/thingspanel/thingspanel-adapter-http | |
| ExecStart=/opt/thingspanel/bin/thingspanel-adapter-http --config /opt/thingspanel/thingspanel-adapter-http/configs/config.yaml | |
| Restart=always | |
| RestartSec=3 | |
| LimitNOFILE=65535 | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| sudo systemctl daemon-reload | |
| sudo systemctl enable thingspanel-adapter-http | |
| fi | |
| sudo systemctl restart thingspanel-adapter-http | |
| sudo systemctl --no-pager -l status thingspanel-adapter-http || true | |
| sudo journalctl -u thingspanel-adapter-http --no-pager -n 200 || true | |
| ' | |
| # Collect remote logs into a downloadable artifact so you don't have to copy/paste. | |
| - name: Collect remote logs | |
| if: ${{ always() }} | |
| env: | |
| DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} | |
| DEPLOY_USER: ${{ secrets.DEPLOY_USER }} | |
| DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || 22 }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p artifacts | |
| ssh -p "$DEPLOY_PORT" -o StrictHostKeyChecking=no "$DEPLOY_USER@$DEPLOY_HOST" '( | |
| echo "### date"; date -Is; | |
| echo; echo "### uname"; uname -a; | |
| echo; echo "### systemctl status"; systemctl --no-pager -l status thingspanel-adapter-http || true; | |
| echo; echo "### journalctl (last 400 lines)"; journalctl -u thingspanel-adapter-http --no-pager -n 400 || true; | |
| )' > artifacts/remote-logs.txt | |
| - name: Upload deploy logs artifact | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: deploy-logs | |
| path: artifacts/remote-logs.txt | |
| retention-days: 7 |