AI agents: see /llms.txt for a full index of this site, or /llms-full.txt for concatenated documentation.

Workshop Docs

Enterprise control plane for Santa. Manage rules, approvals, telemetry, and policies across your macOS fleet.

Workshop Docs
View chapters on this page

Package Rules

A package rule targets a piece of software by name in a package catalog (for example a Homebrew cask or an npm package) rather than by a raw hash or Team ID. Workshop resolves the package to its concrete identifiers and materializes ordinary execution rules from them. As new versions are published (or old ones stop matching your filters), Workshop re-resolves the package and adds or removes the materialized rules automatically, so you manage one package rule instead of a growing list of hashes.

One package rule can cover many versions and, depending on the rule type, many binaries per version. That reach is what makes the filters below useful: they let you narrow a broad package rule down to exactly the versions and binaries you want to trust.

Creating a package rule

Open Rules → Package Rules → New Package Rule. A package rule has a few core fields plus the optional filters described later.

Package source and name

Pick the Package Source that hosts the software, then enter the Package Name as it appears in that catalog:

SourceName example
Homebrewwget (formula)
Homebrew Caskfirefox (cask)
NPMexpress
GitHubowner/repo
Rust (crates.io)rustls
VS Codepublisher.name
Terraform Pluginhashicorp/aws
URLa direct download URL
Nixripgrep (nixpkgs)

Workshop looks the package up in the catalog and reports how many execution rules it will create so you can see the reach before saving.

Tags

Package rules respect the same tag scoping as other rules. Leave tags empty to apply the rule everywhere, or add one or more tags to limit it to the hosts that carry them.

Policy

The Policy decides what the materialized execution rules do:

  • Allow: permit the package’s binaries to run.
  • Allow as Compiler: allow the binaries and treat them as trusted compilers for transitive allowlisting.
  • Block: prevent the package’s binaries from running.
  • CEL: evaluate a CEL expression at execution time to decide allow or block.

For Block and CEL policies you can set an optional Custom Block Message (shown to the user when execution is blocked, HTML supported) and a Custom URL for a help or appeal link.

Preferred rule type

A package rule materializes into execution rules of the type you pick under Preferred Rule Type:

Rule typeMaterializes toPer-binary filter
Binaryone rule per binaryavailable
CDHashone rule per binaryavailable
Signing IDone rule per signing identitynot applicable
Team IDone rule per signing identitynot applicable
Certificateone rule per signing identitynot applicable

Binary and CDHash are the only types that expose per-binary identifiers, so the binary-selection filter is available only for them. The signing-identity types cover every binary signed with that identity, so there is nothing per-binary to filter.

Simple filters

Every package rule can be narrowed with the built-in filters, all optional:

  • Min Release Date and Max Release Date: keep only versions released within a date window.
  • Version Filter: an RE2 regular expression matched against the version string (for example ^1\. to pin to the 1.x series).

These are evaluated when Workshop resolves the package.

Advanced CEL filters 2026.7

Two optional CEL expressions give you finer control than the simple filters. Open Advanced (CEL Filters) in the package rule dialog to set them.

Both filters:

  • Must evaluate to a boolean. true keeps the version or binary, false drops it.
  • Are ANDed with the simple filters above and with each other. A version or binary is covered only if every filter that applies to it returns true.
  • Are evaluated by Workshop when it materializes the rule, not by Santa at execution time. This is a different, smaller surface than the execution-context CEL described in the CEL Guide: there is no execution context here, so no target.* signature fields, args, ancestors, or return-value keywords like ALLOWLIST, only the variables listed below and a boolean result. (The target variable in the version filter below is unrelated to execution CEL’s target: here it is a plain build-target string.)

Version selection

The Version Selection filter runs for each build of each version. A version can ship several builds, one per platform target, and target lets you filter those individually. Use it to soak-test new releases, keep only the newest few versions, or drop builds for platforms you don’t ship.

Variables:

VariableTypeDescription
versionstringThe version string, e.g. 1.25.0
released_attimestampUpstream release date of this version
targetstringBuild target, e.g. arm64_tahoe
latest_released_attimestampRelease date of the newest version in the filtered set
version_rankint1 for the newest version, increasing for older ones
version_countintNumber of versions in the filtered set

version_rank, version_count, and latest_released_at are computed over the versions that already passed the simple filters (date window and version regexp), not the entire upstream catalog. Tightening a simple filter changes all three.

Helper functions (the same relative-time helpers used elsewhere in Workshop CEL):

now()      // the current time
today()    // the current date at UTC midnight
days(N)    // a duration of N days

Use now() - days(30) for relative windows. CEL’s duration() literal does not accept a day suffix (duration("30d") is invalid), so build day-scale durations with days(N).

Examples:

// Soak new releases: only trust versions at least 30 days old.
released_at < now() - days(30)
// Keep only versions released within 60 days of the newest one.
released_at >= latest_released_at - days(60)
// Keep only the five newest versions.
version_rank <= 5
// Drop a build target you don't deploy.
!target.contains("bigsur")
// Only versions released in roughly the last year.
released_at > today() - days(365)

Binary selection

The Binary Selection filter runs once per binary within a matched version. It is available only for the Binary and CDHash rule types, which create one rule per binary. Use it to allow a package’s main executable while excluding the bundled helper binaries it ships.

Variables:

VariableTypeDescription
pathstringPath of the binary inside the package, e.g. Firefox.app/Contents/MacOS/firefox
hashstringSHA-256 hash of the binary
cdhashstringCode directory hash of the binary

Paths are package-relative: they include the bundle root (for example Firefox.app/Contents/MacOS/firefox, or wget/1.25.0/bin/wget for a formula), not a path anchored at Contents/. Match with contains and endsWith rather than startsWith so a rule keeps working regardless of the bundle name:

// Exclude bundled helper binaries (auto-updaters, embedded frameworks, etc.).
!path.contains("/Contents/Frameworks/")
// Allow only the app's main executable.
path.endsWith("/Contents/MacOS/firefox")

Materialized rules are ordinary execution rules and are enforced by Santa like any other. See Rule Packs for the related mechanism that materializes a curated set of rules maintained by North Pole Security.