Files
ansible-arch/docs/superpowers/specs/2026-07-28-ansible-reconciliation-design.md
Tuan-Dat Tran 753bdfd403 docs: add implementation plan for ansible-arch reconciliation
Also folds in the dead handlers/main.yaml finding discovered while writing the plan.
2026-07-28 08:39:18 +02:00

122 lines
5.0 KiB
Markdown

# Ansible-arch ↔ machine reconciliation
Date: 2026-07-28
Status: Approved
## Context
The `ansible-arch` repo had an in-flight uncommitted diff (hyprland.conf tweaks,
new packages across several roles, new dotfiles stow packages) plus untracked
files. Separately, `ansible.cfg` sets `become = True` globally, which caused
the dotfiles role's `stow` task to run as root — the `hypr`, `zellij`, and
`starship.toml` symlinks in `~/.config` ended up owned by `root` instead of
the invoking user. A full audit of installed packages (`pacman -Qeq`) against
what the roles declare also turned up drift in both directions.
Resolution order: prefer encoding drift into ansible roles and re-running the
playbook over hand-editing the machine directly. Direct machine changes are
only for things ansible can't (or already will, as a side effect) fix.
## Scope
One reconciliation pass, no new tooling:
1. Fix the `become` default so privilege escalation is opt-in per task, not
global.
2. Commit the existing in-flight diff and untracked files as-is — they're
already the intended state.
3. Fold audited package/service drift into the appropriate roles.
No repeatable drift-check tool is being added (explicitly out of scope —
one-time fix, matches existing YAGNI preference).
## 1. Privilege escalation fix
- Remove `become = True` from `ansible.cfg` `[privilege_escalation]` (default
becomes `False`).
- Add explicit `become: true` to every task that needs root:
- all `pacman:` module tasks (every role)
- `systemd:` service-enable tasks (hyprland role)
- `user:` group-membership task (hyprland role, docker group)
- `chsh` / `getent` tasks and the sudoers-setup step (common role)
- No change needed for `kewlfft.aur.aur` tasks or the `paru` makepkg shell
task — they never had explicit `become` set, so they now correctly inherit
`become: false`. (They were arguably broken before: makepkg refuses to run
as root. This went unnoticed because the packages were already installed,
so the tasks were no-ops.)
- No change needed for dotfiles-role stow tasks or any `blockinfile`/`.zshrc`/
`.profile` tasks — same reasoning, they now correctly run unprivileged.
- Net effect on `~/.config` symlink ownership: no manual `chown`/`rm` step is
needed. The dotfiles role's "Remove existing config files before stowing"
task unconditionally removes the `hypr`/`zellij`/`starship.toml`/`kanshi`
targets before every `stow` run, so simply re-running `site.yml` after this
fix deletes the root-owned symlinks and recreates them owned by the
invoking user.
## 2. Formalize the in-flight diff
Commit as-is:
- `dotfiles/hypr/.config/hypr/hyprland.conf` (keyboard layout, mouse/scroll
behavior, hyprlock keybind, monitor scaling, dwindle pseudotile changes)
- `roles/ai`, `roles/common`, `roles/devops`, `roles/dotfiles`,
`roles/hyprland`, `roles/multimedia` package/task additions already in the
working tree
`git add` untracked files that are already part of an existing stow package:
- `dotfiles/hypr/.config/hypr/hyprlock.conf`
- `dotfiles/hypr/.config/hypr/monitors.sh`
- `dotfiles/kanshi/`
- `dotfiles/starship/`
## 3. Package/service audit — role placement
Cross-referenced `pacman -Qeq` (explicitly installed) against every
`roles/*/tasks/*.yml` package list.
**Add to `ctf` role:**
- `gitleaks`
- `nuclei-bin` (AUR)
- `picocom`
- `python-pyserial`
**Add to `common` role:**
- `nano`
- `vim`
- `sshpass`
- `smartmontools`
- `cargo-audit`
**Explicitly out of scope** (base install / firmware / bootloader —
provisioning concerns this repo doesn't own):
`base`, `linux`, `linux-firmware`, `efibootmgr`, `lvm2`, `sudo`,
`btrfs-progs`, `amd-ucode`, `intel-media-driver`, `libva-intel-driver`,
`vulkan-intel`, `sof-firmware`, `xorg-server`, `xorg-xinit`,
`zram-generator`, `snapper`.
**Flagged, no role change:** `dunst` — installed but superseded by `swaync`
(already declared in the hyprland role). Left as-is; not added to any role,
not uninstalled.
**No action needed** (false positives from the audit):
`paru`, `paru-debug` (installed by the common role's own bootstrap task, not
a plain pacman list item), `ttf-joypixels` (already declared, just via a
single-value `name:` key the audit grep didn't match).
**Minor cleanup:** remove the duplicate `docker` package entry from the
`cs_student` role — `devops` already declares it.
**Dead file found during planning:** `roles/common/handlers/` contains both
`main.yml` and `main.yaml`. Ansible's role loader searches handler file
extensions in a fixed order and stops at the first match, so `main.yml`
(which already has `become: true`) is the only one ever loaded — `main.yaml`
is dead and orphaned. Delete it.
## Verification
- `ansible-playbook site.yml --check --diff` runs clean (no unexpected
changes) after the `become` fix and role edits.
- `ansible-playbook site.yml` run confirms `~/.config/hypr`,
`~/.config/zellij`, `~/.config/starship.toml`, `~/.config/kanshi` are
owned by the invoking user, not root.
- `git status` clean after committing.