Skip to content

Update deployment SSH key ownership and allow branch-based workflow testing#5

Merged
findolor merged 17 commits into
mainfrom
chore/local-db-op
May 26, 2026
Merged

Update deployment SSH key ownership and allow branch-based workflow testing#5
findolor merged 17 commits into
mainfrom
chore/local-db-op

Conversation

@findolor
Copy link
Copy Markdown
Collaborator

@findolor findolor commented Apr 13, 2026

Depends on

Motivation

The local DB remote deployment should no longer depend on legacy SSH recipients that are not intended to have access in this repo.

This PR updates the provisioning/deployment access model to use the new github_do key, keeps arda as the only additional recipient, and makes the manual GitHub workflows testable from a non-main branch so provisioning and deploy can be exercised before merge.

Solution

  • change the Terraform SSH key lookup to use github_do
  • update the encrypted-recipient config in keys.nix so only github_do and arda retain access
  • remove the old st0x-op, sid, and ci recipients from the repo config
  • update Provision Host to accept target_ref and allow_non_main, check out the selected ref, and persist Terraform state back to that same ref
  • update Deploy to accept target_ref and allow_non_main so the branch version of the workflow can be exercised against the real host before merge
  • keep the default production path unchanged by defaulting both workflows to target_ref=main and allow_non_main=false

Checks

By submitting this for review, I am confirming I have done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Validated locally with:

  • not run yet; workflow changes have been reviewed but not exercised through GitHub Actions from this branch

Summary by CodeRabbit

  • Chores
    • Deployment and provisioning workflows now let you choose a target Git ref, include a validation toggle for non-main refs, and show the selected target in summaries. Workflows decrypt and load runtime config at runtime for deployment and storage operations; state persistence follows the chosen target.
    • Infrastructure defaults updated: new default SSH key, larger VM size, and simplified role assignments for SSH/infra credentials.
  • Documentation
    • Added example runtime env and terraform vars entries documenting optional overrides.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Workflows now accept workflow_dispatch inputs to select a target ref and optionally allow non-main runs; they validate and checkout that ref, decrypt and load runtime env into $GITHUB_ENV at runtime, and push state to the selected ref. SSH keys/roles and Terraform defaults were updated; example runtime config added.

Changes

Cohort / File(s) Summary
Deploy workflow
.github/workflows/deploy.yaml
Added workflow_dispatch inputs target_ref and allow_non_main; export TARGET_REF; validate TARGET_REF; checkout ref: ${{ env.TARGET_REF }}; decrypt/load runtime env at runtime into $GITHUB_ENV; removed static SPACES/DUMP env entries; include target in summary.
Provision host workflow
.github/workflows/provision-host.yaml
Same workflow_dispatch inputs and TARGET_REF flow; validate TARGET_REF; checkout chosen ref; push state to "$TARGET_REF"; make persisting Terraform state conditional on file existence; update step summaries.
Local DB / utility workflow
.github/workflows/create-empty-local-db-manifest.yaml
Removed static SPACES env entries; added step to write SSH key, use nix shell + rage to decrypt config/runtime.env.age, source temp env, and export DUMP_BASE_URL and SPACES_* into $GITHUB_ENV; adjust manifest URL capture.
Runtime config examples & secrets
config/runtime.env.example, config/secrets.nix
Added config/runtime.env.example with DUMP_BASE_URL and SPACES_* placeholders. Added config/secrets.nix exposing "runtime.env.age".publicKeys = (import ../keys.nix).roles.infra.
SSH keys / roles
keys.nix
Removed st0x-op, ci, sid key entries; added github_do; updated roles.infra and roles.ssh to [ github_do arda ].
Terraform variables & examples
infra/variables.tf, infra/terraform.tfvars.example
Changed Terraform defaults: ssh_key_name st0x-opgithub_do; droplet_size s-1vcpu-1gbs-2vcpu-4gb. Added commented example override lines documenting ssh_key_name, region, and droplet_size.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant GH as GitHub Actions
    participant Runner as Job Runner
    participant Nix as Nix/rage
    participant Git as Git Remote

    User->>GH: trigger workflow_dispatch(target_ref, allow_non_main)
    GH->>Runner: start job with inputs
    Runner->>Runner: set env TARGET_REF = inputs.target_ref
    Runner->>Runner: validate TARGET_REF == "main" OR allow_non_main == true
    alt validation passes
        Runner->>Git: actions/checkout ref=TARGET_REF
        Runner->>Nix: nix shell -> rage decrypt config/runtime.env.age -> /tmp/runtime.env
        Nix->>Runner: decrypted file
        Runner->>Runner: source /tmp/runtime.env -> export DUMP_BASE_URL, SPACES_* to GITHUB_ENV
        Runner->>Runner: run deployment/provision steps
        Runner->>Git: git push origin HEAD:"$TARGET_REF"
        Runner->>Runner: update step summaries with Target ref
    else validation fails
        Runner->>Runner: fail workflow
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the two main changes: updating SSH key ownership from legacy recipients to github_do, and enabling branch-based workflow testing via new inputs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/local-db-op

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Collaborator Author

