# Contributing ## Conventions - All Ansible modules use FQCN: `ansible.builtin.template`, not `template` - Every task has a `name:` that reads as a sentence and at least one tag - Role variables use `rolename__varname` double-underscore namespace - No plain text secrets outside `vault.yml` files ## Branching Single-contributor, trunk-based: - `main` is the trunk and must always work. Small, self-contained changes commit straight to `main`. - Use a short-lived branch for sweeping or AI-driven changes you want to review as one diff or be able to abandon: `role/`, `fix/`, `feat/`, `chore/`. Merge to `main` when it looks right, then delete the branch. - Run `make lint` (and `make test` for touched roles) before committing. - Commit messages: imperative mood, ≤72-char subject; commit in logical units. - Push to Forgejo often — it is the off-machine backup. ## Adding a role Follow the runbook: `docs/runbooks/new-role.md` Always use `make new-role NAME=` to scaffold — never create structure by hand. ## Secrets The master vault password lives in Vaultwarden; `rbw` fetches it on demand via `scripts/vault-pass-client.sh` (run `rbw unlock` once per session). Never put secrets in any file other than `vault.yml`. See `docs/runbooks/rotate-secrets.md` for rotation procedures. ## Generated files Some files are produced by tooling and must not be hand-edited — change the source and regenerate. Each generated file carries a header saying so. | Generated file | Source of truth | Regenerate with | |---|---|---| | `inventories//hosts.yml` | `terraform/environments//main.tf` (`local.vms`) | `make tf-inventory TF_ENV=` | Exception: the control node is added to `hosts.yml` by hand — see `docs/runbooks/new-host.md`. ## Testing Before committing or merging to main: ```bash make lint make test ROLE= make check PLAYBOOK=site ``` All three must pass cleanly.