From 93c480ea3c736cbe1826b417f598fc6276a2aee4 Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Thu, 9 Jul 2026 08:21:02 +0200 Subject: [PATCH] Add GCP leoclean skill sync helper (#66) --- deploy/sync-gcp-leoclean-skills.sh | 107 +++++++++++++++++++++++++++++ tests/test_teleo_agent_systemd.py | 20 ++++++ 2 files changed, 127 insertions(+) create mode 100755 deploy/sync-gcp-leoclean-skills.sh diff --git a/deploy/sync-gcp-leoclean-skills.sh b/deploy/sync-gcp-leoclean-skills.sh new file mode 100755 index 0000000..b14dcad --- /dev/null +++ b/deploy/sync-gcp-leoclean-skills.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Sync source-controlled GCP leoclean skills into the GCP parallel runtime. +# +# Defaults target the non-production GCP leoclean service. This script does not +# touch the production Telegram token and does not read or print secrets. +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +PROJECT="${PROJECT:-teleo-501523}" +ZONE="${ZONE:-europe-west6-a}" +INSTANCE="${INSTANCE:-teleo-prod-1}" +SERVICE="${SERVICE:-leoclean-gcp-prod-parallel.service}" +REMOTE_SKILLS_DIR="${REMOTE_SKILLS_DIR:-/home/teleo/.hermes/profiles/leoclean/skills}" +SOURCE_DIR="${SOURCE_DIR:-$REPO_ROOT/hermes-agent/leoclean-skills/gcp}" + +DRY_RUN=false +RESTART=false +VERIFY_ONLY=false + +usage() { + cat <<'USAGE' +Usage: deploy/sync-gcp-leoclean-skills.sh [--dry-run] [--restart] [--verify-only] + +Environment overrides: + PROJECT GCP project, default teleo-501523 + ZONE GCP zone, default europe-west6-a + INSTANCE GCP VM, default teleo-prod-1 + SERVICE systemd service, default leoclean-gcp-prod-parallel.service + REMOTE_SKILLS_DIR runtime skills dir, default /home/teleo/.hermes/profiles/leoclean/skills + SOURCE_DIR local source dir, default hermes-agent/leoclean-skills/gcp +USAGE +} + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=true ;; + --restart) RESTART=true ;; + --verify-only) VERIFY_ONLY=true ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "Unknown arg: $arg" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [ ! -d "$SOURCE_DIR" ]; then + echo "ERROR: source skill directory not found: $SOURCE_DIR" >&2 + exit 1 +fi +if [ ! -f "$SOURCE_DIR/teleo-kb-bridge/SKILL.md" ]; then + echo "ERROR: source teleo-kb-bridge skill not found under $SOURCE_DIR" >&2 + exit 1 +fi + +GCP_SSH=( + gcloud compute ssh "$INSTANCE" + --project="$PROJECT" + --zone="$ZONE" + --tunnel-through-iap +) + +verify_command=$(cat <|wrap claim IDs, proposal IDs' '$REMOTE_SKILLS_DIR/teleo-kb-bridge/SKILL.md' +systemctl show '$SERVICE' -p ActiveState -p SubState -p NRestarts -p MainPID --no-pager +REMOTE +) + +if $DRY_RUN; then + echo "DRY RUN: would stream $SOURCE_DIR to $INSTANCE:$REMOTE_SKILLS_DIR" + echo "DRY RUN: project=$PROJECT zone=$ZONE service=$SERVICE restart=$RESTART verify_only=$VERIFY_ONLY" + exit 0 +fi + +if $VERIFY_ONLY; then + "${GCP_SSH[@]}" --command="$verify_command" + exit 0 +fi + +REMOTE_TMP="/tmp/teleo-gcp-leoclean-skills-$(date -u +%Y%m%dT%H%M%SZ)-$$" +sync_command=$(cat <|wrap claim IDs, proposal IDs' "\$remote_skills/teleo-kb-bridge/SKILL.md" +if [ '$RESTART' = true ]; then + sudo systemctl restart "\$service" +fi +systemctl show "\$service" -p ActiveState -p SubState -p NRestarts -p MainPID --no-pager +REMOTE +) + +COPYFILE_DISABLE=1 tar --format=ustar -C "$SOURCE_DIR" -cf - . | "${GCP_SSH[@]}" --command="$sync_command" diff --git a/tests/test_teleo_agent_systemd.py b/tests/test_teleo_agent_systemd.py index 57c51b3..f8e0101 100644 --- a/tests/test_teleo_agent_systemd.py +++ b/tests/test_teleo_agent_systemd.py @@ -90,3 +90,23 @@ def test_deploy_scripts_sync_leoclean_skills_and_restart_gateway_when_active(): assert 'VPS_LEOCLEAN_SKILLS="/home/teleo/.hermes/profiles/leoclean/skills"' in manual_deploy assert 'hermes-agent/leoclean-skills/vps/' in manual_deploy assert 'systemctl is-active --quiet leoclean-gateway.service' in manual_deploy + + +def test_gcp_leoclean_skill_sync_targets_parallel_runtime_without_secrets(): + script_path = REPO_ROOT / "deploy" / "sync-gcp-leoclean-skills.sh" + script = script_path.read_text() + + assert 'PROJECT="${PROJECT:-teleo-501523}"' in script + assert 'ZONE="${ZONE:-europe-west6-a}"' in script + assert 'INSTANCE="${INSTANCE:-teleo-prod-1}"' in script + assert 'SERVICE="${SERVICE:-leoclean-gcp-prod-parallel.service}"' in script + assert "hermes-agent/leoclean-skills/gcp" in script + assert "--tunnel-through-iap" in script + assert "/home/teleo/.hermes/profiles/leoclean/skills" in script + assert "/kb/claims/|wrap claim IDs, proposal IDs" in script + assert 'COPYFILE_DISABLE=1 tar --format=ustar -C "$SOURCE_DIR" -cf - .' in script + assert 'sudo tar -C "\\$remote_skills" -xf -' in script + assert "sudo systemctl restart" in script + assert "sudo rsync" not in script + assert "TELEGRAM_BOT_TOKEN" not in script + assert "CLOUDSQL_PASSWORD" not in script