Inspector Coverage
Inspectors are the data-collection modules that populate snapshot sections. Each inspector implements the Inspector trait and runs during the scan phase.
Source: crates/collect/src/inspectors/
Execution model
Inspectors run in two waves:
- Wave 1 – RPM inspector runs first. Its output (installed packages, file ownership, verification results) is extracted into an
RpmStatestruct. - Wave 2 – all other inspectors run in parallel. They receive the
RpmStateas read-only context to classify files as RPM-owned vs. unowned.
If the RPM inspector fails entirely, Wave 2 inspectors that depend on RPM state return InspectorError::Failed.
Inspector reference
RpmInspector
| ID | Rpm |
| Applies to | PackageBased systems |
| Snapshot field | rpm (RpmSection) |
| Source | inspectors/rpm/ (multi-file module) |
What it reads:
| Data source | Purpose |
|---|---|
rpm -qa --queryformat | Installed package list (NEVRA) |
rpm -qa (sentinel format) | File ownership mapping (/etc paths to owning packages) |
rpm -Va | Package verification results (modified files) |
dnf repoquery --userinstalled | Leaf package classification |
dnf repoquery --requires --resolve | Dependency graph for leaf/auto classification |
/etc/yum.repos.d/ | Repository configuration files |
| RPM GPG keyring | Imported GPG keys |
dnf module list --enabled | Enabled module streams |
dnf versionlock list | Version lock entries |
dnf repolist --enabled | Enabled repository list (for repo-less detection) |
find /var/cache/dnf -name *.rpm | Cached RPM files for repo-less packages |
Section fields: packages_added, base_image_only, rpm_va, repo_files, gpg_keys, version_changes, leaf_packages, auto_packages, leaf_dep_tree, module_streams, version_locks, multiarch_packages, duplicate_packages.
Repo-less detection (inspectors/rpm/repoless.rs): After the main RPM inventory, packages whose source_repo is empty or names a disabled/removed repository are flagged as repo-less. For each repo-less package, the inspector scans /var/cache/dnf/ for cached .rpm files matching the package NEVRA. Matching uses case-insensitive substring comparison between install-time short names (e.g., AppStream) and full repo IDs (e.g., rhel-9-for-aarch64-appstream-rpms). Cached RPMs are bundled in the tarball under repoless-packages/; uncached RPMs are annotated as MANUAL for user provision via the refine UI.
ConfigInspector
| ID | Config |
| Applies to | PackageBased systems |
| Snapshot field | config (ConfigSection) |
| Source | inspectors/config/ (multi-file module) |
What it reads:
| Data source | Purpose |
|---|---|
rpm -Va results (from RpmState) | RPM-owned files with modifications |
/etc/ directory walk | Unowned configuration files |
/usr/etc vs /etc overlay diff | Ostree/bootc system config changes |
| Path classification rules | Category assignment (network, security, auth, etc.) |
Branches: Traditional package-based systems use rpm -Va + /etc walk. Ostree/bootc systems use /usr/etc overlay diffing instead.
ServicesInspector
| ID | Services |
| Applies to | PackageBased systems |
| Snapshot field | services (ServiceSection) |
| Source | inspectors/services.rs |
What it reads:
| Data source | Purpose |
|---|---|
systemctl list-unit-files --type=service | Installed service units and their states |
/etc/systemd/system/, /usr/lib/systemd/system/ | Unit file locations |
.preset files | Systemd preset rules for deviation detection |
Drop-in directories (*.d/) | Service override snippets |
NetworkInspector
| ID | Network |
| Applies to | PackageBased systems |
| Snapshot field | network (NetworkSection) |
| Source | inspectors/network.rs |
What it reads:
| Data source | Purpose |
|---|---|
/etc/NetworkManager/system-connections/ | NetworkManager connection profiles |
firewall-cmd / firewalld config | Firewall zones and direct rules |
/etc/sysconfig/network-scripts/route-* | Static route files |
/etc/hosts | Custom host entries |
| Proxy environment / config | HTTP/HTTPS proxy settings |
| DNS configuration | DNS provenance detection |
StorageInspector
| ID | Storage |
| Applies to | PackageBased systems |
| Snapshot field | storage (StorageSection) |
| Source | inspectors/storage.rs |
What it reads:
| Data source | Purpose |
|---|---|
/etc/fstab | Persistent mount definitions |
findmnt --json | Active mount points |
lvs / LVM metadata | LVM volume configuration |
| Mount options | Credential reference detection |
ScheduledTasksInspector
| ID | ScheduledTasks |
| Applies to | PackageBased systems |
| Snapshot field | scheduled_tasks (ScheduledTaskSection) |
| Source | inspectors/scheduled.rs |
What it reads:
| Data source | Purpose |
|---|---|
/etc/cron.d/, /etc/cron.daily/, etc. | System cron directories |
/var/spool/cron/ | Per-user crontabs |
systemctl list-timers | Active systemd timers |
/var/spool/at/ | Pending at jobs |
Extra output: Generates systemd timer unit equivalents for discovered cron entries (stored as GeneratedTimerUnit).
Scans cron/at command content for secret-like patterns (password, secret, token, key, credential) and emits redaction hints.
ContainersInspector
| ID | Containers |
| Applies to | PackageBased systems |
| Snapshot field | containers (ContainerSection) |
| Source | inspectors/containers.rs |
What it reads:
| Data source | Purpose |
|---|---|
/etc/containers/systemd/, /usr/share/containers/systemd/ | Quadlet unit files (.container, .volume, etc.) |
~/.config/containers/systemd/ | User-level Quadlet files |
docker-compose*.yml / docker-compose*.yaml | Compose file discovery |
podman ps --format json | Running container inventory |
flatpak list | Installed Flatpak applications |
Parses Image= directives from .container Quadlet files to identify container image references.
Compose detection: Discovered compose files (docker-compose*.yml / docker-compose*.yaml) are stored in compose_files and bundled in the tarball under compose/. In the Containerfile, compose stacks are rendered as a reference-only comment block (no COPY or RUN) with a pointer to the bundled files and guidance on Quadlet migration.
NonRpmInspector
| ID | NonRpm |
| Applies to | PackageBased systems |
| Snapshot fields | non_rpm_software (NonRpmSoftwareSection), unmanaged_files (UnmanagedFileSection) |
| Source | inspectors/nonrpm.rs |
Scan roots: /opt, /srv, /usr/local. Directories matching node_modules, .git, .cache, .npm, .bundle, __pycache__, target, build, dist are pruned during recursive walks.
What it reads:
| Data source | Purpose |
|---|---|
pyvenv.cfg file walk | Python virtual environment discovery |
pip list --path <site-packages> --format=json | Per-venv pip package inventory |
.dist-info/ directory scan | Fallback venv package detection when pip list fails |
pip list --format=json (system) | System-level pip packages |
rpm -qf <path> | RPM ownership filtering for system pip packages |
package-lock.json file walk | npm project discovery (lockfile version 2/3 parsing) |
package.json | npm manifest fallback when no lockfile present |
Gemfile.lock file walk | Ruby gem project discovery (specs section parsing) |
Gemfile | Ruby project manifest collection |
gem list --local | System-installed gem detection |
.env files in common locations | Environment variable files (redaction-sensitive) |
.git/ directories | Git repository locations |
readelf on unpackaged binaries | ELF binary detection |
Language package detection methods:
| Method | Ecosystem | Confidence | Description |
|---|---|---|---|
python venv | pip | High | pyvenv.cfg found + requirements.txt present in venv root |
pip dist-info | pip | Medium | pyvenv.cfg found but no requirements.txt; packages read from .dist-info/ directories |
pip list | pip | Medium | System-level pip packages via pip list --format=json, RPM-owned packages filtered out via rpm -qf |
npm lockfile | npm | High | package-lock.json found; dependencies parsed from lockfile |
npm manifest | npm | Low | package.json found but no lockfile; dependency names extracted, no pinned versions |
gem lockfile | gem | High | Gemfile.lock found; gems parsed from specs section |
gem system | gem | Medium/Low | System gems via gem list --local, RPM-owned gems filtered out |
Confidence rendering: High-confidence items render as active Containerfile directives. Medium-confidence items render as commented-out directives. Low-confidence items render as advisory comments only.
Unmanaged file scanning (scan_unmanaged_files()): When --include-unmanaged is passed, files under /opt, /srv, /usr/local that are not owned by RPM or claimed by a Tier 1 language package environment are cataloged with provenance signals:
| Signal | Source | Description |
|---|---|---|
| Last modified | stat | File modification timestamp |
| Permissions | stat | File permission bits |
| UID / GID | stat | Owning user and group IDs |
| Writable mount | findmnt | Whether the file resides on a writable mount |
| Mutable | Filesystem check | Whether the file path is on a mutable filesystem layer |
| Service working dir | systemctl show | Whether the path is a service’s WorkingDirectory |
Symlinks are detected without following and preserved as tar symlink entries. In the Containerfile, symlinks render as RUN ln -sf directives rather than COPY.
KernelbootInspector
| ID | KernelBoot |
| Applies to | PackageBased systems |
| Snapshot field | kernel_boot (KernelBootSection) |
| Source | inspectors/kernelboot.rs |
What it reads:
| Data source | Purpose |
|---|---|
lsmod | Currently loaded kernel modules |
/etc/sysctl.d/, /etc/sysctl.conf | Sysctl parameter overrides |
timedatectl | Timezone configuration |
tuned-adm active | Active tuned profile |
/etc/dracut.conf.d/, /etc/modprobe.d/ | Boot configuration snippets |
SelinuxInspector
| ID | Selinux |
| Applies to | PackageBased systems |
| Snapshot field | selinux (SelinuxSection) |
| Source | inspectors/selinux.rs |
What it reads:
| Data source | Purpose |
|---|---|
getenforce / /etc/selinux/config | SELinux mode (enforcing/permissive/disabled) |
semodule -l | Custom SELinux policy modules |
semanage boolean -l | Boolean overrides from defaults |
semanage fcontext -l -C | Custom file context rules |
semanage port -l -C | Custom port label assignments |
| Audit rule files | Audit subsystem rules |
fips-mode-setup --check | FIPS mode status |
/etc/pam.d/ | PAM configuration files |
UsersGroupsInspector
| ID | UsersGroups |
| Applies to | PackageBased systems |
| Snapshot field | users_groups (UserGroupSection) |
| Source | inspectors/users.rs |
What it reads:
| Data source | Purpose |
|---|---|
/etc/passwd | Non-system users (UID 1000–59999) |
/etc/shadow | Password aging, hash status |
/etc/group | Non-system groups (GID 1000–59999) |
/etc/gshadow | Group shadow entries |
/etc/sudoers, /etc/sudoers.d/ | Sudoers rules |
~/.ssh/authorized_keys | SSH key references (redacted by default) |
/etc/subuid, /etc/subgid | Subordinate UID/GID mappings |
SubscriptionInspector
| ID | Subscription |
| Applies to | PackageBased systems |
| Snapshot field | subscription (SubscriptionSection) |
| Source | inspectors/subscription.rs |
| Activation | Only runs when --preserve subscription is passed |
What it reads:
| Data source | Purpose |
|---|---|
/etc/pki/entitlement/*.pem | Entitlement certificate and key pairs (serial-number matched) |
/etc/rhsm/ca/ | CA certificates (e.g., redhat-uep.pem) |
/etc/rhsm/rhsm.conf | Subscription manager configuration |
/etc/yum.repos.d/redhat.repo | Red Hat repository definition |
/etc/pki/consumer/cert.pem | Consumer cert for org metadata (org ID, system UUID, RHSM server) |
Section fields: entitlement_certs, ca_certs, config_files, earliest_expiry, incomplete, org_id, system_uuid, rhsm_server, source_hostname.
Behaviors:
- Cert/key files are base64-encoded in the snapshot and decoded during tarball staging.
- Certificate expiry is parsed from X.509 PEM data. Certs expiring within 14 days or already expired trigger warnings.
- Bundle completeness is evaluated against a four-component contract (entitlement pair, CA cert, rhsm.conf, redhat.repo). Missing components set
incomplete: truewith a warning naming the missing item. - Symlinks within subscription paths are followed; symlinks resolving outside approved roots are rejected with a warning.
- Files over 1 MB are rejected.
- Permission-denied errors produce warnings (not silent skips).
Redaction engine
The redaction engine runs as a pipeline stage after collection, before rendering. It is not an inspector but operates on inspector output.
Source: crates/pipeline/src/redaction/
Pattern types
| Pattern | What it matches | Example |
|---|---|---|
| PasswordHash | Shadow-file password hash strings | $6$rounds=... |
| PEM block | Full PEM certificate/key blocks (-----BEGIN...-----END) | Private keys, certificates |
| Connection string | Database connection URLs (PostgreSQL, MySQL, MongoDB) | mongodb://user:pass@host/db |
| NSS/PAM token | Sensitive tokens in NSS/PAM configuration files | ldap_default_authtok values |
Behaviors
- Comment-line filtering – lines beginning with
#are excluded from pattern matching to avoid false positives in commented-out configuration. - False-positive filtering – known non-sensitive values (e.g., example hostnames, placeholder strings) are filtered out before redaction.
- Structure preservation – connection string redaction preserves the URL structure (scheme, host, path) while replacing credentials with
[REDACTED]. MongoDB connection strings preserve themongodb://prefix and database path. - Inspector hints – inspectors emit
RedactionHintvalues to flag content they know is sensitive (e.g., sudoers env vars matching secret patterns, SSH key material). The redaction engine uses these hints to supplement pattern-based scanning.