findolor commented Apr 13, 2026

@findolor findolor changed the title chore: switch provisioning SSH key to local-db-op Update deployment SSH key ownership and allow branch-based workflow testing Apr 13, 2026
@findolor findolor marked this pull request as ready for review April 13, 2026 09:18
@findolor findolor self-assigned this Apr 13, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/provision-host.yaml:
- Around line 37-44: The current Validate target ref step allows tag/SHA refs
when allow_non_main=true, which can lead to attempting a state push to a
non-branch ref; update that step to explicitly verify TARGET_REF is an existing
branch before proceeding (e.g., run a git query such as git ls-remote --heads
origin "$TARGET_REF" or use the GitHub API to confirm a refs/heads/$TARGET_REF
exists) and fail with a clear error if the branch is missing; keep the existing
allow_non_main gating but add this branch-existence check in the same step so
the later state push only runs for valid branch destinations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 49e623d5-3c09-4f09-9351-63cc3ff7d4fe

📥 Commits

Reviewing files that changed from the base of the PR and between f588169 and 991837d.

📒 Files selected for processing (4)
  • .github/workflows/deploy.yaml
  • .github/workflows/provision-host.yaml
  • infra/variables.tf
  • keys.nix

Comment thread .github/workflows/provision-host.yaml
@findolor findolor force-pushed the chore/local-db-op branch 3 times, most recently from 0b08c92 to 743a1f6 Compare April 14, 2026 10:48
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/create-empty-local-db-manifest.yaml:
- Around line 30-48: Extract the repeated SSH/rage decryption block into a
reusable composite action (e.g. create
.github/actions/load-runtime-config/action.yaml) that exposes an input like
"ssh_key" and implements the steps currently in the workflow (mkdir ~/.ssh,
write and chmod id_ed25519, run rage to decrypt config/runtime.env.age to
/tmp/local-db-runtime.env, source it and append DUMP_BASE_URL, SPACES_REGION,
SPACES_BUCKET, SPACES_ENDPOINT to $GITHUB_ENV); then replace the inline block in
this workflow and deploy.yaml with a single step that calls the composite action
and passes secrets.SSH_KEY as the ssh_key input.

In `@infra/variables.tf`:
- Line 10: The default SSH key name variable is set to "github_do" which must
exist in DigitalOcean or Terraform will fail; verify or change the default by
updating the variable `var.ssh_key_name` in `infra/variables.tf` or add the
corresponding SSH key in your DigitalOcean account so the `data
"digitalocean_ssh_key"` lookup in `infra/main.tf` can succeed. Ensure the chosen
name matches the actual key label in DigitalOcean and keep `var.ssh_key_name`
consistent across your Terraform configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07dcdc9b-ed2a-4ece-9ec7-f283d96c64e2

📥 Commits

Reviewing files that changed from the base of the PR and between 0b08c92 and 743a1f6.

📒 Files selected for processing (8)
  • .github/workflows/create-empty-local-db-manifest.yaml
  • .github/workflows/deploy.yaml
  • config/runtime.env.age
  • config/runtime.env.example
  • config/secrets.nix
  • infra/terraform.tfvars.age
  • infra/terraform.tfvars.example
  • infra/variables.tf

Comment thread .github/workflows/create-empty-local-db-manifest.yaml
Comment thread infra/variables.tf
description = "Name of the SSH key in DigitalOcean to add to the droplet"
type = string
default = "st0x-op"
default = "github_do"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how the SSH key is referenced in main.tf
ast-grep --pattern 'data "digitalocean_ssh_key" $_ {
  $$$
}'

Repository: rainlanguage/rain.local-db.remote

Length of output: 59


🏁 Script executed:

#!/bin/bash
# First, check if the infra directory exists and list relevant files
git ls-files infra/ | head -20

Repository: rainlanguage/rain.local-db.remote

Length of output: 254


🏁 Script executed:

#!/bin/bash
# Search for digitalocean_ssh_key references using rg
rg "digitalocean_ssh_key" --type tf -B 2 -A 2

Repository: rainlanguage/rain.local-db.remote

Length of output: 366


🏁 Script executed:

#!/bin/bash
# Read the actual variables.tf file around line 10
if [ -f infra/variables.tf ]; then
  cat -n infra/variables.tf | head -30
else
  echo "infra/variables.tf not found"
fi

Repository: rainlanguage/rain.local-db.remote

Length of output: 912


Ensure the github_do SSH key exists in DigitalOcean before running Terraform.

The digitalocean_ssh_key data source in infra/main.tf looks up the SSH key by the name stored in var.ssh_key_name. If no SSH key named github_do exists in the DigitalOcean account, Terraform will fail during the apply step.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infra/variables.tf` at line 10, The default SSH key name variable is set to
"github_do" which must exist in DigitalOcean or Terraform will fail; verify or
change the default by updating the variable `var.ssh_key_name` in
`infra/variables.tf` or add the corresponding SSH key in your DigitalOcean
account so the `data "digitalocean_ssh_key"` lookup in `infra/main.tf` can
succeed. Ensure the chosen name matches the actual key label in DigitalOcean and
keep `var.ssh_key_name` consistent across your Terraform configuration.

@findolor findolor force-pushed the chore/local-db-op branch from 743a1f6 to ea4d719 Compare April 14, 2026 12:47
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/create-empty-local-db-manifest.yaml:
- Around line 30-47: The decrypted runtime file /tmp/local-db-runtime.env
created in the "Load encrypted runtime config" step contains sensitive secrets
and must be removed after use; modify the step so that after sourcing and
appending the needed variables to GITHUB_ENV you securely delete the temporary
file (e.g., overwrite/shred if available or at minimum rm -f
/tmp/local-db-runtime.env) and ensure it had restrictive permissions while
present; reference the commands that create/source the file (nix shell ... >
/tmp/local-db-runtime.env and source /tmp/local-db-runtime.env) and add a
cleanup action immediately after exporting the variables.

In @.github/workflows/deploy.yaml:
- Around line 74-88: The decrypted runtime file /tmp/local-db-runtime.env is
left on disk after the "Load encrypted runtime config" step; update that step
(the shell block that runs nix/rage and sources /tmp/local-db-runtime.env) to
securely remove the file when done by adding a removal command (e.g., rm -f
/tmp/local-db-runtime.env) after exporting the variables to $GITHUB_ENV so the
temporary secret file does not persist on the runner.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 40a610b8-8592-4734-be71-fc916fb07d33

📥 Commits

Reviewing files that changed from the base of the PR and between 743a1f6 and ea4d719.

📒 Files selected for processing (8)
  • .github/workflows/create-empty-local-db-manifest.yaml
  • .github/workflows/deploy.yaml
  • config/runtime.env.age
  • config/runtime.env.example
  • config/secrets.nix
  • infra/terraform.tfvars.age
  • infra/terraform.tfvars.example
  • infra/variables.tf

Comment thread .github/workflows/create-empty-local-db-manifest.yaml Outdated
Comment thread .github/workflows/deploy.yaml Outdated
@findolor findolor force-pushed the chore/local-db-op branch 5 times, most recently from 83ae77c to 8516824 Compare April 15, 2026 06:58
@findolor findolor force-pushed the chore/local-db-op branch from 8516824 to 3f38d00 Compare April 15, 2026 07:26
@JuaniRios JuaniRios requested a review from hardyjosh May 26, 2026 12:42
Copy link
Copy Markdown
Collaborator Author

findolor commented May 26, 2026

Merge activity

  • May 26, 3:00 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 26, 3:00 PM UTC: @findolor merged this pull request with Graphite.

@findolor findolor merged commit b10da84 into main May 26, 2026
2 checks passed
findolor added a commit that referenced this pull request May 26, 2026
## Depends on

- #5

## Motivation

The remote local DB host needs to run more than one sync process at a time during schema and database migrations. The existing singleton producer must keep running while a new deployment-id based sync instance is added beside it.

## Solution

- keep the existing legacy `local-db-sync.service` and `local-db-sync.timer`
- keep legacy runtime paths under `/etc/local-db-remote/env`, `/var/lib/local-db-remote/bin`, and `/var/lib/local-db-remote/work/local-db`
- make `local-db-remote-run` backwards-compatible: without `LOCAL_DB_DEPLOYMENT_ID`, it uses the legacy paths
- add deployment-id validation and per-deployment paths when `LOCAL_DB_DEPLOYMENT_ID` is set
- add `local-db-sync@<deployment_id>.service` and `local-db-sync@<deployment_id>.timer`
- create shared host directories for named deployment env, binary, and work state

## Checks

By submitting this for review, I am confirming I have done the following:
- [x] made this PR as small as possible
- [ ] unit-tested any new functionality
- [x] linked any relevant issues or PRs
- [ ] included screenshots (if this involves a front-end change)

Validated locally with:
- `bash -n nixos/local-db-remote-run.sh`
- `nix eval '.#nixosConfigurations.local-db-remote.config.systemd.services.local-db-sync.serviceConfig.EnvironmentFile'`
- `nix eval '.#nixosConfigurations.local-db-remote.config.systemd.services."local-db-sync@".serviceConfig.Environment'`
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.

4 participants