Repository navigation
v1.8.0 — what your nodes actually run
The console can say what a node does get, not only what it should.
Classification has always described intent thoroughly — every class on a node, which group set it, why that group matched. The catalog is the result, and nothing read it. So "is /etc/ssh/sshd_config the same on all 190 servers?" had no answer here.
That is not a lookup. It is a consistency question, and configuration management exists to make an estate uniform.
Added
Estate-wide resource search
A new Resources page, peer to Nodes. Results group by resource and lead with variance:
⚠ File[/etc/ssh/sshd_config] production 12 nodes 2 variants
✓ File[/etc/motd] production 12 nodes 1 variant
Disagreements sort to the top. A flat list of 190 identical rows hides the three that differ, which is the opposite of what an operator opened the screen to find.
Variance without fetching a single parameter
PuppetDB's resource field is a SHA-1 over type, title and parameters, so identical hashes mean byte-identical parameters. The list query uses extract to omit parameters outright — a value never fetched cannot leak through a rendering bug, a log line, an error page or a screenshot.
Counted within an environment, never across it
A development node and a production node legitimately differ. Counting that as drift would flag a two-environment estate as entirely inconsistent on day one, and an alert that cries wolf gets muted — taking the one that mattered with it.
Expand to see who, compare to see what
Expanding a row names which nodes carry which configuration. Comparing parameters fetches one representative per variant and diffs them:
− app18.nexuspuppet.test + cache35.nexuspuppet.test
# managed by puppet
− PermitRootLogin no
+ PermitRootLogin yes
Multi-line values get a line diff with unchanged bulk collapsed, so a 200-line config file shows the stanza that changed rather than two columns to compare by eye.
Composes with fact filtering
"File[/etc/resolv.conf] on Ubuntu 22.04 nodes" is one query, reusing the inventory subquery from v1.7.7. Filtering by parameter value is supported too — "every node where sshd_config permits root login" — which needs no parameter to be displayed.
resources:read, a new and privileged permission
Deliberately not inventory:read. Facts describe a machine; resource parameters are its configuration payload — a File's content is the whole file body, and a class parameter may hold a credential.
Read-only audit events
Expanding parameters, and any query filtering on a parameter value, write an AuditLog row. Ordinary browsing does not — burying the events that matter under thousands that do not is how a trail stops being read.
The row is written before the read, so a crash cannot lose the evidence while keeping the disclosure. And it records the question, never the answer: no parameter value is ever written into the audit log, because that would copy the estate's secrets into a table that gets forwarded off-box.
Upgrading
One migration, admin_resources_read. No configuration changes.
Every existing ADMIN gains the ability to read managed file contents. The migration grants resources:read to the built-in ADMIN role. It is granted because otherwise nobody could hold it: creating a custom role answers 501 without the enterprise layer, so leaving it unheld would make the feature unreachable in every core deployment rather than merely restricted. VIEWER and OPERATOR are unaffected.
A deployment that needs "an admin who manages users but must not read file contents" needs the enterprise layer to express it, by granting the permission to a custom role and narrowing ADMIN.
AuditLog consumers must tolerate null before and after. Read events have neither. This is visible on the wire, including to syslog and webhook forwarding.
A note on how this was built
Every slice shipped with a defect that only a real environment found, and CI was green on all of them: a lowercase resource type answering 500 instead of 400; built-in role defaults living in three places rather than two; a screen that could report drift but never name the machine; and a parameter comparison that pushed one node's column off-screen entirely.
The last was found by copying the table and pasting it, revealing a value that had never been on screen. The API, the audit rows, the diff logic and the built bundle had all passed.
Full changelog: v1.7.7...v1.8.0