mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
test(lint): demand a package-install nocheck on every role package_install
The batch lint cannot see the conditions an include or a role invocation puts around a task file, so an install there could pass as unconditional and be dropped onto every host. Every package_install task in a role now has to say why it cannot ride the deploy-start batch; the 26 existing ones name their reason (needed before update, repository first, task or include condition, conditional role, removal, controller delegation). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
18ea75049e
commit
cb4d340de9
26 files changed
+55
-28
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- block:
|
||||
- name: 📦 Install GCC compiler and runtime (cross-distro)
|
||||
package_install:
|
||||
package_install: # nocheck: package-install sys-pip builds on gcc before the update role and the batch run
|
||||
id: gcc
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
}}
|
||||
|
||||
- name: 📦 Install Nix via package manager on Arch-based systems
|
||||
package_install:
|
||||
package_install: # nocheck: package-install Arch only, other distros take the installer path
|
||||
id: nix
|
||||
become: true
|
||||
when:
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
- name: 📦 Install the btrfs tools the snapshot launcher shells out to
|
||||
become: true
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only on hosts with a btrfs mount
|
||||
id: btrfs-tools
|
||||
when: ansible_facts.mounts | selectattr('fstype', 'equalto', 'btrfs') | list | length > 0
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
no-resolv and would answer .onion only.
|
||||
- name: "📦 Egress router | Install dnsmasq (host split-DNS forwarder)"
|
||||
become: true
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only on the egress router this file is included for
|
||||
id: dnsmasq
|
||||
- name: "📁 Egress router | Ensure the dnsmasq drop-in directory exists"
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
when: WIREGUARD_MESH_NAMES | length == 0
|
||||
|
||||
- name: "📦 Install the WireGuard tooling"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install the mesh bootstrap runs before the update role and the batch run
|
||||
id:
|
||||
- wireguard
|
||||
- iproute
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
server IP/hostname is mandatory.
|
||||
|
||||
- name: "📦 Install the NFS client"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install the controller installs it too, by delegation from the NFS server role
|
||||
id: nfs-client
|
||||
|
||||
- name: "🔧 Match NFSv4 idmap to the ganesha test server"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: "📦 Ensure e2fsprogs is installed for mkfs.ext4"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only the ext4 loop overlay backing includes this file
|
||||
id: e2fsprogs
|
||||
|
||||
- name: "✅ Refuse to mount over a non-empty export base"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
mode: "0755"
|
||||
|
||||
- name: "📦 Install the NFS client"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install runs on the controller by delegation, outside any host's batch
|
||||
id: nfs-client
|
||||
|
||||
- name: "🔎 Read current mount source at controller {{ DIR_VAR_LIB }}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: "📦 Install the userspace nfs-ganesha server"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only the ganesha NFS flavor includes this file
|
||||
id:
|
||||
- nfs-ganesha
|
||||
- libntirpc
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
- name: "📦 Install the kernel NFS server"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only the kernel NFS flavor includes this file
|
||||
id:
|
||||
- nfs-client
|
||||
- nfs-kernel-server
|
||||
|
||||
- name: "📦 Install the SELinux python binding (seboolean module + selinux fact)"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only the kernel NFS flavor includes this file
|
||||
id: selinux-python-binding
|
||||
|
||||
- name: "📊 Re-gather the SELinux fact now the binding is present"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
system_service_tpl_on_failure: "{{ lookup('unit_name','sys-ctl-alm-email@', suffix=False) }}%i.service"
|
||||
|
||||
- name: 📦 install curl
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only hosts with Telegram alerts run this role
|
||||
id: curl
|
||||
|
||||
- include_tasks: utils/once/flag.yml
|
||||
@@ -9,7 +9,7 @@
|
||||
loop_var: sys_ctl_cln_bkps_dependency
|
||||
|
||||
- name: 📦 install lsof
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only hosts that clean backups run this role
|
||||
id: lsof
|
||||
|
||||
- name: 📦 install psutil via pip
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
loop_var: sys_ctl_mtn_cert_renew_dependency
|
||||
|
||||
- name: 📦 install certbot
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only hosts with Let's Encrypt certificates run this role
|
||||
id: certbot-nginx
|
||||
|
||||
- include_role:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- name: ✅ Ensure hostname package is installed
|
||||
become: true
|
||||
package_install:
|
||||
package_install: # nocheck: package-install skipped inside containers
|
||||
id: hostname-tool
|
||||
when: not DOCKER_IN_CONTAINER | bool
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
when: run_once_dev_gcc is not defined
|
||||
|
||||
- name: 🐍 python pip install
|
||||
package_install:
|
||||
package_install: # nocheck: package-install needed before the update role and the batch run
|
||||
id: python-pip
|
||||
|
||||
- include_tasks: utils/once/flag.yml
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
- block:
|
||||
- name: 📦 Install sudo (Arch/Manjaro)
|
||||
package_install:
|
||||
package_install: # nocheck: package-install user-root needs sudo before the update role and the batch run
|
||||
id: sudo
|
||||
- name: ▶️ run the sudo tasks once
|
||||
set_fact:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: 📦 install certbot
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only hosts with Let's Encrypt certificates run this role
|
||||
id: certbot
|
||||
|
||||
- name: "📂 Include tasks for 'No-Webroot-ACME-CHALLENGE-METHOD'"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
when: ansible_facts['os_family'] == 'RedHat'
|
||||
|
||||
- name: 📦 Install Docker packages
|
||||
package_install:
|
||||
package_install: # nocheck: package-install needs the Docker repository the role adds first
|
||||
id: docker-cli
|
||||
register: sys_svc_container_packages_install
|
||||
retries: 5
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
global_install: true
|
||||
|
||||
- name: ✅ Ensure 'ip' and 'ping' commands are available for automtu
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only for the automtu measurement this file is included for
|
||||
id:
|
||||
- iproute
|
||||
- iputils-ping
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: "✅ Ensure msmtp-mta is absent (conflicts with postfix smtp-forwarder)"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install removes msmtp-mta, the batch only installs
|
||||
id: msmtp-mta
|
||||
state: absent
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
- when: lookup('email').external | bool
|
||||
block:
|
||||
- name: 📦 Install msmtp-mta when Mailu is used and package exists on distro
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only inside the Mailu block and only where the distro ships msmtp-mta
|
||||
id: msmtp-mta
|
||||
register: sys_svc_mail_msmtp_mta
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
when: sys_svc_mail_smtp_postfix_binary.stat.exists
|
||||
|
||||
- name: 🗑️ Remove postfix when external SMTP is used (conflicts with msmtp-mta)
|
||||
package_install:
|
||||
package_install: # nocheck: package-install removes postfix, the batch only installs
|
||||
id: postfix
|
||||
state: absent
|
||||
when: lookup('email').external | bool
|
||||
@@ -12,7 +12,7 @@
|
||||
when: run_once_sys_daemon is not defined
|
||||
|
||||
- name: "📦 Install local SMTP relay (Postfix)"
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only when the email relay is not external
|
||||
id: postfix
|
||||
|
||||
- name: "🔧 Configure Postfix as localhost-only relay"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
when: ansible_facts['os_family'] == 'Debian'
|
||||
|
||||
- name: 📦 Install OpenSSH client
|
||||
package_install:
|
||||
package_install: # nocheck: package-install user-root and the mesh bootstrap need it before the update role and the batch run
|
||||
id: openssh-client
|
||||
|
||||
- include_tasks: utils/once/flag.yml
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: 📦 Install ACL utilities
|
||||
package_install:
|
||||
package_install: # nocheck: package-install only the permissions step this file is included for needs setfacl
|
||||
id: acl
|
||||
|
||||
- name: ✅ Ensure backups root exists and owned by backup
|
||||
|
||||
@@ -12,7 +12,12 @@ role's own task installs it. Four rules hold that split together:
|
||||
them on hosts where the condition is false;
|
||||
* every id of a role the constructor runs ahead of the batch is
|
||||
``batch: false``, because the batch would install it too late;
|
||||
* a role file references only ids the shared root file declares.
|
||||
* a role file references only ids the shared root file declares;
|
||||
* every ``package_install`` task of a role carries
|
||||
``# nocheck: package-install <reason>`` on its module line or the line
|
||||
above, naming why it cannot ride the batch. The batch cannot see the
|
||||
conditions an include or a role invocation puts around a task file, so an
|
||||
unmarked install would slip past the first two rules.
|
||||
|
||||
A ``run_once_<role>`` guard is no condition here: it only keeps a role from
|
||||
running twice in one deploy.
|
||||
@@ -25,7 +30,8 @@ import unittest
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from utils.cache.files import iter_project_files
|
||||
from utils.annotations.suppress import is_suppressed_at
|
||||
from utils.cache.files import iter_project_files, read_text
|
||||
from utils.cache.yaml import load_yaml_any
|
||||
from utils.packages.registry import build_registry, load_references
|
||||
from utils.roles.invocations import (
|
||||
@@ -45,6 +51,8 @@ _RUN_ONCE_GUARD_RE = re.compile(
|
||||
r"|not\s+\(\s*run_once_\w+\s*\|\s*default\(false\)\s*\|\s*bool\s*\))$"
|
||||
)
|
||||
_BATCH_LOOKUP = "lookup('package_batch'"
|
||||
_RULE = "package-install"
|
||||
_MODULE_LINE_RE = re.compile(r"^\s*(?:-\s+)?package_install:")
|
||||
|
||||
|
||||
def _conditions(task: dict[str, Any]) -> list[str]:
|
||||
@@ -179,6 +187,25 @@ class TestPackageBatch(unittest.TestCase):
|
||||
+ "\n".join(f" - {o}" for o in offenders)
|
||||
)
|
||||
|
||||
def test_role_package_installs_are_marked(self) -> None:
|
||||
offenders: list[str] = []
|
||||
for path in _role_task_files():
|
||||
lines = read_text(str(path)).splitlines()
|
||||
offenders.extend(
|
||||
f"{path.relative_to(PROJECT_ROOT)}:{number}"
|
||||
for number, line in enumerate(lines, start=1)
|
||||
if _MODULE_LINE_RE.match(line)
|
||||
and not is_suppressed_at(lines, number, _RULE)
|
||||
)
|
||||
if offenders:
|
||||
self.fail(
|
||||
f"{len(offenders)} package_install task(s) in a role bypass the "
|
||||
"deploy-start batch without saying why. Drop the task so the batch "
|
||||
"installs the id, or flag the id 'batch: false' and mark the task "
|
||||
f"'# nocheck: {_RULE} <why it cannot ride the batch>':\n"
|
||||
+ "\n".join(f" - {o}" for o in offenders)
|
||||
)
|
||||
|
||||
def test_references_name_shared_ids(self) -> None:
|
||||
offenders = [
|
||||
f"roles/{role}/meta/packages.yml: '{package_id}'"
|
||||
|
||||
Reference in new issue
Block a user