name: Build & Deploy Hermy HQ (Nix + Attic) on: push: branches: [main] workflow_dispatch: concurrency: group: hermyhq-deploy cancel-in-progress: false permissions: contents: read id-token: write env: VPS_HOST: ${{ secrets.VPS_HOST }} VPS_USER: ${{ secrets.VPS_USER }} jobs: build-and-deploy: runs-on: ubuntu-latest timeout-minutes: 60 steps: - name: Checkout uses: actions/checkout@v7 with: fetch-depth: 0 - name: Install Nix uses: DeterminateSystems/nix-installer-action@v22 with: determinate: false extra-conf: | sandbox = false accept-flake-config = true extra-substituters = https://attic.asepharyana.my.id/asepharyana extra-trusted-public-keys = asepharyana:zBpY6vNI1nDJ4mU6W4q880BB0JB1qb3gRKkO/tGSMiQ= - name: Cache Nix uses: DeterminateSystems/magic-nix-cache-action@v14 with: use-flakehub: false - name: Build hermyhq id: build run: | nix build .#hermyhq --impure --option sandbox false --print-build-logs STORE_PATH=$(readlink result) echo "store-path=$STORE_PATH" >> "$GITHUB_OUTPUT" echo "Build OK hermyhq: $STORE_PATH" - name: Push to Attic cache env: ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }} run: | if [ -z "$ATTIC_TOKEN" ]; then echo "ATTIC_TOKEN not set; skipping attic push" exit 0 fi STORE_PATH="${{ steps.build.outputs.store-path }}" ATTIC_DIR="/nix/store/fygyy3yk4rqdknxkiwkqambpnhyax0k4-attic-0.1.0" ATTIC_BIN="" if command -v attic >/dev/null 2>&1; then ATTIC_BIN="$(command -v attic)" elif nix-store --realise "$ATTIC_DIR" 2>/tmp/attic-bootstrap.err; then echo "✅ Pulled attic client from attic cache (HTTPS substituter)" ATTIC_BIN="$ATTIC_DIR/bin/attic" else echo "attic client unavailable on runner; skipping push (VPS will fall back)" exit 0 fi mkdir -p "$HOME/.config/attic" cat > "$HOME/.config/attic/config.toml" < ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 sed -i 's/\r$//' ~/.ssh/id_ed25519 ssh-keygen -y -f ~/.ssh/id_ed25519 >/dev/null 2>&1 || { echo "SSH key invalid"; exit 1; } ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts 2>/dev/null - name: Deploy hermyhq to VPS run: | STORE_PATH="${{ steps.build.outputs.store-path }}" echo "=== Realising hermyhq: $STORE_PATH (substitute from attic, fallback ssh copy) ===" if ssh "$VPS_USER@$VPS_HOST" "sudo /nix/var/nix/profiles/default/bin/nix-store --realise '$STORE_PATH'" 2>/dev/null; then echo "Substituted hermyhq from Attic cache" else echo "Attic substitute failed; falling back to ssh copy" nix copy --to "ssh://$VPS_USER@$VPS_HOST" "$STORE_PATH" fi echo "=== Updating profile ===" ssh "$VPS_USER@$VPS_HOST" "sudo /nix/var/nix/profiles/default/bin/nix-env --profile /nix/var/nix/profiles/hermyhq --set '$STORE_PATH'" echo "=== Restarting service ===" ssh "$VPS_USER@$VPS_HOST" \ "sudo systemctl daemon-reload && sudo systemctl restart hermyhq && for i in \$(seq 1 15); do state=\$(sudo systemctl is-active hermyhq 2>/dev/null || echo inactive); [ \"\$state\" = \"active\" ] && break; sleep 2; done; echo \"final-state=\$state\"; [ \"\$state\" = \"active\" ]" echo "✅ hermyhq deployed" cleanup: needs: build-and-deploy if: always() runs-on: ubuntu-latest steps: - name: Nix GC on VPS env: VPS_HOST: ${{ secrets.VPS_HOST }} VPS_USER: ${{ secrets.VPS_USER }} SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }} run: | mkdir -p ~/.ssh echo "$SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts 2>/dev/null ssh "$VPS_USER@$VPS_HOST" "sudo /usr/local/bin/nix-gc-vps.sh" || echo "⚠️ Nix GC gagal (non-fatal)"