flowchart TD
A[Package audit] --> F[Unmanaged package found]
F --> Q{Is the package needed?}
Q -->|No / not intentional| R[Remove package]
Q -->|Yes, for the lab baseline| M["<a href='https://github.com/fs-ise/workstation-setup/tree/main/roles' target=_blank>Add to shared role</a>"]
Q -->|Yes, managed personally| O[Add to overlay role]
Q -->|Yes, genuine local exception| L[Add narrow exception in topmost layer]
M --> DS[Repository desired state updated]
O --> DS
L --> DS
R --> C[Local drift removed]
DS --> U[Run make configure again]
U --> W[Workstation aligned]
Audit configuration
Run the existing package and manual-installation audit:
make auditThis invokes playbooks/audit-unmanaged-packages.yml. Its scope is deliberately limited: it detects DNF packages outside the Ansible-managed package declarations and selected unmanaged filesystem installations. It does not compare every file, service, preference, or application setting and is not comprehensive configuration-drift detection. See Apply configuration or Update configuration for the operational workflows.
The audit reports two kinds of unmanaged software:
- A DNF User-reason but Ansible-unmanaged package is tracked by RPM/DNF with the install reason
User, but is not declared in this repository’s managed package lists or package allowlists. Packages withGroupor dependency-related reasons are excluded.External Userand other external or uncertain reasons are reported separately for review but do not fail the audit. If DNF5 reason reporting is unavailable, the audit preserves compatibility by treating the older command’s--userinstalledresults as user-requested. - An unmanaged filesystem installation is a file, symlink, or
/optinstallation that is not owned by an RPM and is not in the separate manual-install allowlists. This commonly includes software unpacked from tarballs.
The DNF managed set has no separate package manifest. The audit discovers roles/*/defaults/main.yml, loads those role defaults, and combines every <role>_managed_dnf_packages declaration, then trims, deduplicates, and sorts package names before comparing them. When a role adds a DNF package, declare it in that role’s package variables and expose it through <role>_managed_dnf_packages; use the same variable from the install task where practical. The audit therefore follows the installation source of truth instead of copying package names into group_vars.
Audit unmanaged packages
Local package changes should not remain invisible. The audit helps identify software that was installed manually or introduced outside the Ansible-managed package lists.
For each audit finding, decide what it means:
- Unintentional change or unnecessary software: remove the package.
- Software needed on all managed workstations: add it to the relevant Ansible role.
- Software managed by a personal or other overlay: declare it in that overlay’s role package list and run the combined audit from the overlay.
- A genuine local exception: record a narrow exception in the topmost configuration layer. Do not add personal packages to the shared allowlist.
AI coding tools such as ChatGPT or Codex can help draft the required Ansible changes, but review package names, repository additions, and role placement before committing.
Decision workflow
How filtering works
To keep the audit actionable, this repository supports two filtering mechanisms:
package_audit_allowlistfor exact package namespackage_audit_allowlist_patternsfor regex-based package families
Use exact allowlist entries whenever possible. The shared allowlist is reserved for shared Fedora/system exceptions; overlay exceptions belong in the overlay. Regex patterns are reserved for tightly bounded package families, such as known kernel subpackages.
Every pattern must enumerate the allowed suffixes and match the complete package name. Do not use open-ended prefixes such as ^lib, ^perl, or ^gnome-: they can hide unrelated software that a user installed manually.
Audit manual filesystem installations
The filesystem category checks regular files and symlinks in /usr/local/bin and /usr/local/sbin, plus direct directory and symlink children of /opt. It resolves executable symlinks where possible and asks RPM which package owns the effective path. RPM-owned entries are not findings, and broken symlinks are reported safely. The audit intentionally does not scan ~/.local, where tools such as uv, pipx, Cargo, and npm commonly create legitimate user-managed files.
Configure this category independently in group_vars/all/package_audit.yml:
manual_install_audit_allowlist:
- local-tool
- /opt/institution-tool
manual_install_audit_allowlist_patterns:
- '^lab-'
manual_install_audit_fail_on_unmanaged: false
manual_install_audit_recommendations:
quarto: "Install the official Quarto RPM through the quarto role."Exact and regex allowlists match either the normalized installation name or its reported path. Prefer exact entries and keep patterns narrow. The default is report-only; set manual_install_audit_fail_on_unmanaged to true to make remaining findings fail the playbook.
Prefer a suitable official RPM or package-managed installation over a tarball/manual installation. Allowlist intentional exceptions rather than deleting them: this audit is read-only and never changes detected software.