Imported from simp/pupmod-simp-polkit (
AGENTS.md). Install upstream withnpx skills add simp/pupmod-simp-polkit. Copyright stays with the author.
AGENTS.md
This file provides guidance to AI agents when working with code in this repository.
What this module does
simp-polkit is a SIMP Puppet module that manages PolicyKit (polkit) on
Enterprise Linux systems. It installs and enables the polkit package/service,
optionally manages the polkitd service user, and provides defined types for
adding authorization policies in both the modern JavaScript rules.d format
(polkit::authorization::rule / polkit::authorization::basic_policy) and the
legacy Local Authority .pkla format (polkit::local_authority)
(metadata.json summary, manifests/init.pp).
The module is OS-gated and inert by default on unsupported systems. The main
class and every public defined type wrap their logic in
simplib::module_metadata::os_supported(load_module_metadata($module_name), { 'release_match' => 'major' }) and do nothing (the class only optionally warns)
when the OS is not in metadata.json's support matrix
(manifests/init.pp, manifests/local_authority.pp,
manifests/authorization/basic_policy.pp, manifests/authorization/rule.pp).
Business logic
-
polkit(manifests/init.pp) — Public entry class (notassert_private()'d; consumersinclude 'polkit'). Parameters (init.pp):$manage_polkit_user(Boolean, defaulttrue) — whether to manage thepolkitduser. Enabled by default because newer polkit versions require the user to be in the group assigned to/procto function (init.pp).$package_ensure(Polkit::PackageEnsure) — defaults tosimplib::lookup('simp_options::package_ensure', { 'default_value' => 'installed' })(init.pp).$warn_on_unsupported_os(Boolean, defaulttrue) — emit awarning()(notfail()) on an unsupported OS (init.pp,44-46).
Control flow (
init.pp):- When the OS is supported:
include polkit::installandinclude polkit::service, withClass['polkit::install'] ~> Class['polkit::service']; and if$manage_polkit_user, additionallyinclude polkit::userorderedClass['polkit::install'] -> Class['polkit::user'] ~> Class['polkit::service']. - When the OS is not supported and
$warn_on_unsupported_os: emit awarning()naming the OS and how to silence it — and manage nothing else.
-
polkit::install(manifests/install.pp) —assert_private()'d (install.pp). Managespackage { $package_name }(default'polkit') at$package_ensure(defaults to$polkit::package_ensure,install.pp). -
polkit::service(manifests/service.pp) — Public (notassert_private()'d; it instead callssimplib::assert_metadata($module_name)atservice.pp). Managesservice { $service_name }(default'polkit')ensure => running,enable => true,hasrestart/hasstatus => true(service.pp). -
polkit::user(manifests/user.pp) —assert_private()'d (user.pp). Manages thepolkitduser. Reads the/procmount's group from thesimplib__mountpointsfact ($facts.dig('simplib__mountpoints', '/proc', 'options_hash', '_gid__group'),user.pp):- If the
/procgroup is set, it is prepended to the user'sgroups(user.pp). - Else, if
/procis mounted withhidepid > 0, it declarespolkit::user::hidepid_notifyatwarningordebuglevel depending on$report_proc_issues(user.pp). - Declares
user { $user: * => $_user_options }via the splat operator (user.pp).
- If the
-
polkit::user::hidepid_notify(manifests/user/hidepid_notify.pp) —assert_private()'d (hidepid_notify.pp). Split into its own class purely for notification-chaining correctness (hidepid_notify.pp). Emits anotifyat$log_levelwarning that/procneeds agidoption whenhidepid > 0(hidepid_notify.pp). -
polkit::local_authority(manifests/local_authority.pp) — Public defined type. Writes a legacy.pklafile. Requires at least one of$result_active/$result_inactive/$result_any, elsefail()(local_authority.pp). Maps the$authorityenum to a numbered directory (vendor→10-vendor.d…mandatory→90-mandatory.d,local_authority.pp), validates$identityviapolkit::validate_identity()(local_authority.pp), and manages afilerendered fromtemplates/local_authority.erb,require => Package['polkit'](local_authority.pp). -
polkit::authorization::rule(manifests/authorization/rule.pp) — Public defined type. Low-level: writes an arbitrary$contentstring to${rulesd}/${priority}-${sanitized_name}.rules(default rulesd/etc/polkit-1/rules.d). The name is downcased and a fixed set of shell/path metacharacters (space/ ! @ # $ % ^ & *and[/|) is replaced with_viaregsubst— other punctuation (e.g..,-,:) is left as-is (rule.pp). -
polkit::authorization::basic_policy(manifests/authorization/basic_policy.pp) — Public defined type. A convenience wrapper that renderstemplates/basic_policy.erb(which builds the JavaScript condition from$action_id/$user/$group/$local/$active, or uses a supplied$condition) and hands the result topolkit::authorization::rule(basic_policy.pp). If no$conditionis given,$action_idis required, elsefail()(basic_policy.pp).
Gotchas / non-obvious details
- The module is inert, not failing, on unsupported OSes. The main class and
all three public defined types wrap their logic in the
os_supportedcheck and simply do nothing on an unsupported OS (init.pp,local_authority.pp,basic_policy.pp,rule.pp). The comment "this defined type is inert if called from an unsupported OS" appears verbatim in each define. This is deliberate backwards compatibility. polkit::serviceis public but is the class that asserts metadata. It is the one class callingsimplib::assert_metadata($module_name)(service.pp), not the entry class.polkit::install,polkit::user, andpolkit::user::hidepid_notifyare the onlyassert_private()'d classes.$manage_polkit_userdefaults totruefor a reason. Newer polkit needspolkitdin the/procgroup; the module wires the group in from thesimplib__mountpointsfact (init.pp,user.pp).- The hidepid warning only fires under specific conditions —
/procmounted withhidepid > 0and no_gid__groupset (user.pp,hidepid_notify.pp). The check is duplicated in bothpolkit::userandpolkit::user::hidepid_notify. polkit::validate_identityacceptsunix-netgroupbut the type/docstrings advertise fewer. The Ruby function's valid headers areunix-user,unix-group,unix-netgroup, plus the literaldefault; netgroups may not contain a glob (lib/puppet/functions/polkit/validate_identity.rb). The local_authority docstring only mentions user/group (local_authority.pp).- The
basic_policydocstring references apolkit::conditionfunction that does not exist.basic_policy.ppsays the define "can use the polkit::condition function to generate a condition", but no such function is present inlib/— the condition is actually built inline insidetemplates/basic_policy.erb. Treat the docstring as stale. simp/simp_optionsis NOT a declared dependency inmetadata.json, yet the manifest consumes thesimp_options::*seam viasimplib::lookup(provided bysimp/simplib).simp_optionsdoes not even appear in.fixtures.yml— onlysimplibandstdlibare checked out.- Acceptance runs in CI under podman/docker.
spec/acceptance/suites/default/has beaker specs, and.github/workflows/pr_tests.ymlruns them in anacceptancejob overdocker_*nodesets (see Repository layout).
The simp_options / simplib::lookup seam
This is the module's SIMP configuration seam. There is exactly one such call:
| File | Key | default_value |
|---|---|---|
init.pp |
simp_options::package_ensure |
'installed' |
polkit::install::package_ensure and polkit::service::ensure do not call
the seam directly — install inherits $polkit::package_ensure (install.pp),
and service::ensure hard-defaults to 'running' (service.pp). Keep
routing SIMP feature toggles through simplib::lookup('simp_options::*', { 'default_value' => ... }) with an explicit default rather than assuming
simp_options is included.
Dependencies
Module dependencies (from metadata.json dependencies):
puppetlabs/stdlib>= 8.0.0 < 10.0.0(providesStdlib::Absolutepath, string helpers).simp/simplib>= 4.9.0 < 6.0.0(providessimplib::lookup,simplib::assert_metadata,simplib::module_metadata::os_supported, and thesimplib__mountpointsfact).
There is no simp.optional_dependencies key in metadata.json.
Fixture-only dependencies (from .fixtures.yml, present for test compilation,
not runtime deps): simplib, stdlib (the runtime deps above; nothing else).
Runtime requirement (from metadata.json requirements): `openvox
= 8.0.0 < 9.0.0`.
Supported OS matrix (from metadata.json operatingsystem_support): CentOS
9/10; RedHat 8/9/10; OracleLinux 8/9/10; Rocky 8/9/10; AlmaLinux 8/9/10.
Repository layout
manifests/init.pp— thepolkitentry class (OS gate + install/service/user wiring).manifests/install.pp— privatepolkit::install(thepolkitpackage).manifests/service.pp— publicpolkit::service(thepolkitservice; callsassert_metadata).manifests/user.pp— privatepolkit::user(thepolkitduser +/procgroup logic).manifests/user/hidepid_notify.pp— privatepolkit::user::hidepid_notify(hidepid warning, split out for chaining).manifests/local_authority.pp— public define writing legacy.pklafiles.manifests/authorization/rule.pp— public define writing raw.rulesfiles.manifests/authorization/basic_policy.pp— public define wrappingrulewith a generated JS condition.types/authority.pp—Polkit::Authorityenum (vendor/org/site/local/mandatory).types/packageensure.pp—Polkit::PackageEnsure(String or ensure enum).types/result.pp—Polkit::Result(optional polkit result enum).lib/puppet/functions/polkit/validate_identity.rb— Ruby function validating polkit identity strings.templates/local_authority.erb— renders.pklacontent.templates/basic_policy.erb— renders the JS rule + builds the condition.metadata.json— deps, OS matrix, OpenVox requirement (no optional deps, nodata).spec/classes/{init,user}_spec.rb,spec/defines/{local_authority,authorization/basic_policy,authorization/rule}_spec.rb,spec/functions/polkit/validate_identity_spec.rb— rspec-puppet unit tests.spec/acceptance/suites/default/{00_default,10_proc_hidepid}_spec.rb— beaker acceptance specs;spec/acceptance/nodesets/ships bothdocker_*and vagrant nodesets (almalinux/centos/oel/rhel/rocky8/9/10).REFERENCE.md— generated Puppet Strings reference.- No
data/orhiera.yaml— this module ships no module data; parameter defaults live in the manifests and inmetadata.json. - Acceptance runs in CI:
.github/workflows/pr_tests.ymlhas anacceptancejob (pr_tests.yml) alongsidepuppet-syntax,puppet-style,ruby-style,file-checks,releng-checks, andspec-tests(matrix over Puppet/Ruby versions). Its matrix nodes aredocker_alma8/9/10,docker_centos9/10,docker_oel8/9/10,docker_rhel8/9, anddocker_rocky8/9/10. It startspodman.socket, exportsDOCKER_HOST, and runsbundle exec rake beaker:suites[default,<node>]withBEAKER_HYPERVISOR=docker(pr_tests.yml).
Common commands
# Install dependencies
bundle install
# Run all unit tests
bundle exec rake spec
# Run a single spec
bundle exec rspec spec/classes/init_spec.rb
# Puppet lint
bundle exec rake lint
# Ruby lint
bundle exec rake rubocop
# Regenerate REFERENCE.md from puppet-strings docstrings
puppet strings generate --format markdown --out REFERENCE.md
# Run the default beaker acceptance suite (CI runs the docker_* nodes)
bundle exec rake beaker:suites[default]
Relevant gem pins (from Gemfile): puppetlabs_spec_helper ~> 8.0.0,
simp-rake-helpers ~> 5.24.0, simp-rspec-puppet-facts ~> 4.0.0,
simp-beaker-helpers ~> 2.0.0. Rubocop is pinned to ~> 1.88.0. The test group
installs both openvox and puppet gems, defaulting to the >= 8 < 9 range.
spec/spec_helper.rb requires puppetlabs_spec_helper/module_spec_helper and
simp/rspec-puppet-facts (spec/spec_helper.rb).
Conventions
- Preserve the
@summary/@parampuppet-strings docstrings on classes, defines, types, and the Ruby function — they driveREFERENCE.md. RegenerateREFERENCE.mdafter changing docs or parameters. - Keep every public entry point OS-gated with
simplib::module_metadata::os_supported(load_module_metadata($module_name), { 'release_match' => 'major' })— the module is inert (not failing) on unsupported OSes, and callers rely on that. - Continue routing SIMP feature toggles through
simplib::lookup('simp_options::*', { 'default_value' => ... })rather than assumingsimp_optionsis included. - Keep private helper classes (
install,user,hidepid_notify)assert_private()'d; the public seam ispolkit,polkit::service, and the three defined types. Gemfile,spec/spec_helper.rb, and.github/workflows/pr_tests.ymlcarry a puppetsync notice — they are baseline-managed and the next sync overwrites local edits. Push changes to those files upstream to the baseline, not here.- Match the existing 2-space Puppet indentation and aligned-arrow parameter
style used in
manifests/.