diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 78258d9..8b299c3 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -13,39 +13,26 @@ jobs: run: | mkdir -p ~/.ssh # Dedicated key file so we never overwrite the runner user's own key. - # nix/deploy.nix pins this via `-i ~/.ssh/gebos_deploy`. install -m 600 /dev/stdin ~/.ssh/gebos_deploy <<< "${{ secrets.DEPLOY_SSH_KEY }}" ssh-keyscan -H db.gebos.online app.gebos.online ingest.gebos.online >> ~/.ssh/known_hosts 2>/dev/null || true + # The gitea-runner is a systemd DynamicUser whose passwd home is `/`, + # so ssh expands `~` to `/.ssh/...` rather than $HOME. deploy-rs passes + # ssh opts with no shell, so it can't expand $HOME itself. Build the + # absolute paths here (bash expands $HOME) and hand them to deploy-rs + # via --ssh-opts; they append to nix/deploy.nix's path-free sshOpts. + echo "DEPLOY_SSH_OPTS=-i $HOME/.ssh/gebos_deploy -o UserKnownHostsFile=$HOME/.ssh/known_hosts" >> "$GITHUB_ENV" - name: Build all closures run: nix flake check --no-build - # TEMPORARY: diagnose the SSH auth failure to db-host. Prints only the - # PUBLIC key fingerprint (no private material) and the ssh negotiation. - # Remove once deploys succeed. - - name: Debug SSH to db-host - run: | - echo "== runner =="; whoami; echo "HOME=$HOME" - echo "== installed deploy PUBLIC key (compare to nix/hosts/common.nix:26-27) ==" - ssh-keygen -y -f ~/.ssh/gebos_deploy -P "" < /dev/null \ - || echo ">>> KEY UNREADABLE: encrypted (has passphrase) or missing" - echo "deploy should be ...Z+SU" - echo "me@larsnolden.com should be ...cdd0" - echo "== ssh auth negotiation ==" - ssh -vvv -F none -i ~/.ssh/gebos_deploy -o IdentitiesOnly=yes \ - -o StrictHostKeyChecking=accept-new -o BatchMode=yes \ - deploy@db.gebos.online 'echo CONNECTED as $(whoami)@$(hostname)' 2>&1 \ - | grep -Ei 'CONNECTED|denied|Server accepts|Offering|Authenticated|not accessible|Host key|incorrect passphrase|No such' \ - || true - # Order matters: db schema migrations are part of db-host's activation, # so it must land first. App-host's Supabase compose stack expects the # schemas to exist. mqtt-ingest only needs the network paths to db-host. - name: Deploy db-host - run: nix run github:serokell/deploy-rs -- .#db-host --skip-checks + run: nix run github:serokell/deploy-rs -- --ssh-opts "$DEPLOY_SSH_OPTS" .#db-host --skip-checks - name: Deploy app-host - run: nix run github:serokell/deploy-rs -- .#app-host --skip-checks + run: nix run github:serokell/deploy-rs -- --ssh-opts "$DEPLOY_SSH_OPTS" .#app-host --skip-checks - name: Deploy mqtt-ingest - run: nix run github:serokell/deploy-rs -- .#mqtt-ingest --skip-checks + run: nix run github:serokell/deploy-rs -- --ssh-opts "$DEPLOY_SSH_OPTS" .#mqtt-ingest --skip-checks diff --git a/nix/deploy.nix b/nix/deploy.nix index ec0f027..fdb81cf 100644 --- a/nix/deploy.nix +++ b/nix/deploy.nix @@ -12,14 +12,15 @@ let }; in { - # The Gitea runner has a global `Host * IdentityFile ~/.ssh/larsnolden` in its - # ~/.ssh/config (a passphrase-locked key). `-F none` makes ssh ignore that - # config so it doesn't offer the wrong key; `-i` + IdentitiesOnly pins the - # dedicated deploy key the workflow installs. Applies to both `nix copy` and - # the activation SSH. + # Path-free ssh options only. The key path and known_hosts are runner-specific + # and injected by the deploy.yml via deploy-rs `--ssh-opts` (which appends to + # this list for both `nix copy` and the activation SSH). They must be absolute: + # the gitea-runner is a systemd DynamicUser whose passwd home is `/`, so ssh + # expands `~` to `/.ssh/...` (NOT $HOME) and a tilde here finds no key. The + # workflow builds the absolute paths from $HOME, where bash expands correctly. + # `-F none` ignores the runner's ~/.ssh/config; IdentitiesOnly pins the key. sshOpts = [ "-F" "none" - "-i" "~/.ssh/gebos_deploy" "-o" "IdentitiesOnly=yes" "-o" "StrictHostKeyChecking=accept-new" ];