From 03d33f83ddcf05c33edab795b1cbff9bf7688159 Mon Sep 17 00:00:00 2001 From: sjat Date: Thu, 11 Jun 2026 14:53:55 +0200 Subject: [PATCH] fix(O1): scaffold docker_host role so `make lint` passes on main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit playbooks/site.yml imports the docker_host role, but it didn't exist, so ansible-lint's syntax-check failed on a clean checkout — breaking CLAUDE.md's "main must always work" / "Never skip lint" (top open finding O1 from the 2026-06-11 review). Scaffold docker_host as a proper placeholder via the prescribed mechanism (make new-role): filled meta/main.yml + README, an honest no-task tasks/main.yml documenting planned scope (Docker engine + Compose, daemon hardening, nftables.d container rules per ADR-004/020), and the standard molecule scenario. This preserves site.yml's full-standard-state intent rather than dropping the play. Update STATUS.md (docker_host moves from "Not in git" to "scaffolded, no tasks") and the role/playbook READMEs to match. make lint: 0 failures, 0 warnings; check-tags OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- STATUS.md | 8 ++--- playbooks/README.md | 2 +- playbooks/site.yml | 6 ++-- roles/README.md | 2 +- roles/docker_host/README.md | 34 +++++++++++++++++++ roles/docker_host/defaults/main.yml | 1 + roles/docker_host/handlers/main.yml | 1 + roles/docker_host/meta/main.yml | 11 ++++++ .../docker_host/molecule/default/converge.yml | 7 ++++ .../docker_host/molecule/default/molecule.yml | 31 +++++++++++++++++ roles/docker_host/molecule/default/verify.yml | 11 ++++++ roles/docker_host/tasks/main.yml | 13 +++++++ 12 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 roles/docker_host/README.md create mode 100644 roles/docker_host/defaults/main.yml create mode 100644 roles/docker_host/handlers/main.yml create mode 100644 roles/docker_host/meta/main.yml create mode 100644 roles/docker_host/molecule/default/converge.yml create mode 100644 roles/docker_host/molecule/default/molecule.yml create mode 100644 roles/docker_host/molecule/default/verify.yml create mode 100644 roles/docker_host/tasks/main.yml diff --git a/STATUS.md b/STATUS.md index 1796ea3..bdba503 100644 --- a/STATUS.md +++ b/STATUS.md @@ -35,14 +35,14 @@ _Last reviewed: 2026-06-11._ | Thing | State | |---|---| | `roles/base/` | **Partially built.** The `firewall` concern is implemented (nftables: catalog-driven default-deny + east-west allowlist + auto-rollback apply; ADR-020) with pytest + Molecule render/syntax tests. Other concerns (SSH hardening, fail2ban, auditd, packages, users) are **not** built yet, so `make deploy PLAYBOOK=site` has no real content to apply (the make target itself now works — see "Real and working today"). | -| `roles/docker_host/` | Not in git. Same. | +| `roles/docker_host/` | **Scaffolded, no tasks.** In git (meta/README/molecule filled), wired into `playbooks/site.yml` so the standard state is expressed end-to-end and `make lint` covers it, but it has no tasks yet — applying it is a no-op. Planned scope (Docker engine + Compose, daemon hardening, `nftables.d` container rules) in ADR-004/ADR-020. | | `inventories/*/hosts.yml` | Structured stubs with empty host maps (`hosts: {}`); regenerated by `make tf-inventory` once Terraform has hosts | | `inventories/production/group_vars/{docker_hosts,proxmox_hosts}/` | Empty dirs | So `make deploy PLAYBOOK=site` has no real content to apply — `base` is only partially -built (its `firewall` concern only) and the `docker_host` role does not exist yet. (The -`make check`/`deploy` machinery itself now works — first proven by applying `dev_env` via -`playbooks/workstation.yml`.) +built (its `firewall` concern only) and the `docker_host` role is scaffolded but has no +tasks yet. (The `make check`/`deploy` machinery itself now works — first proven by +applying `dev_env` via `playbooks/workstation.yml`.) ## Designed but not built diff --git a/playbooks/README.md b/playbooks/README.md index 9380ef5..096a6b0 100644 --- a/playbooks/README.md +++ b/playbooks/README.md @@ -5,7 +5,7 @@ Top-level orchestration playbooks. No inline vars — configuration comes from - `site.yml` — full standard state: applies `base` to all hosts and `docker_host` to docker hosts. **Note:** `base` is only partially built (its `firewall` concern) - and `docker_host` does not exist yet, so this is incomplete — see `STATUS.md`. + and `docker_host` is scaffolded with no tasks yet, so this is incomplete — see `STATUS.md`. - `workstation.yml` — applies the `dev_env` role (interactive developer environment) to the `control` group; built and applied to `ubongo` (see `STATUS.md`). - `bootstrap.yml` — first-run setup for a host that may not have Python yet; diff --git a/playbooks/site.yml b/playbooks/site.yml index 20dc80c..0ce57a1 100644 --- a/playbooks/site.yml +++ b/playbooks/site.yml @@ -1,9 +1,9 @@ --- # site.yml — apply full standard state to all hosts # Run via: make deploy PLAYBOOK=site -# NOTE: `base` is only partially built (its `firewall` concern; see STATUS.md) and the -# `docker_host` role does not exist yet, so this playbook applies base's firewall but is -# incomplete until `docker_host` is created. +# NOTE: `base` is only partially built (its `firewall` concern; see STATUS.md) and +# `docker_host` is scaffolded but has no tasks yet, so this playbook applies base's +# firewall but is otherwise incomplete until those roles gain content. - name: Apply base configuration to all hosts hosts: all diff --git a/roles/README.md b/roles/README.md index 9af6674..e75ce7d 100644 --- a/roles/README.md +++ b/roles/README.md @@ -10,6 +10,6 @@ Each role must have: a `molecule/default/` scenario (Debian 13), a populated Current state: `base` is **partially built** — its `firewall` concern (nftables) is implemented and tested; the other concerns (SSH hardening, fail2ban, auditd, packages, -users) are not yet built. `docker_host` does **not exist yet**. `dev_env` (interactive +users) are not yet built. `docker_host` is **scaffolded but has no tasks yet**. `dev_env` (interactive developer environment) is built and applied. See `STATUS.md` for the authoritative breakdown. diff --git a/roles/docker_host/README.md b/roles/docker_host/README.md new file mode 100644 index 0000000..1c490ad --- /dev/null +++ b/roles/docker_host/README.md @@ -0,0 +1,34 @@ +# docker_host + +Docker engine + Compose runtime applied to every host in the `docker_hosts` group. +Provides the container platform that the per-service roles (one service = one role, +ADR-004) deploy their Compose stacks onto. + +> **Status: scaffolded, not yet implemented.** This role has no tasks yet — applying it +> is a no-op. It is wired into `playbooks/site.yml` so the full standard state is +> expressed end-to-end, and so `make lint` covers it. See `STATUS.md`. + +## Planned scope + +- Install Docker engine + the Compose plugin, version-pinned (ADR-011). +- Daemon hardening: `iptables: false` (the host `base` firewall owns nftables, ADR-020), + log driver, `live-restore`, user-namespace remapping where practical (ADR-002). +- Render container forward/NAT rules into `/etc/nftables.d/*.nft` — the include hook the + `base` role's ruleset exposes (see `roles/base/README.md`). +- Provide the runtime the service roles deploy their Compose files onto. + +## Variables + +None yet. Placeholders will use the `docker_host__*` namespace (CLAUDE.md convention). + +## Example + +```yaml +- hosts: docker_hosts + become: true + roles: + - role: docker_host + tags: [docker_host] +``` + +See ADR-004 (`docs/decisions/004-docker-model.md`) for the Docker & Compose model. diff --git a/roles/docker_host/defaults/main.yml b/roles/docker_host/defaults/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/docker_host/defaults/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/docker_host/handlers/main.yml b/roles/docker_host/handlers/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/docker_host/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/docker_host/meta/main.yml b/roles/docker_host/meta/main.yml new file mode 100644 index 0000000..9175efb --- /dev/null +++ b/roles/docker_host/meta/main.yml @@ -0,0 +1,11 @@ +--- +galaxy_info: + author: sjat + description: Docker engine + Compose runtime for boma docker_hosts (Debian 13). + license: MIT + min_ansible_version: "2.17" + platforms: + - name: Debian + versions: + - trixie +dependencies: [] diff --git a/roles/docker_host/molecule/default/converge.yml b/roles/docker_host/molecule/default/converge.yml new file mode 100644 index 0000000..3cc5f30 --- /dev/null +++ b/roles/docker_host/molecule/default/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + gather_facts: true + + roles: + - role: docker_host diff --git a/roles/docker_host/molecule/default/molecule.yml b/roles/docker_host/molecule/default/molecule.yml new file mode 100644 index 0000000..b23d8da --- /dev/null +++ b/roles/docker_host/molecule/default/molecule.yml @@ -0,0 +1,31 @@ +--- +dependency: + name: galaxy + options: + requirements-file: ../../requirements.yml + +driver: + name: docker + +platforms: + - name: instance + # Project-owned image built from .docker/molecule-debian13/Dockerfile + # and hosted in the Forgejo container registry. + # Build/push with: make molecule-image / make molecule-image-push + image: forgejo.nyumbani.baobab.band/sjat/molecule-debian13:latest + pre_build_image: true + privileged: true # required for systemd + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + command: /lib/systemd/systemd + +provisioner: + name: ansible + inventory: + host_vars: + instance: + ansible_user: root + +verifier: + name: ansible diff --git a/roles/docker_host/molecule/default/verify.yml b/roles/docker_host/molecule/default/verify.yml new file mode 100644 index 0000000..c87d14e --- /dev/null +++ b/roles/docker_host/molecule/default/verify.yml @@ -0,0 +1,11 @@ +--- +- name: Verify + hosts: all + gather_facts: true + + tasks: + - name: Add verification tasks here + ansible.builtin.assert: + that: true + msg: "Replace this with real assertions" + tags: [verify] diff --git a/roles/docker_host/tasks/main.yml b/roles/docker_host/tasks/main.yml new file mode 100644 index 0000000..e5bd2f7 --- /dev/null +++ b/roles/docker_host/tasks/main.yml @@ -0,0 +1,13 @@ +--- +# docker_host — Docker engine + Compose runtime for hosts in the docker_hosts group. +# +# SCAFFOLDED, NOT YET IMPLEMENTED. This role is referenced by playbooks/site.yml so the +# full standard state is expressed end-to-end, but it has no tasks yet — applying it is a +# no-op. See STATUS.md ("Scaffolded but empty") and ADR-004 (Docker & Compose model). +# +# Planned scope (ADR-002/004/020): +# - install Docker engine + compose plugin (version-pinned, per ADR-011) +# - daemon hardening: iptables:false (host nftables owns the firewall, ADR-020), +# log-driver, live-restore, userns where practical +# - render container forward/NAT rules into /etc/nftables.d/*.nft (the base-role hook) +# - deploy per-service Compose stacks from the service roles (one service = one role)