From 8558fd6b4030724f535e978857d412af2850981d Mon Sep 17 00:00:00 2001 From: Deeman Date: Mon, 23 Feb 2026 18:23:19 +0100 Subject: [PATCH] feat: no-root deploy, remove CI deploy stage, deploy alerts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deploy.sh installs sops/age to ./bin/ (no root/sudo needed) - Remove CI deploy stage — supervisor auto-pulls and deploys (zero CI secrets: no SSH keys, no deploy credentials) - Supervisor sends alert on deploy success/failure via webhook Co-Authored-By: Claude Opus 4.6 --- .gitignore | 4 ++-- .gitlab-ci.yml | 19 +++---------------- deploy.sh | 19 ++++++++++++------- src/padelnomics/supervisor.py | 6 +++++- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 24fcb96..df3ed51 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,6 @@ dist/ build/ *.egg-info/ -# Tailwind CSS -bin/tailwindcss +# Local binaries (tailwindcss, sops, age) +bin/ web/src/padelnomics/static/css/output.css diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 79e08f4..96e8323 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,5 @@ stages: - test - - deploy test: stage: test @@ -15,18 +14,6 @@ test: - if: $CI_COMMIT_BRANCH == "master" - if: $CI_PIPELINE_SOURCE == "merge_request_event" -deploy: - stage: deploy - image: alpine:latest - needs: [test] - rules: - - if: $CI_COMMIT_BRANCH == "master" - before_script: - - apk add --no-cache openssh-client - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts - script: - - ssh "$DEPLOY_USER@$DEPLOY_HOST" "cd /opt/padelnomics && git pull origin master && ./deploy.sh" +# Deployment is handled by the on-server supervisor (src/padelnomics/supervisor.py). +# It polls git every 60s, detects code changes, and runs deploy.sh automatically. +# No CI secrets needed — zero SSH keys, zero deploy credentials. diff --git a/deploy.sh b/deploy.sh index 421133d..0c87b53 100755 --- a/deploy.sh +++ b/deploy.sh @@ -2,6 +2,11 @@ set -euo pipefail # ── Ensure sops + age are installed ─────────────────────── +APP_DIR="$(cd "$(dirname "$0")" && pwd)" +BIN_DIR="$APP_DIR/bin" +mkdir -p "$BIN_DIR" +export PATH="$BIN_DIR:$PATH" + ARCH=$(uname -m) case "$ARCH" in x86_64) ARCH_SOPS="amd64"; ARCH_AGE="amd64" ;; @@ -10,23 +15,23 @@ case "$ARCH" in esac if ! command -v age &>/dev/null; then - echo "==> Installing age..." + echo "==> Installing age to $BIN_DIR..." AGE_VERSION="v1.3.1" curl -fsSL "https://dl.filippo.io/age/${AGE_VERSION}?for=linux/${ARCH_AGE}" -o /tmp/age.tar.gz - tar -xzf /tmp/age.tar.gz -C /usr/local/bin --strip-components=1 age/age age/age-keygen - chmod +x /usr/local/bin/age /usr/local/bin/age-keygen + tar -xzf /tmp/age.tar.gz -C "$BIN_DIR" --strip-components=1 age/age age/age-keygen + chmod +x "$BIN_DIR/age" "$BIN_DIR/age-keygen" rm /tmp/age.tar.gz fi if ! command -v sops &>/dev/null; then - echo "==> Installing sops..." + echo "==> Installing sops to $BIN_DIR..." SOPS_VERSION="v3.12.1" - curl -fsSL "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.${ARCH_SOPS}" -o /usr/local/bin/sops - chmod +x /usr/local/bin/sops + curl -fsSL "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.${ARCH_SOPS}" -o "$BIN_DIR/sops" + chmod +x "$BIN_DIR/sops" fi # ── Ensure age keypair exists ───────────────────────────── -AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-/opt/padelnomics/age-key.txt}" +AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-$APP_DIR/age-key.txt}" export SOPS_AGE_KEY_FILE="$AGE_KEY_FILE" if [ ! -f "$AGE_KEY_FILE" ]; then diff --git a/src/padelnomics/supervisor.py b/src/padelnomics/supervisor.py index e864f05..55f8fef 100644 --- a/src/padelnomics/supervisor.py +++ b/src/padelnomics/supervisor.py @@ -321,7 +321,11 @@ def tick() -> None: # Deploy web app if code changed if os.getenv("SUPERVISOR_GIT_PULL") and web_code_changed(): logger.info("Web code changed — deploying") - run_shell("./deploy.sh") + ok, _ = run_shell("./deploy.sh") + if ok: + send_alert("Deploy succeeded") + else: + send_alert("Deploy FAILED — check journalctl -u padelnomics-supervisor") finally: conn.close()