Commit graph

19 commits

Author SHA1 Message Date
dfc64da2eb feat(makefile): add EXTRA passthrough to check/deploy for ad-hoc ansible args
Lets an operator pass extra ansible-playbook args through make without bypassing it — e.g. -e ansible_host=<WAN> to manage a host over a relay-independent path during a cutover that restarts its own mesh relay.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 09:22:20 +02:00
d68734267b feat(make): test-integration / test-integration-clean targets
Add ADR-025 integration-test harness targets to Makefile:
- test-integration HOST=<name> [CERTS=internal|le-staging] [KEEP=1]
- test-integration-clean (prune stale VM snapshots)

Also add tests/integration/.run/ to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 12:45:38 +02:00
c1323a3f29 feat(make): registry-login via vaulted Forgejo token (kaizen)
scripts/registry-login.sh reads vault.forgejo.registry_token and pipes it to
docker login --password-stdin (never echoed, never on argv); 'make registry-login'
wires it with the venv binaries. Adds the operator-minted CHANGEME vault stub
(fill via make edit-vault) and a per-machine prereq note in the claude-code-setup
runbook, so 'make caddy-image-push'/'molecule-image-push' become agent-completable
non-interactively. Consumes the 2026-06-15 signal in docs/FRICTION.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 17:50:07 +02:00
d407aeabb2 feat(docker): custom Caddy image with the Gandi DNS-01 plugin
Compiles caddy-dns/gandi v1.1.0 into Caddy v2.11.4 via xcaddy so mesh/LAN-only
hosts (no public A-record) can issue certs via ACME DNS-01. Pinned per ADR-011/014.

The M4a attempt failed for two reasons, both addressed here:
  - built on a Hetzner IP -> Google's Go module proxy 403s those ranges. The
    Makefile target is documented to build on ubongo, then push to Forgejo.
  - older libdns/gandi sent Gandi's deprecated Apikey header. v1.1.0 sends the
    PAT as Authorization: Bearer to api.gandi.net/v5/livedns.

make caddy-image / caddy-image-push mirror the molecule-image targets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 06:57:38 +02:00
13ae674cc9 chore(kaizen): first /kaizen run — curate 12 friction signals
Dogfood of the new /kaizen command. 11 consumed, 1 kept open.
- SYSTEMATIZE → docs/testing/gotchas.md (apply:{tags} propagation, Molecule
  tag-isolation testing, API/templating render-only gap); CLAUDE.md
  (item['key'] loop convention, TF module required_providers); public_dns
  README (Gandi null-MX workaround).
- CHANGE → extend the Stop hook to also guard the brainstorming spec-review gate
  (verified: blocks the gate, passes meta-discussion).
- SYSTEMATIZE → make new-role scaffolds the access__/backup__ noqa reminder;
  ADR-004 documents the cross-role-naming convention.
- ALREADY-BUILT/ACCEPTED → exec-menu guard verified firing; ADR-023; ADR-024;
  subagent-faithfulness now embodied in the two-stage subagent review.
- KEEP-OPEN → a repo-scan.py check for ADRs that over-claim reconciliation.

Nudge: OVERDUE (13 signals) → ok (1). make lint + 16 friction-scan tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:46:23 +02:00
b7e919d6b3 refactor(reverse_proxy): vanilla Caddy + HTTP-01 (drop DNS-01 custom image)
Switch from a custom caddy-dns/gandi image built on-host to the official
caddy:2 image with per-host ACME HTTP-01 certificates. Removes the
Dockerfile, env.j2 (Gandi token), on-host image build/ship/load tasks,
the caddy-image Makefile target, and the wildcard DNS-01 Caddyfile.
Each route now gets its own server block and automatic certificate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 18:11:20 +02:00
50b6445bdd feat(reverse_proxy): Caddy role (Gandi DNS-01, on-host image build, route catalog)
Implements the Caddy reverse proxy role (ADR-024): builds boma/caddy-gandi:latest
on-host (caddy-dns/gandi plugin), renders Caddyfile from route catalog, brings
Compose project up. Adds community.docker to requirements.yml, production group_vars,
and a caddy-image Makefile target.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:36:58 +02:00
22021210c4 feat(make): optional LIMIT= and TAGS= passthrough on check/deploy
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:41:59 +02:00
07af037ff3 feat(make): offsite TF token injection + directory inventory + tf-inventory-offsite
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:05:41 +02:00
79f2315eee feat(make): add edit-vault + check-vault targets
`make edit-vault` runs `ansible-vault edit` (decrypt → nvim → re-encrypt on :wq,
abort on :cq) so editing the vault is one step with no plaintext left in the work
tree, then validates structure. `make check-vault` runs scripts/check-vault.py:
decrypts in-memory, asserts valid YAML with secrets under the nested `vault:` map
and no empty leaves, and prints a values-masked structure view (comments visible,
secrets never printed). Both default to the production all-vault; override VAULT=.

