CI / ruff · mypy · pytest (pull_request) Successful in 4m3s
- infra/runner/tgit-runner: deploy/restart/remove/list по SSH forced command; аргументы не исполняются и не глобятся; архив — только файлы и папки, без «..», ≤ 20 МБ, есть main.py; health_url — только localhost - песочница: uid 10001, read-only, tmpfs noexec, cap-drop ALL, no-new-privileges, 128 МБ без swap, 0.25 CPU, 64 PID, --network none (сеть — только по egress-allow админа), лимит 10 сервисов, 2 образа - новая версия стартует рядом (-next) и заменяет старую, только став healthy; иначе удаляется, старая работает, exit 3 - бот: после push git archive изменённых services/<name>/ → runner; автору — «🚀 работает» или «⛔ не развёрнут» с логом, команде — алерт ⛔; удалённая папка → remove; «♻️ Перезапустить» в «Статусе» для админа (S-5) - examples/escape_attempts: все попытки выбраться — BLOCKED на живом Docker - install.sh, authorized_keys.example; CD бота обновляет runner на хосте Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
1.5 KiB
Bash
Executable File
44 lines
1.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Runs on the server: unpack release-<sha>.tgz, swap app/ atomically, compose up, wait for healthy.
|
|
# bash /srv/tgit/<env>/remote.sh <env> <sha> (uploaded by deploy.sh; safe to re-run)
|
|
set -euo pipefail
|
|
ENV=$1
|
|
SHA=$2
|
|
DIR=/srv/tgit/$ENV
|
|
PROJECT=tgit-$ENV
|
|
cd "$DIR"
|
|
|
|
if [ -f "release-$SHA.tgz" ]; then
|
|
rm -rf app.new && mkdir app.new && tar -xzf "release-$SHA.tgz" -C app.new && rm -f "release-$SHA.tgz"
|
|
cp .env app.new/.env
|
|
rm -rf app.old
|
|
[ -d app ] && mv app app.old
|
|
mv app.new app
|
|
fi
|
|
|
|
cd app
|
|
# Labels on the bot container, shown on its «Статус» card
|
|
export TGIT_SHA=$SHA TGIT_DEPLOYED_AT
|
|
TGIT_DEPLOYED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
docker compose -p "$PROJECT" up -d --build --remove-orphans </dev/null
|
|
|
|
status=""
|
|
for _ in $(seq 1 40); do
|
|
status=$(docker inspect -f '{{.State.Health.Status}}' "$PROJECT-bot-1" 2>/dev/null || true)
|
|
[ "$status" = healthy ] && break
|
|
sleep 3
|
|
done
|
|
if [ "$status" != healthy ]; then
|
|
echo "bot is '$status' after 2 min — last logs:" >&2
|
|
docker logs --tail 50 "$PROJECT-bot-1" >&2 || true
|
|
echo "rollback: cd $DIR && rm -rf app && mv app.old app && cd app && docker compose -p $PROJECT up -d --build" >&2
|
|
exit 1
|
|
fi
|
|
echo "$SHA" > ../REVISION
|
|
# Keep tgit-runner in step with the bot (installed once by infra/runner/install.sh; absent — nothing to update)
|
|
if [ -d /srv/tgit/runner ] && [ -w /srv/tgit/runner ]; then
|
|
install -m 755 infra/runner/tgit-runner /srv/tgit/runner/tgit-runner
|
|
fi
|
|
docker image prune -f >/dev/null
|
|
echo "bot healthy @ $SHA ($ENV)"
|