Policy¶

patcher.policy holds the catalog rules that are deliberately hardcoded rather than user-configurable. Each constant is owned by a different layer (ingest, matching, stitch, export) and is independent of the others. They live in one module so the decisions are reviewable in a single place instead of being scattered next to the code that happens to read them.

Catalog constants¶

INGEST_EXCLUDED_TEAM_IDS

Apple Developer Team IDs dropped while parsing Installomator fragments. These are labels with broken or non-standard data (for example, lcadvancedvpnclient, and the zulujdk* labels whose versioning relies on HTML scraping). Excluding them at ingest keeps the bad records out of the catalog entirely.

IGNORED_TITLES

The client matcher’s skip list of Jamf patch-title names, written as glob patterns (Adobe *, Jamf *, Apple macOS *, …). A title here is never matched against the catalog, either because it is managed out-of-band (Adobe via the Admin Console), updated by its own mechanism (Jamf, Apple), or no longer supported. This is distinct from the user-configurable ignored_titles plist setting, which is a per-install preference layered on top.

CURATED_BUNDLE_IDS

A slug → bundle_id seed used during the catalog stitch. Some install sources carry no bundle identifier, so Jamf App Installers titles cannot attach to them automatically. Each entry supplies the authoritative bundleId (taken from the App Installers titles API) so the stitch can bridge the gap for high-value apps like Zoom, Docker, and OBS.

IGNORED_EXPORT_COLUMNS

The internal columns dropped from the rendered reports. See the field policy below.

Export field policy¶

A PatchTitle carries a few fields that exist purely as internal plumbing: title_id and name_id are Jamf join keys, and install_label / homebrew_cask are raw matcher output. Whether those reach an export depends on the format, because the formats serve two different audiences.

Rendered reports (PDF, Excel, HTML) are for a human reading a patch report. Exporter drops IGNORED_EXPORT_COLUMNS from the DataFrame before rendering, so the join keys and raw matcher fields never show up as columns. (The Homebrew column is the exception: the raw homebrew_cask field is dropped, then a readable Homebrew column is derived from it only when a cask actually matched.)

JSON is a machine-to-machine transport. It is serialized straight from the models via titles_to_dict() with no DataFrame round-trip, so it keeps every field, title_id and name_id included. A downstream consumer building a dashboard or alerting pipeline needs those identifiers to join back against Jamf.

Note

There is no toggle today: JSON always keeps the internal keys and the rendered formats always drop them. A future option could let JSON callers opt into the human-facing shape (dropping the internal keys) when they only want the report-visible fields.