Skip to content

chore: replace self-hosted deploy runner with SSH from GitHub-hosted runners - #3

Merged
soy-chrislo merged 4 commits into
mainfrom
chore/public-repo-ssh-deploy
Jul 31, 2026
Merged

chore: replace self-hosted deploy runner with SSH from GitHub-hosted runners#3
soy-chrislo merged 4 commits into
mainfrom
chore/public-repo-ssh-deploy

Conversation

@soy-chrislo

Copy link
Copy Markdown
Owner

Summary

The deploy pipeline in this repo (.github/workflows/deploy.yml) was copied verbatim from the private tunodo-organization/auth-gateway repo and has never worked here: the deploy job requires a [self-hosted, linux, deploy-host] runner, and this repo can never register one — it's a personal-account repo, not a member of tunodo-organization, and org-scoped runner groups (the only safe mechanism to expose a self-hosted runner to a public repo) don't extend outside org membership. Verified live via gh api orgs/tunodo-organization/actions/runner-groups, not assumed.

This PR replaces the self-hosted deploy job with one that runs on GitHub-hosted ubuntu-latest runners and reaches the target VPS over SSH as an existing dedicated deploy account — the same convention already used by other, unrelated projects on that same VPS. See docs/adr/ADR-0027-public-repo-ssh-deploy.md for the full decision record.

  • deploy.yml: deploy job now runs-on: ubuntu-latest; raw ssh/scp (not a third-party composite action) with a pinned known_hosts secret for real host-key verification; no docker login on the VPS at all (the GHCR package is made public instead); if: always() cleanup of the remote temp dir.
  • deploy/{prod,staging,dev}/docker-compose.yml: fixed the stale ghcr.io/CHANGEME_GITHUB_ORG/auth-gateway placeholder to the real ghcr.io/soy-chrislo/queres namespace this repo actually publishes to.
  • deploy/README.md: replaced the org-only "dedicated runner group" mitigation section (inapplicable to a personal-account repo) with the actual SSH deploy-credential provisioning steps.
  • docs/adr/ADR-0027-public-repo-ssh-deploy.md: new — records why self-hosted is structurally unavailable here and the alternatives that were ruled out (docker login over SSH, appleboy/ssh-action, editing the live compose file before the new image is provably pullable).

Real production VPS details (hostname, deploy account name, other tenants' SSH key identifiers sharing that account) are deliberately not spelled out anywhere in this public repo — the workflow resolves what it needs at runtime from GitHub Environment secrets instead.

This is infrastructure/CI-only: no application code changed.

Test plan

  • .github/workflows/deploy.yml parses as valid YAML (python3 -c "import yaml; yaml.safe_load(open('.github/workflows/deploy.yml'))")
  • Every run: block in the file passes bash -n (syntax check), including the heredoc-based remote script
  • The printf %q-based remote-command construction was traced by hand and simulated locally to confirm it round-trips DEPLOY_PATH/IMAGE_TAG/TMP_DIR correctly through the remote shell
  • code-reviewer and security-reviewer subagents run 3 times against the actual diff (not just this description); each round's findings were fixed and re-verified before the next
  • workflow_dispatch against staging once the SSH secrets exist (tracked as follow-up work, not part of this PR — secrets don't exist yet)
  • End-to-end staging deploy verification (health check + login flow) — follow-up, after secrets are provisioned

Christian Rubio added 4 commits July 30, 2026 23:07
…runners

soy-chrislo/queres is a personal-account repo, not an org member, so the
org's self-hosted runner-group mechanism can never apply here (verified via
the GitHub API, not assumed). Rewrites deploy.yml's deploy job to run on
ubuntu-latest and reach the VPS over SSH as the existing deploy system user
(the same convention four other projects on that VPS already use), makes
the GHCR package public to drop docker login entirely, fixes the GHCR image
reference in all three compose files, rewrites deploy/README.md's runner
section, and records the reversal in ADR-0027.
…ploy diff

- Stop naming the real VPS hostname and other, unrelated projects' SSH key
  identifiers in the new public docs (deploy.yml header, deploy/README.md,
  ADR-0027) — those details don't belong in a public repo and weren't this
  project's to disclose.
- Converge all three ssh/scp remote-command constructions in deploy.yml on
  the same safe pattern (a single, already-quoted command string) instead of
  relying on ssh's unquoted joining of trailing arguments for one of them;
  the prior comment claimed a safety property that pattern didn't actually
  provide, even though today's fixed values aren't exploitable.
- Pre-clean the remote frontends temp dir before every scp, since scp -r
  merges into an existing directory rather than mirroring it.
- Document the new SCP-to-temp-dir frontend transfer mechanism in ADR-0027,
  which the prior version omitted.
TMP_DIR was still /home/deploy/tmp-frontends-<env> after the previous
redaction pass -- flagged by a re-review as still disclosing the real
deploy account name via a standard /home/<user> convention, and it was
also being restated in prose in ADR-0027.

Make TMP_DIR a path relative to the deploy account's home directory
instead (ssh/scp both resolve relative remote paths against $HOME by
convention). The remote script resolves it back to an absolute path via
$HOME before using it in `docker run -v`, since Docker treats a
bind-mount source with no leading / as a named-volume name to create,
not a bind mount -- silently mounting an empty volume instead of the
scp'd files if left relative there.
A third review pass found the previous redaction (hostname, sibling
project key labels, /home/<user> path) missed three prose sentences that
still spelled out the real account name directly (backticked `deploy`,
distinct from the GitHub Actions job also named `deploy:`, which is fine
to disclose since it's defined in this same public file). Reworded to
refer to it generically, consistent with the rest of the redaction.
@soy-chrislo
soy-chrislo merged commit 888bbd5 into main Jul 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant