Capstone: harden and document
Capstone: harden and document
Goal: Make remote deploy (deploy-rs and/or Colmena) the normal path, and wire CI that builds Capstone artifacts and preferably pushes a binary cache.
Baseline: flakes on nixos-26.05, secrets already on a path. This chapter is remote delivery + automation—not new app features.
Why this chapter exists
nixos-rebuild --flake only on the box is not a deploy story. Capstone A requires a deploy path and CI that would catch breakage before you SSH in panic. Cache push turns CI minutes into laptop seconds.
Theory 1 — Deploy definition of done
| Item | Done means |
|---|---|
| Tool chosen | deploy-rs or Colmena (both OK; one is enough for A) |
| Config in repo | deploy.nodes or Colmena hive committed |
| Auth | SSH key or deploy user documented |
| Magic | One command updates lab host from admin machine |
| Failure UX | Partial failure doesn’t leave mystery state; rollback known |
| Docs | docs/DEPLOY.md with command + prerequisites + rollback |
deploy-rs sketch
# flake outputs fragment — follow current deploy-rs docs for 26.05-era usage
{
inputs.deploy-rs.url = "github:serokell/deploy-rs";
outputs = { self, nixpkgs, deploy-rs, ... }: {
nixosConfigurations.lab = /* … */;
deploy.nodes.lab = {
hostname = "lab.local"; # or IP
profiles.system = {
user = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.lab;
};
};
};
}deploy .#lab
# or: nix run github:serokell/deploy-rs -- .#labColmena sketch
# hive.nix idea
{
meta.nixpkgs = import (builtins.getFlake "…").inputs.nixpkgs { };
lab = { … imports … };
}colmena apply --on labPick one primary path; document the other as optional.
Theory 2 — CI definition of done
| Item | Done means |
|---|---|
| Workflow file | .github/workflows/ci.yml (or Forgejo/Gitea equivalent) |
| Triggers | PR + push to main (or Capstone branch policy) |
| Build | nix build toplevel and/or nix flake check |
| Logs | Failures visible in CI UI |
| Cache (preferred) | Push to Cachix/Attic/etc. with secrets in CI vault |
| Pin | Nix installer version documented |
Minimal workflow sketch
name: ci
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-26.05
# - uses: cachix/cachix-action@v15
# with: { name: mycache, authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' }
- run: nix build .#nixosConfigurations.lab.config.system.build.toplevel -L
- run: nix flake check -LAdapt for KVM runners if nixosTest requires nested virt; otherwise split fast checks vs nightly tests.
Theory 3 — Cache push value
| Without project cache | With project cache |
|---|---|
| Every agent rebuilds your overlays | Shared substitutes |
| Laptop recompiles CI work | Laptop substitutes CI outputs |
| Slow feedback | Minutes matter less |
If you cannot push a cache yet, document waiver and still build in CI. Preferred: push.
Theory 4 — SSH deploy auth checklist
| Check | Note |
|---|---|
| Deploy key or agent | Non-interactive preferred for CI deploy (optional) |
root vs sudo user |
Match deploy tool docs |
| Host key verification | known_hosts managed deliberately |
| Network path | Admin machine can reach lab |
| Firewall | SSH open; no accidental lockout without console |
Theory 5 — RUNBOOK / DEPLOY docs minimum
docs/DEPLOY.md:
- Prerequisites (keys, network, flake path)
- Happy path one-liner
- Dry-run / build-only variant
- Failure symptoms
- Rollback pointer (
docs/RUNBOOK.md)
- Who is allowed to deploy
Concrete checklists
Deploy checklist
- Tool chosen and committed
- One-command deploy from admin machine
- Deploy log saved
- Rollback path written
docs/DEPLOY.mdcomplete
CI checklist
- Workflow runs on PR
- Toplevel or checks green
- Cache push or explicit waiver
- Nix version noted
- Badge or URL in CAPSTONE-A
Lab 0 — Workspace
mkdir -p ~/lab/nixos/capstone/harden
cd /path/to/capstone-flakeSnapshot lab VM before first remote deploy if deploy is new.
Lab 1 — Wire deploy tool
- Add deploy-rs or Colmena input.
- Point at lab host.
- Deploy once from admin machine.
- Capture log:
deploy .#lab 2>&1 | tee ~/lab/nixos/capstone/harden/deploy.logAcceptance: Remote activation succeeds; host healthy after.
Lab 2 — CI workflow
- Add workflow file.
- Push branch; observe CI.
- Fix until green.
- Optionally add Cachix/Attic push.
# local parity
nix build .#nixosConfigurations.lab.config.system.build.toplevel -L
nix flake check -LLab 3 — Hardening pass (light)
Do not start new apps. Optionally:
- SSH: password auth off if not already
- Firewall review
systemctl --failedclean
- Fail2ban only if already planned
Document changes in ARCHITECTURE.
Lab 4 — Docs
| Doc | Update |
|---|---|
docs/DEPLOY.md |
Full path |
docs/RUNBOOK.md |
Deploy + rollback stubs |
docs/CAPSTONE-A.md |
Tick deploy + CI |
docs/TRUST.md |
CI cache keys / trusted-users if changed |
Lab 5 — Failure tabletop
Write without executing production:
- Deploy fails mid-activation → what do you do?
- CI red on main → who unblocks?
- Cache token leaked → rotation steps
Lab 6 — Elitebook admin path
If admin machine is the Elitebook host and target is guest:
# from host
ping -c1 <guest>
ssh root@<guest> true
deploy .#lab # or colmenaAcceptance: Works over libvirt network without manual nixos-rebuild on guest.
Common gotchas
| Symptom | Fix |
|---|---|
| SSH permission denied | Keys, user, PermitRootLogin policy |
| deploy evaluates wrong system | system/attr mismatch |
| CI OOM | lower jobs; cache; split matrix |
| nixosTest needs KVM on GA | nightly self-hosted or skip in PR |
| Cache auth fails | secrets scope; trusted-public-keys on consumers |
Checkpoint
- Remote deploy one-liner works
- CI builds Capstone artifacts
- Cache push or waiver documented
- DEPLOY + RUNBOOK updated
- CAPSTONE-A ticks with proof
- Three personal gotchas
Commit
git add .
git commit -m "capstone: deploy path and CI hardening"Write three personal gotchas before continuing.
Next
→ Capstone: prove rebuildability — tests, runbook, diagrams.