hrafn was handed to infra-ops for uptime ownership with no CI deploy and no commit provenance -- the image was always local/hrafn:v1 and the whole working tree lived in the compose directory. These two files fix both. They are authored here because infra-ops owns hrafn's uptime, but they belong in vh/hrafn; claude-bot is not a collaborator there, so they are handed to the repo holder rather than committed directly. - playbooks-deploy.yaml -> vh/hrafn playbooks/deploy.yaml - gitea-workflows-deploy.yaml -> vh/hrafn .gitea/workflows/deploy.yaml Design calls recorded in the README: the build context travels as one tarball rather than per-file upload steps (nevermore's pattern fails open when a new source file has no matching step), and the playbook refuses to deploy unless .env exists at 0600 -- a guard prompted by it arriving 0644 with a live bearer token in it. Validated with `elway --dry-run`, which caught a real interpolation bug during authoring. No new Actions secrets needed.
2.5 KiB
hrafn CI deploy — authored here, lands in vh/hrafn
These two files replace hrafn's hand-rsync deploy. They are authored and
version-controlled here because infra-ops owns hrafn's uptime, but they
belong in the vh/hrafn repo — infra-ops has no write access to it
(claude-bot is not a collaborator), so they are handed to the repo holder
rather than committed directly.
| file here | destination in vh/hrafn |
|---|---|
playbooks-deploy.yaml |
playbooks/deploy.yaml |
gitea-workflows-deploy.yaml |
.gitea/workflows/deploy.yaml |
Keep this copy in sync if the deployed version changes, or delete it once
infra-ops has write access to vh/hrafn and the repo copy is canonical.
What the change buys
The pre-CI shape was: rsync a working tree into /opt/docker/compose/hrafn/,
then docker compose build && up. Two problems, both fixed here.
- No provenance. The image was always
local/hrafn:v1, so nothing on the box could answer "what commit is running". The image is now tagged with the commit SHA, and/opt/docker/compose/hrafn/.deployedrecords the SHA and timestamp. Rollback becomes a retag. - The whole repo lived in the compose directory —
tests/,docs/,ROADMAP.md,persistent-memory.md,CLAUDE.md. Only the build context ships now (Dockerfile,compose.yaml,pyproject.toml,README.md,src/).
Two design calls worth knowing
- Tarball, not per-file upload steps. nevermore's playbook enumerates
every source file as its own
upload:step. That is explicit, but it fails open: addsrc/hrafn/newthing.py, forget the matching step, and the deploy silently ships without it. hrafn's build context travels as one archive so it cannot go partial. .envis never deployed. It is host-owned,0600, and holds the bearer token. The playbook refuses to run if it is missing or not0600— a guard added because the file arrived at0644on handoff.
Validation
The playbook parses and interpolates clean under elway's own parser:
scripts/elway ana-docker --playbook stacks/hrafn/ci/playbooks-deploy.yaml \
--var hrafn_sha=abc123def456 --dry-run
That dry-run is worth running after any edit — it caught a real bug during
authoring, where a comment containing a literal {{ ... }} identifier was
picked up by elway's variable substitution and failed the run.
No new Actions secrets are required: DEPLOY_SSH_KEY and MGMT_REPO_TOKEN
already exist at user scope on vh from the nevermore/task-board wiring.