#!/bin/bash set -e cd "$(dirname "$0")/.." # Configuration FQDN="doot.terst.org" SITE_DIR="/site/${FQDN}" SERVICE="task-dashboard@${FQDN}" DEPLOY_HOST="tungsten" if [ "$(hostname)" != "${DEPLOY_HOST}" ]; then echo "Refusing to deploy: this is $(hostname), not ${DEPLOY_HOST}." >&2 exit 1 fi echo "==> Building CSS..." npm run css:build echo "==> Building binary..." BUILD_COMMIT=$(git rev-parse --short HEAD) BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ') LDFLAGS="-X main.buildCommit=${BUILD_COMMIT} -X main.buildTime=${BUILD_TIME}" go build -ldflags "$LDFLAGS" -o app cmd/dashboard/main.go echo "==> Stopping service..." systemctl stop ${SERVICE} || true echo "==> Syncing assets and migrations to ${SITE_DIR}..." # Sync static files rsync -av --delete web/static/ ${SITE_DIR}/public/ # Sync templates rsync -av --delete web/templates/ ${SITE_DIR}/templates/ # Sync migrations rsync -av --delete migrations/ ${SITE_DIR}/migrations/ echo "==> Swapping binary..." mv app ${SITE_DIR}/app echo "==> Setting permissions..." # Scope permission fixing to the directories this script actually manages. # # This previously ran `find ${SITE_DIR} -type f -exec chmod 644 {} +` across the # whole site directory and then restored +x on ${SITE_DIR}/app alone. That also # stripped the execute bit from every sub-service binary under # ${SITE_DIR}/services/, e.g. services/scout/app. Those services keep running # from their already-open file, so nothing appears to break — until the next # reboot, when systemd cannot exec them and they fail with 203/EXEC. Scout was # down for three and a half weeks that way, serving 502s behind /scout/, because # the failure is invisible until someone opens the page. for managed in public templates migrations; do [ -d "${SITE_DIR}/${managed}" ] || continue chown -R www-data:www-data "${SITE_DIR}/${managed}" find "${SITE_DIR}/${managed}" -type d -exec chmod 755 {} + find "${SITE_DIR}/${managed}" -type f -exec chmod 644 {} + done chown www-data:www-data ${SITE_DIR}/app chmod +x ${SITE_DIR}/app chmod 600 ${SITE_DIR}/.env 2>/dev/null || true # Belt and braces: re-assert +x on every executable the site depends on. Even # though the blanket chmod above is gone, a missing execute bit here is what an # outage looks like, and asserting it costs nothing. # # The old blanket chmod took out four binaries in one go — services/scout/app, # services/hawaii/app, bin/claudomator and bin/claude (which claudomator execs # via --claude-bin). Only ${SITE_DIR}/app survived, because it was the single # path the script put the bit back on. Both locations are covered here. for svc_bin in ${SITE_DIR}/services/*/app ${SITE_DIR}/bin/*; do [ -f "$svc_bin" ] || continue chmod +x "$svc_bin" done echo "==> Starting service..." systemctl start ${SERVICE} sleep 1 systemctl status ${SERVICE} --no-pager -l echo "==> Deploy complete!"