From ff574aa710f8358404cf67c548ae864ebdde9f17 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 22 Jun 2026 22:51:53 -0700 Subject: [PATCH] Add safe-deploy.sh: Python-based env parser, handles special chars in .env values safely. Remove legacy shell deploy scripts superseded by pipeline. --- .woodpecker.yml | 5 ++- deploy/git.sh | 5 --- deploy/media.sh | 4 --- deploy/safe-deploy.sh | 36 +++++++++++++++++++++ deploy/woodpecker-setup.sh | 65 -------------------------------------- 5 files changed, 38 insertions(+), 77 deletions(-) delete mode 100644 deploy/git.sh delete mode 100644 deploy/media.sh create mode 100755 deploy/safe-deploy.sh delete mode 100644 deploy/woodpecker-setup.sh diff --git a/.woodpecker.yml b/.woodpecker.yml index 2b31c37..91e9caa 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -165,6 +165,7 @@ steps: - echo "$SSH_KEY" | base64 -d > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - ssh-keyscan -H 192.168.4.32 >> ~/.ssh/known_hosts 2>/dev/null + - scp -o StrictHostKeyChecking=no deploy/safe-deploy.sh root@192.168.4.32:/tmp/sd.sh - | YAML_FILES=$(echo "${CI_COMMIT_CHANGED_FILES}" | tr ',' '\n' | grep '\.yaml$' || true) [ -z "$YAML_FILES" ] && echo "No yaml files changed" && exit 0 @@ -174,9 +175,7 @@ steps: rsync -av -e "ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa" \ "$f" root@192.168.4.32:/volume1/docker/compose-files/ ssh -o StrictHostKeyChecking=no root@192.168.4.32 \ - "cd /volume1/docker/compose-files \ - && if [ -f ${STACK}.env ]; then set -a; . ./${STACK}.env; set +a; fi \ - && docker stack deploy -c ${STACK}.yaml ${STACK}" \ + "python3 /tmp/sd.sh ${STACK}" \ && echo " OK $STACK" || { echo " FAIL $STACK"; exit 1; } done secrets: [ ssh_key ] diff --git a/deploy/git.sh b/deploy/git.sh deleted file mode 100644 index 7a97529..0000000 --- a/deploy/git.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Deploy script for git stack -cd /volume1/docker/compose-files -set -a && . ./git.env && set +a -docker stack deploy git -c git.yaml "$@" diff --git a/deploy/media.sh b/deploy/media.sh deleted file mode 100644 index 5837de6..0000000 --- a/deploy/media.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -cd /volume1/docker/compose-files -set -a && . ./media.env && set +a -docker stack deploy media -c media.yaml "$@" diff --git a/deploy/safe-deploy.sh b/deploy/safe-deploy.sh new file mode 100755 index 0000000..04a798c --- /dev/null +++ b/deploy/safe-deploy.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# safe-deploy.sh — Safe Docker Stack deployer with .env support +# Usage: python3 deploy/safe-deploy.sh [compose-dir] +# Parses .env safely — no shell interpretation of special chars +import subprocess, sys, os + +def parse_env_file(path): + env = {} + with open(path) as f: + for line in f: + line = line.rstrip('\n') + if not line.strip() or line.strip().startswith('#'): continue + if '=' not in line: continue + key, _, value = line.partition('=') + key = key.strip(); value = value.strip() + if len(value) >= 2: + if (value[0]=="'" and value[-1]=="'") or (value[0]=='"' and value[-1]=='"'): + value = value[1:-1] + env[key] = value + return env + +def main(): + if len(sys.argv) < 2: print("Usage: safe-deploy.sh [dir]"); sys.exit(1) + stack = sys.argv[1] + d = sys.argv[2] if len(sys.argv)>2 else "/volume1/docker/compose-files" + yp = os.path.join(d, stack+".yaml") + ep = os.path.join(d, stack+".env") + if not os.path.exists(yp): print(f"ERROR: {yp} not found"); sys.exit(1) + env = dict(os.environ) + if os.path.exists(ep): parsed=parse_env_file(ep); print(f" Loaded {len(parsed)} vars"); env.update(parsed) + else: print(f" No {stack}.env - deploying without overlay") + cmd=["docker","stack","deploy","-c",yp,stack] + print(f" Running: {chr(32).join(cmd)}") + sys.exit(subprocess.run(cmd,env=env,cwd=d).returncode) + +if __name__=="__main__": main() diff --git a/deploy/woodpecker-setup.sh b/deploy/woodpecker-setup.sh deleted file mode 100644 index 8ae9def..0000000 --- a/deploy/woodpecker-setup.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# Setup script for Woodpecker CI/CD -# Run this before deploying woodpecker.yaml - -set -e - -echo "🔧 Woodpecker Setup Script" -echo "==========================" -echo "" - -# Step 1: Database setup -echo "Step 1: Creating PostgreSQL database and user..." - -WOODPECKER_DB_USER=${1:-woodpecker} -WOODPECKER_DB_PASS=${2:-changeme} - -docker exec -it $(docker ps -q -f "label=com.docker.compose.service=postgresql") psql -U postgres << SQL --- Drop if exists (be careful!) -DROP DATABASE IF EXISTS woodpecker; -DROP USER IF EXISTS woodpecker; - --- Create fresh database -CREATE DATABASE woodpecker; -CREATE USER $WOODPECKER_DB_USER WITH PASSWORD '$WOODPECKER_DB_PASS'; -GRANT ALL PRIVILEGES ON DATABASE woodpecker TO $WOODPECKER_DB_USER; - --- Switch to woodpecker DB and grant schema access -\c woodpecker -GRANT ALL ON SCHEMA public TO $WOODPECKER_DB_USER; - -\q -SQL - -echo "✅ Database created" -echo "" - -# Step 2: Generate agent secret -echo "Step 2: Generating Agent Secret..." -AGENT_SECRET=$(openssl rand -hex 32) -echo "Agent Secret: $AGENT_SECRET" -echo "" - -# Step 3: Instructions -echo "Step 3: Next Steps" -echo "==================" -echo "1. Go to Gitea: https://git.bryanmail.net" -echo "2. Settings → Applications → OAuth2 Applications" -echo "3. Create New OAuth2 Application:" -echo " - Name: Woodpecker" -echo " - Redirect URI: https://woodpecker.bryanmail.net/authorize" -echo "4. Copy Client ID and Secret" -echo "" -echo "5. Update woodpecker.env with:" -echo " WOODPECKER_GITEA_CLIENT=" -echo " WOODPECKER_GITEA_SECRET=" -echo " WOODPECKER_AGENT_SECRET=$AGENT_SECRET" -echo " DB_USER=$WOODPECKER_DB_USER" -echo " DB_PASS=$WOODPECKER_DB_PASS" -echo "" -echo "6. Deploy:" -echo " docker stack deploy -c woodpecker.yaml woodpecker" -echo "" -echo "7. Access:" -echo " https://woodpecker.bryanmail.net" -echo ""