Update the vault header comment, CLAUDE.md (command table + Secrets section), and
scripts/README to point at edit-vault (note check-vault.py is the one venv-
dependent helper, by design).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 09:36:15 +02:00
a2bb99928c fix(deploy): make check/deploy actually run
Two latent bugs that blocked the documented deploy path (never exercised
end-to-end before applying dev_env to ubongo):
- Makefile: the PLAYBOOK variable was both the ansible-playbook BINARY path
  and the user-supplied playbook NAME, so `make check/deploy PLAYBOOK=<name>`
  overrode the binary. Renamed the binary var to PLAYBOOK_BIN.
- ansible.cfg: stdout_callback=yaml and callbacks_enabled=timer were
  community.general plugins (not installed; boma only ships ansible.posix).
  Use the built-in default callback with callback_result_format=yaml and
  ansible.posix.profile_tasks — same intent, no new heavy collection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 14:09:12 +02:00
2dbcac11a0 chore(tooling): scope ansible-lint to ansible content; venv PATH in make test
Kaizen 2026-06-10 fixes:
- ansible-lint pre-commit hook now `always_run: false` + a files filter for
  roles/playbooks/inventories YAML, so docs-/config-only commits skip it and no
  longer need `rbw unlock` (root cause was ansible-lint auto-decrypting the
  group_vars vault, not the syntax-check).
- `make test`/`test-all` prepend $(CURDIR)/.venv/bin to PATH so non-activated
  agent runs find ansible-config/ansible-playbook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:51:30 +02:00
0b59107b33 feat(tags): enforce tag vocabulary in make lint; fix docker_host tag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 09:37:43 +02:00
0513971f40 Fix Forgejo registry path to owner/image format (review R10a)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 21:34:02 +02:00
bf9ce95e1e Fix make new-role: brace expansion fails under dash
The mkdir used shell brace expansion {tasks,handlers,...}, which /bin/sh (dash)
does not support, so new-role created one literally-named dir and then errored.
make new-role had never worked on this host. Use explicit mkdir paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 19:35:11 +02:00
1642d1786a Wire Terraform vlan_tag and fix scaffold placeholder (R9,R11)
R9: pass vlan_tag (default 20 = srv VLAN, ADR-007) from both envs to the
proxmox_vm module so VMs are tagged, not on untagged vmbr0. R11: make new-role
now sed-substitutes ROLE_NAME_PLACEHOLDER so scaffolded molecule converge works
out of the box.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 19:34:02 +02:00
bb2179a288 Apply review fixes R12-R14: printf scaffold, phantom control/ dir, Galaxy wording
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 19:19:47 +02:00
4ee1b66e23 Source vault password from Vaultwarden via rbw; nest vault structure
Master vault password is fetched from Vaultwarden via the rbw agent
(scripts/vault-pass-client.sh, wired as vault_password_file) instead of a
plaintext .vault_pass. Vault secrets use a nested vault.<service>.<key> map.
Encrypted vault.yml files are excluded from lint. Includes the host rename in
Makefile and STATUS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 18:16:35 +02:00
3f1d7eb128 Add core Ansible scaffold, tooling, and pre-commit guards
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 14:10:01 +02:00