9.9 KiB
9.9 KiB
Ansible Repo Audit — Findings
Generated 2026-06-04 after auditing ~70 role files, 7 playbooks/configs, 21 host_vars, and 50+ templates.
Completed Fixes
- Removed all Forgejo references — deleted
roles/forgejo/, removed forgejo play fromplaybook.yml, removedforgejo_serversgroup fromhosts, removed forgejo vars fromhost_vars/git.mcintire.me.yml, removed docker-mirror CNAME from DNS zone. - Fixed hardcoded SSH private key paths — replaced all 20 occurrences of
/Users/graham/.ssh/id_ed25519and/Users/graham/.ssh/ansiblewithansible_ssh_private_key_file: "{{ lookup('env', 'ANSIBLE_SSH_PRIVATE_KEY_FILE') | default('~/.ssh/ansible', true) }}"ingroup_vars/all/all.yml. SetANSIBLE_SSH_PRIVATE_KEY_FILEenv var to override. - Fixed
community.mysqlcollection — added torequirements.ymland installed (fixes monitor role crash). - Removed broken
setup-userMakefile target — referenced non-existentsetup-user.sh. - Fixed tracking issues —
git rm --cachedfor 5.DS_Storefiles and.vscode/settings.json; added.ansible/to.gitignore. - Fixed stale documentation — updated
CLAUDE.mdandREADME.mdto reflect actual playbook structure, roles, inventory groups, and collections. - Fixed non-FQCN module references — converted ~290 short module names (
apt:,service:,template:, etc.) to FQCNs (ansible.builtin.apt:, etc.) across all roles and playbooks. - Fixed
become:/gather_facts:boolean forms —become: yes→become: true,gather_facts: no→gather_facts: falsein all plays. - Removed deprecated
inject_facts_as_varsfromansible.cfg. - Added missing task names —
import_tasks/include_rolecalls inbase/tasks/main.ymlandgeneral/tasks/main.ymlnow have descriptive names. - Fixed
partial-becomebug — addedbecome: yesto librenms clone task. - Added
pipefailto risky shell command inudp-gro-fix.yml. - Quoted octal mode values —
mode: 0755→mode: '0755', etc. - Hardened
.ansible-lintconfig — setprofile: production, added exclude paths, removed all skip_list entries. - Added defaults for 4 undefined template variables —
ntpserver,template_run_date,deb_mirror,sshd.*all have safe fallbacks now. - Removed Alpine role reference —
include_role: name=alpineinroles/base/tasks/main.ymlwas pointing to a non-existent role. - Fixed SSH
-tflag placement — Moved before hostname in bothbootstrap-rebootandrebootMakefile targets. - Fixed
general.ymlreferences —bootstrap-network,run-all,qc-webMakefile targets now useplaybook.yml; removedqc-webtarget (qc_webgroup doesn't exist). - Removed all Docker targets —
build-*,run-*,push-*,base-*,latest,local,clean,dirs— no Dockerfile at repo root ever existed. - Fixed
install-collections— removed references to deletedroles/requirements.ymlandscripts/fix-deprecated-imports.sh. - Deleted orphaned
host_vars/db.aprs.me.yml— host not in inventory;db.w5isp.comalready serves as the single database server. - Deleted unreferenced roles — removed
icinga2-container/,debug/,mailcow/,syncthing/(no plays applied them). - Removed unused Galaxy dependencies — deleted
geerlingguy.docker,geerlingguy.kubernetesfromrequirements.yml; deleted entireroles/requirements.yml(graylog2.graylog, bertvv.bind, artis3n.tailscale); mergednetbox.netboxinto root file. - Cleaned fact_cache — removed 56 stale files.
- Removed unused inventory groups —
home_clusteranddns_servers(defined but never targeted).
🔴 Security (fix immediately)
| # | Issue | Location |
|---|---|---|
| 1 | Plaintext secrets in .envrc — Tailscale auth key, PowerDNS API key, PostgreSQL password, Proxmox root password in plaintext on disk. Use ansible-vault or a secrets manager. |
.envrc:3,6,9,14 |
| 2 | Hardcoded cloud-init password — cipassword in plaintext for BIND9 VM. Anyone with repo access can SSH in as debian. |
playbook.yml:159 |
| 3 | Hardcoded SSH public key — Same ed25519 key in playbook, setup-host.sh, and base/files/ansible.pub. Not vaulted. Rotate + move to vault. |
playbook.yml:106, setup-host.sh:17, base/files/ansible.pub |
🔴 Broken Infrastructure (will fail at runtime)
| # | Issue | Location |
|---|---|---|
| 5 | general.yml does not exist — Referenced by 3 Makefile targets plus docs. Content was merged into playbook.yml but Makefile was never updated. |
Makefile:40,56,68 |
| 6 | No Dockerfile at repo root — All build-*, run-*, push-* Makefile targets fail. base-latest/base-local reference non-existent sub-targets. |
Makefile:3-30 |
| 8 | geerlingguy.postgresql not in requirements.yml — Role referenced in playbook.yml:73 for postgresql_servers but not installable via ansible-galaxy. |
playbook.yml:73, requirements.yml |
🔴 Runtime Crashes (undefined template variables)
All template variable defaults have been added. See Completed Fixes for details.
🟡 Logic Bugs
| # | Issue | Location |
|---|---|---|
| 18 | Firewall role runs twice on every non-Proxmox host — once via base role's include_role and once via explicit firewall play. |
playbook.yml:18-25, roles/base/tasks/main.yml:50-55 |
| 19 | SSH -t flag in wrong position — Placed after hostname where it's treated as a remote command, not a local SSH option. |
Makefile:43,65 |
| 20 | ansible_user in [ssh_connection] section — Silently ignored by Ansible. Should be remote_user under [defaults]. |
ansible.cfg:32 |
| 21 | run.sh masks playbook failures — tee pipeline without set -o pipefail always exits 0. |
run.sh:18 |
| 22 | playbook_handlers.yml is orphaned — Defines Restart firewalld handler but is never imported by any playbook. |
playbook_handlers.yml |
| 23 | changed_when: true on idempotent commands — removes prevents re-execution but changed_when overrides natural detection. |
roles/debian/tasks/main.yml:5, roles/general/tasks/udp-gro-fix.yml:27, roles/mailcow/tasks/main.yml:156 |
| 24 | run-local mounts wrong path — ${PWD}/run/fact_cache doesn't exist. dirs creates tmp/fact_cache which is never used. |
Makefile:10,34 |
| 25 | TAILSCALE_AUTHKEY vs TAILSCALE_KEY mismatch — .envrc exports TAILSCALE_AUTHKEY but docs say role expects TAILSCALE_KEY. |
.envrc:3 vs CLAUDE.md |
| 26 | bootstrap.yml second play unconditionally uses become_method: sudo — Will hang if graham needs sudo password and -K not provided. |
bootstrap.yml:71-81 |
| 27 | mail.mcintire.me and git.mcintire.me use bare ansible_host=mail/ansible_host=git — DNS resolution depends on control node's search domain. |
hosts:24,51 |
| 28 | Variable naming inconsistency — Some templates use flat names (nameservers), some use nested (network.nameservers). |
resolv.conf.j2 vs group_vars/all/all.yml |
🟡 Best Practice / Lint Violations
All items in this section have been fixed.
🟡 Dead Code & Stale Files
All items in this section have been fixed.
🟢 Previously Fixed
| # | Issue | Fix |
|---|---|---|
| 4 | Hardcoded Forgejo runner token in host_vars | Deleted with forgejo cleanup |
| 7 | setup-user.sh doesn't exist |
Removed broken Makefile target |
| 11 | community.mysql.mysql_db module not found |
Added community.mysql to requirements.yml and installed |
| 45 | 5 .DS_Store files tracked by git |
git rm --cached |
| 46 | .vscode/settings.json tracked despite gitignore |
git rm --cached |
| 47 | .ansible/ directory not in .gitignore |
Added to .gitignore |
| 48 | Stale CLAUDE.md (references general.yml, missing roles, wrong commands) |
Rewritten with accurate playbooks, roles, collections, commands |
| 49 | Stale README.md (wrong directory tree, incomplete groups) |
Rewritten with accurate structure and inventory groups |
| 29 | Non-FQCN module references (~290 instances) | Converted all to FQCNs across all roles and playbooks |
| 30 | Unquoted octal mode values (9 instances) | All quoted with single quotes |
| 31 | become: yes / gather_facts: no |
Changed to become: true / gather_facts: false |
| 32 | inject_facts_as_vars deprecated |
Removed from ansible.cfg |
| 33 | Missing task names on import_tasks/include_role |
Added descriptive names |
| 34 | partial-become bug in librenms |
Added become: yes |
| 35 | risky-shell-pipe without pipefail |
Added set -o pipefail |
| 36 | Minimal .ansible-lint config |
Set profile: production, added exclude paths, empty skip_list |
| 37 | Unreferenced icinga2-container/ and debug/ roles |
Deleted |
| 38 | Unreferenced mailcow/ and syncthing/ roles |
Deleted |
| 39 | geerlingguy.docker and geerlingguy.kubernetes never used |
Removed from requirements.yml |
| 40 | graylog2.graylog and bertvv.bind never used |
Deleted roles/requirements.yml |
| 41 | collections/requirements.yml redundant |
Merged into root file, deleted |
| 42 | Stale fact_cache files (56 files) | Deleted all |
| 43 | home_cluster and dns_servers groups never targeted |
Removed from hosts |
| 9 | alpine role referenced but doesn't exist |
Removed include_role from roles/base/tasks/main.yml |
| 10 | Orphaned host_vars/db.aprs.me.yml with no inventory entry |
Deleted (superseded by db.w5isp.com) |
| 12-15 | Undefined template variables (ntpserver, template_run_date, deb_mirror, sshd.*) | Added ` |
| -- | Alpine role reference to non-existent role | Removed from roles/base/tasks/main.yml |
| -- | SSH -t flag after hostname in Makefile |
Moved before hostname |
Recommended Top 2 Fixes
- Rotate all 4 plaintext secrets in
.envrcand move toansible-vault - Add
geerlingguy.postgresqltorequirements.yml— will crash otherwise