Files
puppet-catalog-tools/README.md
T
unkin-agent 3f14554fae
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
read facts from PuppetDB's query API
- rename internal/pdbmux to internal/puppetdb
- fetch facts with one GET /pdb/query/v4/facts AST query per node
- drop the per-node fallback route and its two response shapes
- rename --pdb to --puppetdb, CATALOG_DIFF_PDB to CATALOG_DIFF_PUPPETDB and
  pdb_url to puppetdb_url
- describe the fact source generically in the README and AGENTS.md
2026-09-12 17:49:57 +10:00

5.5 KiB

puppet-catalog-tools

CLI tooling for the Puppet estate. Currently one binary:

  • catalog-diff — compiles a host's catalog in a base environment and in the environment built from the branch under test, then diffs the two.

Catalogs are compiled over the puppetserver API (POST /puppet/v4/catalog) with facts read from PuppetDB. Nothing is compiled locally and nothing is persisted on the server.

Install

dnf install puppet-catalog-tools      # from the artifactapi rpm-internal repo
# or
make build                            # -> dist/catalog-diff

Usage

catalog-diff web01.example.net --branch benvin/motd-change
catalog-diff web01.example.net --environment benvin_motd_change --json
catalog-diff web01.example.net --branch benvin/motd-change --testonly
Flag Description
-b, --branch branch under test (required unless --environment is given)
--environment explicit environment name, bypasses branch name conversion
--base base environment to diff against (default develop)
--testonly compile the test environment only; result via exit code
--json machine-readable output
--server puppetserver base URL (default https://puppet.k8s.syd1.au.unkin.net:8140)
--puppetdb PuppetDB base URL (default https://pdbmux.k8s.syd1.au.unkin.net)
--cert / --key / --cacert client mTLS material
--timeout per-compile timeout (default 10m; must be positive)
--retry retries for transient compile or transport failures (default 2, range 0-20; a failed compiler-side PuppetDB query counts, a manifest error does not)
--include-classes diff Class resources (ignored by default; they manage nothing)
--ignore ignore resources matching Type[Title] (glob), repeatable
--ignore-attr ignore a parameter on every resource, repeatable
--display-datatype-changes report changes where only the datatype differs (28 vs "28")
--display-detail-add expand the parameters of added resources
--display-source-file-line print the manifest file and line each change came from

Both compilations run concurrently, so a diff costs roughly one compile.

Exit codes

Code Meaning
0 catalogs compiled, no differences
1 catalog compilation failed in one or both environments
2 catalogs compiled, differences present
3 transport, auth, environment-mismatch or usage error

--testonly prints nothing on success and returns 0, 1 or 3 — never 2.

Configuration

Precedence (lowest to highest): defaults < config file < env vars < flags.

Config file: $XDG_CONFIG_HOME/puppet-catalog-tools/config.yaml (~/.config/puppet-catalog-tools/config.yaml). Write a default with catalog-diff config init; print the active values with catalog-diff config show.

server_url: https://puppet.k8s.syd1.au.unkin.net:8140
puppetdb_url: https://pdbmux.k8s.syd1.au.unkin.net
cert: /etc/puppetlabs/puppet/ssl/certs/catalog-diff.pem
key: /etc/puppetlabs/puppet/ssl/private_keys/catalog-diff.pem
cacert: /etc/puppetlabs/puppet/ssl/certs/ca.pem
base_environment: develop
Env var Config key
CATALOG_DIFF_SERVER server_url
CATALOG_DIFF_PUPPETDB puppetdb_url
CATALOG_DIFF_CERT cert
CATALOG_DIFF_KEY key
CATALOG_DIFF_CACERT cacert
CATALOG_DIFF_BASE_ENVIRONMENT base_environment

catalog-diff needs a client certificate whose certname is allowed to POST /puppet/v4/catalog in the puppetserver auth.conf. PuppetDB is queried without credentials.

Branch to environment name

Puppet environment names must match \A[a-z0-9_]+\Z, so a branch name is converted the way g10k deploys it: every character outside [0-9A-Za-z_] becomes _ (benvin/foo-bar -> benvin_foo_bar). Case is preserved, because g10k preserves it — a branch with capitals therefore deploys to a directory Puppet rejects, and catalog-diff fails fast telling you to rename the branch or pass --environment. --environment bypasses the conversion entirely.

Environment override

Classification runs through an exec ENC (encapic -> encapi), and an ENC-supplied environment outranks the requested one. Every request sets options.prefer_requested_environment, and the returned catalog's own environment is always compared against the one requested. A mismatch between two named environments is a hard error (exit 3) rather than a silent diff of an environment against itself. A response that decodes without an environment name at all is reported as a protocol mismatch instead, because that is a client/ server problem rather than a classification one.

What a catalog diff cannot see

  • Facts come from PuppetDB's last report, not a live agent run, so changes to custom facts are not tested.
  • Provider changes and order-of-operations problems (dependency cycles) do not appear in a catalog.
  • Catalogs are fetched over the API rather than compiled from a checkout, so a change to a static file's content — without its source path changing — produces no readable text diff.

Puppet catalogs can contain unencrypted secrets. Parameters the catalog marks as sensitive are replaced with a digest so a change is still visible without the plaintext reaching stdout or a CI log; anything Puppet does not mark stays in the clear.

Development

make build test lint fmt pre-commit
make rpm            # build + package into dist/*.rpm via nfpm

Golden-file tests: go test ./internal/catalog -update rewrites them.