diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c770028..7572f7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,3 +32,5 @@ jobs: run: pytest promise-types/ -v - name: Lint policy with CFEngine CLI run: cfengine lint --strict no ./ + - name: Check formatting with CFEngine CLI + run: cfengine format --check diff --git a/examples/gpg/password-store-sync.cf b/examples/gpg/password-store-sync.cf index 99132ca..c862c1d 100644 --- a/examples/gpg/password-store-sync.cf +++ b/examples/gpg/password-store-sync.cf @@ -15,12 +15,19 @@ bundle agent main vars: # for gpg_keys promise, pass a keylist data similar to this proposed standard with the addition of the `ascii` property # https://datatracker.ietf.org/doc/draft-mccain-keylist/ (from https://github.com/firstlookmedia/gpgsync project) - # "keylist" data => readjson("/home/user/keylist.json"); - + # "keylist" data => readjson("/home/user/keylist.json"); # Or assembly the information using some policy data manipulation and jq (https://stedolan.github.io/jq/) magic - "fingerprint_files" slist => findfiles("/home/user/.password-store/.pub-keys/*.fp"); - "keys[$(fingerprint_files)][fingerprint]" string => readfile( $(fingerprint_files) ); - "keys[$(fingerprint_files)][ascii]" string => readfile( regex_replace( $(fingerprint_files), ".fp$", ".asc", "") ); + "fingerprint_files" + slist => findfiles("/home/user/.password-store/.pub-keys/*.fp"); + + "keys[$(fingerprint_files)][fingerprint]" + string => readfile($(fingerprint_files)); + + "keys[$(fingerprint_files)][ascii]" + string => readfile( + regex_replace($(fingerprint_files), ".fp$", ".asc", "") + ); + "keylist" data => mapdata("json_pipe", '$(def.jq) {"keys":[.[]]}', keys); git: @@ -28,6 +35,5 @@ bundle agent main repository => "https://github.com/user/my-passwords"; gpg_keys: - "/home/user/.gnupg" - keylist => storejson( @(keylist[0]) ); + "/home/user/.gnupg" keylist => storejson(@(keylist[0])); } diff --git a/examples/rss/rss.cf b/examples/rss/rss.cf index 6b70de5..2cc66f2 100644 --- a/examples/rss/rss.cf +++ b/examples/rss/rss.cf @@ -1,4 +1,3 @@ - promise agent rss { path => "$(example_rss_promise_common.path)"; @@ -15,29 +14,36 @@ bundle agent example_rss_promise # @brief Promise a files content to be the =description= of an item selected from a channel in an RSS feed { rss: - "/tmp/ISS-oldest.txt" # Contains Item description - # REPAIRED if content on disk changes - # KEPT if content on disk does not need changed - # NOTKEPT if unable to fetch rss, unable to re-write content + "/tmp/ISS-oldest.txt" + # Contains Item description + # REPAIRED if content on disk changes + # KEPT if content on disk does not need changed + # NOTKEPT if unable to fetch rss, unable to re-write content + # Default to newest feed => "https://blogs.nasa.gov/stationreport/feed/", - select => "oldest"; # Default to newest + select => "oldest"; - "/tmp/ISS-random.txt" # Contains Item description - # REPAIRED if content on disk changes - # KEPT if content on disk does not need changed - # NOTKEPT if unable to fetch rss, unable to re-write content + "/tmp/ISS-random.txt" + # Contains Item description + # REPAIRED if content on disk changes + # KEPT if content on disk does not need changed + # NOTKEPT if unable to fetch rss, unable to re-write content + # Default to newest feed => "https://blogs.nasa.gov/stationreport/feed/", - select => "random"; # Default to newest + select => "random"; - "/tmp/ISS-newest-from-local-file-source.txt" # Contains Item description - # REPAIRED if content on disk changes - # KEPT if content on disk does not need changed - # NOTKEPT if unable to fetch rss, unable to re-write content + "/tmp/ISS-newest-from-local-file-source.txt" + # Contains Item description + # REPAIRED if content on disk changes + # KEPT if content on disk does not need changed + # NOTKEPT if unable to fetch rss, unable to re-write content + # Default to newest feed => "/tmp/iss.xml", - select => "newest"; # Default to newest + select => "newest"; } bundle agent __main__ { - methods: "example_rss_promise"; + methods: + "example_rss_promise"; } diff --git a/examples/site-up/site_up.cf b/examples/site-up/site_up.cf index 6de97f1..8f50db3 100644 --- a/examples/site-up/site_up.cf +++ b/examples/site-up/site_up.cf @@ -14,6 +14,5 @@ bundle agent site_up_autorun "http://172.28.128.10"; "https://cfengine.com/"; "https://cfengine2.com/"; - "https://unavailable.com" - skip_ssl_verification => "true"; + "https://unavailable.com" skip_ssl_verification => "true"; } diff --git a/inventory/inventory-fde/inventory-fde.cf b/inventory/inventory-fde/inventory-fde.cf index 323e248..063af89 100644 --- a/inventory/inventory-fde/inventory-fde.cf +++ b/inventory/inventory-fde/inventory-fde.cf @@ -1,22 +1,20 @@ body file control { - namespace => "inventory_fde"; + namespace => "inventory_fde"; } - # Duplicated from the CFEngine standard library so this module can be parsed # and tested standalone without loading the full masterfiles. # _tidy: lib/files.cf body delete tidy # _in_shell: lib/commands.cf body contain in_shell - body delete _tidy { - dirlinks => "delete"; - rmdirs => "true"; + dirlinks => "delete"; + rmdirs => "true"; } body contain _in_shell { - useshell => "useshell"; + useshell => "useshell"; } bundle agent main @@ -30,15 +28,13 @@ bundle agent main { vars: linux:: - "_dmsetup" string => "/sbin/dmsetup"; + "_dmsetup" string => "/sbin/dmsetup"; "_cryptsetup" string => "/sbin/cryptsetup"; classes: linux:: - "_have_dmsetup" - expression => isexecutable("${_dmsetup}"); - "_have_cryptsetup" - expression => isexecutable("${_cryptsetup}"); + "_have_dmsetup" expression => isexecutable("${_dmsetup}"); + "_have_cryptsetup" expression => isexecutable("${_cryptsetup}"); # Flag each dm device that has a CRYPT uuid "_dm_is_crypt_${_dm_devices}" @@ -47,26 +43,35 @@ bundle agent main # Classify crypt type per device "_dm_is_luks2_${_dm_devices}" expression => strcmp("LUKS2", "${_dm_crypt_type[${_dm_devices}]}"); + "_dm_is_luks1_${_dm_devices}" expression => strcmp("LUKS1", "${_dm_crypt_type[${_dm_devices}]}"); # Classify each mount: real block device? (starts with /dev/, not a loop device) "_is_real_block_${_mnt_idx}" - expression => regcmp("/dev/(?!loop)\S+", "${_mnt_data[${_mnt_idx}][0]}"); + expression => regcmp( + "/dev/(?!loop)\S+", "${_mnt_data[${_mnt_idx}][0]}" + ); # Classify each real block mount: is device in the crypt paths list? "_is_encrypted_${_mnt_idx}" - expression => regcmp("(${_crypt_paths_regex})", "${_mnt_data[${_mnt_idx}][0]}"), + expression => regcmp( + "(${_crypt_paths_regex})", "${_mnt_data[${_mnt_idx}][0]}" + ), if => canonify("_is_real_block_${_mnt_idx}"); # LUKS1: flag enabled keyslots (slots 0-7, all share global cipher, all use PBKDF2) "_luks1_slot_enabled_${_dm_devices}_${_luks1_slots}" - expression => regcmp("(?s).*Key Slot ${_luks1_slots}: ENABLED.*", "${_luks1_dump[${_dm_devices}]}"), + expression => regcmp( + "(?s).*Key Slot ${_luks1_slots}: ENABLED.*", + "${_luks1_dump[${_dm_devices}]}" + ), if => canonify("_dm_is_luks1_${_dm_devices}"); # Summary classes "_has_encrypted" expression => isgreaterthan(length(_encrypted_mountpoints), 0); + "_has_unencrypted" expression => isgreaterthan(length(_unencrypted_mountpoints), 0); @@ -79,6 +84,7 @@ bundle agent main "_dm_uuid[${_dm_devices}]" string => readfile("/sys/block/${_dm_devices}/dm/uuid"), if => fileexists("/sys/block/${_dm_devices}/dm/uuid"); + "_dm_name[${_dm_devices}]" string => readfile("/sys/block/${_dm_devices}/dm/name"), if => fileexists("/sys/block/${_dm_devices}/dm/name"); @@ -87,26 +93,36 @@ bundle agent main "_crypt_mapper_path[${_dm_devices}]" string => "/dev/mapper/${_dm_name[${_dm_devices}]}", if => canonify("_dm_is_crypt_${_dm_devices}"); + "_crypt_dm_path[${_dm_devices}]" string => "/dev/${_dm_devices}", if => canonify("_dm_is_crypt_${_dm_devices}"); + "_all_crypt_paths" slist => { getvalues(_crypt_mapper_path), getvalues(_crypt_dm_path) }; # Build a regex alternation of all crypt device paths for matching "_crypt_paths_regex" - string => join("|", maplist(regex_replace("$(this)", "([./])", "\\\1", "g"), _all_crypt_paths)); + string => join( + "|", + maplist( + regex_replace("$(this)", "([./])", "\\\1", "g"), _all_crypt_paths + ) + ); # Extract the encryption type for crypt devices # UUID format: CRYPT--- "_dm_crypt_type[${_dm_devices}]" - string => regex_replace("${_dm_uuid[${_dm_devices}]}", "^CRYPT-([^-]+)-.*", "\1", ""), + string => regex_replace( + "${_dm_uuid[${_dm_devices}]}", "^CRYPT-([^-]+)-.*", "\1", "" + ), if => canonify("_dm_is_crypt_${_dm_devices}"); # Underlying block device for each crypt device (for cryptsetup luksDump) "_dm_slaves[${_dm_devices}]" slist => lsdir("/sys/block/${_dm_devices}/slaves", "[a-z].*", false), if => canonify("_dm_is_crypt_${_dm_devices}"); + "_dm_slave_dev[${_dm_devices}]" string => "/dev/${_dm_slaves[${_dm_devices}]}", if => canonify("_dm_is_crypt_${_dm_devices}"); @@ -114,7 +130,10 @@ bundle agent main # Parse /proc/mounts into indexed array # Columns: 0=device, 1=mountpoint, 2=fstype, 3=options, 4=dump, 5=pass "_n_mnt_lines" - int => readstringarrayidx("_mnt_data", "/proc/mounts", "\s*#[^\n]*", "\s+", inf, inf); + int => readstringarrayidx( + "_mnt_data", "/proc/mounts", "\s*#[^\n]*", "\s+", inf, inf + ); + "_mnt_idx" slist => getindices(_mnt_data); # Collect all real block device mountpoints @@ -135,12 +154,16 @@ bundle agent main string => "${_mnt_data[${_mnt_idx}][1]}", if => and( canonify("_dm_is_crypt_${_dm_devices}"), - regcmp("(/dev/mapper/${_dm_name[${_dm_devices}]}|/dev/${_dm_devices})", - "${_mnt_data[${_mnt_idx}][0]}")); + regcmp( + "(/dev/mapper/${_dm_name[${_dm_devices}]}|/dev/${_dm_devices})", + "${_mnt_data[${_mnt_idx}][0]}" + ) + ); # Derive unencrypted mountpoints as the difference "_all_real_mountpoints" slist => getvalues(_all_real_mountpoint); "_encrypted_mountpoints" slist => getvalues(_encrypted_mountpoint); + "_unencrypted_mountpoints" slist => difference(_all_real_mountpoints, _encrypted_mountpoints); @@ -149,8 +172,13 @@ bundle agent main # dmsetup table format: "0 crypt " "_dm_active_cipher[${_dm_devices}]" string => regex_replace( - execresult("${_dmsetup} table ${_dm_name[${_dm_devices}]}", "noshell"), - "^\d+\s+\d+\s+crypt\s+(\S+)\s+.*$", "\1", ""), + execresult( + "${_dmsetup} table ${_dm_name[${_dm_devices}]}", "noshell" + ), + "^\d+\s+\d+\s+crypt\s+(\S+)\s+.*$", + "\1", + "" + ), if => canonify("_dm_is_crypt_${_dm_devices}"); # --- LUKS2 keyslot info via cached JSON metadata --- @@ -163,22 +191,37 @@ bundle agent main string => filestat("${_luks2_cache[${_dm_devices}]}", "mtime"), if => and( canonify("_dm_is_luks2_${_dm_devices}"), - fileexists("${_luks2_cache[${_dm_devices}]}")); + fileexists("${_luks2_cache[${_dm_devices}]}") + ); # --- LUKS1 keyslot info via text parsing --- _have_cryptsetup:: "_luks1_slots" slist => { "0", "1", "2", "3", "4", "5", "6", "7" }; "_luks1_dump[${_dm_devices}]" - string => execresult("${_cryptsetup} luksDump ${_dm_slave_dev[${_dm_devices}]}", "noshell"), + string => execresult( + "${_cryptsetup} luksDump ${_dm_slave_dev[${_dm_devices}]}", + "noshell" + ), if => canonify("_dm_is_luks1_${_dm_devices}"); # LUKS1 global cipher: "Cipher name" + "Cipher mode" "_luks1_cipher_name[${_dm_devices}]" - string => regex_replace("${_luks1_dump[${_dm_devices}]}", "(?s).*Cipher name:\s+(\S+).*", "\1", ""), + string => regex_replace( + "${_luks1_dump[${_dm_devices}]}", + "(?s).*Cipher name:\s+(\S+).*", + "\1", + "" + ), if => canonify("_dm_is_luks1_${_dm_devices}"); + "_luks1_cipher_mode[${_dm_devices}]" - string => regex_replace("${_luks1_dump[${_dm_devices}]}", "(?s).*Cipher mode:\s+(\S+).*", "\1", ""), + string => regex_replace( + "${_luks1_dump[${_dm_devices}]}", + "(?s).*Cipher mode:\s+(\S+).*", + "\1", + "" + ), if => canonify("_dm_is_luks1_${_dm_devices}"); # Build per-keyslot summary for each ENABLED slot @@ -186,7 +229,8 @@ bundle agent main string => "${_luks1_slots}:${_luks1_cipher_name[${_dm_devices}]}-${_luks1_cipher_mode[${_dm_devices}]}/pbkdf2", if => and( canonify("_dm_is_luks1_${_dm_devices}"), - canonify("_luks1_slot_enabled_${_dm_devices}_${_luks1_slots}")); + canonify("_luks1_slot_enabled_${_dm_devices}_${_luks1_slots}") + ); "_luks1_ks_entries[${_dm_devices}]" slist => getvalues("_luks1_ks_entry[${_dm_devices}]"), @@ -197,12 +241,15 @@ bundle agent main if => canonify("_dm_is_luks1_${_dm_devices}"); # --- Inventory attributes --- - linux:: "fde_enabled" - string => ifelse("_has_encrypted.!_has_unencrypted", "yes", - "_has_encrypted._has_unencrypted", "partial", - "no"), + string => ifelse( + "_has_encrypted.!_has_unencrypted", + "yes", + "_has_encrypted._has_unencrypted", + "partial", + "no" + ), meta => { "inventory", "attribute_name=Full disk encryption enabled" }; "fde_method" @@ -225,7 +272,8 @@ bundle agent main string => "${_dm_mountpoint[${_dm_devices}]} : ${_dm_active_cipher[${_dm_devices}]}", if => and( canonify("_dm_is_crypt_${_dm_devices}"), - isvariable("_dm_mountpoint[${_dm_devices}]")); + isvariable("_dm_mountpoint[${_dm_devices}]") + ); _have_cryptsetup:: "_keyslot_info_entry[${_dm_devices}]" @@ -233,23 +281,29 @@ bundle agent main if => and( canonify("_dm_is_luks2_${_dm_devices}"), isvariable("_dm_mountpoint[${_dm_devices}]"), - isvariable("_luks2_ks_${_dm_devices}[keyslots]")); + isvariable("_luks2_ks_${_dm_devices}[keyslots]") + ); "_keyslot_info_entry[${_dm_devices}]" string => "${_dm_mountpoint[${_dm_devices}]} : ${_dm_keyslot_info[${_dm_devices}]}", if => and( canonify("_dm_is_luks1_${_dm_devices}"), - isvariable("_dm_mountpoint[${_dm_devices}]")); + isvariable("_dm_mountpoint[${_dm_devices}]") + ); _has_encrypted._have_dmsetup:: "fde_volume_cipher" slist => getvalues(_volume_cipher_entry), - meta => { "inventory", "attribute_name=Full disk encryption volume ciphers" }; + meta => { + "inventory", "attribute_name=Full disk encryption volume ciphers" + }; _has_encrypted._have_cryptsetup:: "fde_keyslot_info" slist => getvalues(_keyslot_info_entry), - meta => { "inventory", "attribute_name=Full disk encryption keyslot info" }; + meta => { + "inventory", "attribute_name=Full disk encryption keyslot info" + }; files: _have_cryptsetup:: @@ -260,20 +314,29 @@ bundle agent main canonify("_dm_is_luks2_${_dm_devices}"), fileexists("${_luks2_cache[${_dm_devices}]}"), isgreaterthan( - format("%d", eval("$(sys.systime) - ${_luks2_cache_mtime[${_dm_devices}]}")), - "86400")); + format( + "%d", + eval("$(sys.systime) - ${_luks2_cache_mtime[${_dm_devices}]}") + ), + "86400" + ) + ); commands: _have_cryptsetup:: "${_cryptsetup}" - arglist => { "luksDump", - "--dump-json-metadata", - "${_dm_slave_dev[${_dm_devices}]}", - ">", "${_luks2_cache[${_dm_devices}]}" }, + arglist => { + "luksDump", + "--dump-json-metadata", + "${_dm_slave_dev[${_dm_devices}]}", + ">", + "${_luks2_cache[${_dm_devices}]}", + }, contain => _in_shell, if => and( canonify("_dm_is_luks2_${_dm_devices}"), - not(fileexists("${_luks2_cache[${_dm_devices}]}"))); + not(fileexists("${_luks2_cache[${_dm_devices}]}")) + ); methods: _have_cryptsetup:: @@ -283,41 +346,35 @@ bundle agent main useresult => "_luks2_ks_${_dm_devices}", if => and( canonify("_dm_is_luks2_${_dm_devices}"), - fileexists("${_luks2_cache[${_dm_devices}]}")); + fileexists("${_luks2_cache[${_dm_devices}]}") + ); reports: - !linux.verbose_mode:: - "$(this.promise_filename): $(this.namespace):$(this.bundle) is currently only instrumented for Linux. Please consider making a pull request or filing a ticket to request your specific platform."; + !linux.verbose_mode:: + "$(this.promise_filename): $(this.namespace):$(this.bundle) is currently only instrumented for Linux. Please consider making a pull request or filing a ticket to request your specific platform."; } bundle agent luks2_keyslot_info(cache_file) # @brief Parse LUKS2 JSON metadata and return keyslot summary { vars: - "_json" - data => readjson("${cache_file}"); - - "_ks_idx" - slist => getindices("_json[keyslots]"); - - # Build per-keyslot summary: ":/" - "_ks_entry[${_ks_idx}]" - string => "${_ks_idx}:${_json[keyslots][${_ks_idx}][area][encryption]}/${_json[keyslots][${_ks_idx}][kdf][type]}"; + "_json" data => readjson("${cache_file}"); + "_ks_idx" slist => getindices("_json[keyslots]"); - "_ks_entries" - slist => getvalues(_ks_entry); + # Build per-keyslot summary: ":/" + "_ks_entry[${_ks_idx}]" + string => "${_ks_idx}:${_json[keyslots][${_ks_idx}][area][encryption]}/${_json[keyslots][${_ks_idx}][kdf][type]}"; - "_keyslots" - string => join(", ", sort(_ks_entries, "lex")); + "_ks_entries" slist => getvalues(_ks_entry); + "_keyslots" string => join(", ", sort(_ks_entries, "lex")); reports: - "${_keyslots}" - bundle_return_value_index => "keyslots"; + "${_keyslots}" bundle_return_value_index => "keyslots"; } body file control { - namespace => "default"; + namespace => "default"; } bundle agent __main__ diff --git a/inventory/inventory-fwupd/policy.cf b/inventory/inventory-fwupd/policy.cf index b824c34..3662dc7 100644 --- a/inventory/inventory-fwupd/policy.cf +++ b/inventory/inventory-fwupd/policy.cf @@ -21,7 +21,6 @@ # UPDATES_AVAILABLE - one or more devices have firmware updates pending # NO_DEVICES - fwupd present but reports no updatable devices # FWUPD_MISSING - fwupd not installed on the host - bundle agent inventory_fwupd_main { vars: @@ -29,20 +28,26 @@ bundle agent inventory_fwupd_main # Public API: referenced by manage-fwupd and other consumers. "fwupdmgr" string => ifelse( - fileexists("/usr/bin/fwupdmgr"), "/usr/bin/fwupdmgr", - fileexists("/usr/local/bin/fwupdmgr"), "/usr/local/bin/fwupdmgr", - "/usr/bin/fwupdmgr"); - - "_fwupd_dir" string => "$(sys.statedir)/fwupd"; + fileexists("/usr/bin/fwupdmgr"), + "/usr/bin/fwupdmgr", + fileexists("/usr/local/bin/fwupdmgr"), + "/usr/local/bin/fwupdmgr", + "/usr/bin/fwupdmgr" + ); + + "_fwupd_dir" string => "$(sys.statedir)/fwupd"; "_devices_src" string => "/var/cache/fwupd/devices.json"; "_updates_src" string => "$(_fwupd_dir)/inventory_updates.json"; "_security_src" string => "$(_fwupd_dir)/inventory_security.json"; - "_cache" string => "$(_fwupd_dir)/inventory_cache"; - "_template" string => "$(this.promise_dirname)/fwupd-inventory.mustache"; + "_cache" string => "$(_fwupd_dir)/inventory_cache"; + "_template" string => "$(this.promise_dirname)/fwupd-inventory.mustache"; # TTLs in seconds for the fwupdmgr-derived JSON caches. - "_updates_ttl" string => "43200"; # 12 h - "_security_ttl" string => "86400"; # 24 h + # 12 h: + "_updates_ttl" string => "43200"; + + # 24 h: + "_security_ttl" string => "86400"; # Pre-compute file mtimes here rather than calling filestat() inline # inside class expressions: nested $(filestat($(path), mtime)) does not @@ -50,20 +55,36 @@ bundle agent inventory_fwupd_main # silently never match. Defaulting to "0" when a file is missing lets # the class expressions below stay simple and total. "_cache_mtime" - string => ifelse(fileexists("$(_cache)"), - filestat("$(_cache)", "mtime"), "0"); + string => ifelse( + fileexists("$(_cache)"), filestat("$(_cache)", "mtime"), "0" + ); + "_devices_mtime" - string => ifelse(fileexists("$(_devices_src)"), - filestat("$(_devices_src)", "mtime"), "0"); + string => ifelse( + fileexists("$(_devices_src)"), + filestat("$(_devices_src)", "mtime"), + "0" + ); + "_updates_mtime" - string => ifelse(fileexists("$(_updates_src)"), - filestat("$(_updates_src)", "mtime"), "0"); + string => ifelse( + fileexists("$(_updates_src)"), + filestat("$(_updates_src)", "mtime"), + "0" + ); + "_security_mtime" - string => ifelse(fileexists("$(_security_src)"), - filestat("$(_security_src)", "mtime"), "0"); + string => ifelse( + fileexists("$(_security_src)"), + filestat("$(_security_src)", "mtime"), + "0" + ); - "_updates_age" string => eval("$(sys.systime) - $(_updates_mtime)", "math", "infix"); - "_security_age" string => eval("$(sys.systime) - $(_security_mtime)", "math", "infix"); + "_updates_age" + string => eval("$(sys.systime) - $(_updates_mtime)", "math", "infix"); + + "_security_age" + string => eval("$(sys.systime) - $(_security_mtime)", "math", "infix"); # /proc/1 mtime is when PID 1 (init) was exec'd, i.e., boot time on # Linux. Used below to force a refresh of the updates cache after a @@ -71,15 +92,17 @@ bundle agent inventory_fwupd_main # snapshot that still lists devices whose updates have already been # activated. "_boot_mtime" - string => ifelse(fileexists("/proc/1"), - filestat("/proc/1", "mtime"), "0"); + string => ifelse( + fileexists("/proc/1"), filestat("/proc/1", "mtime"), "0" + ); classes: linux:: "have_fwupdmgr" scope => "namespace", expression => isexecutable("$(fwupdmgr)"); - "_have_devices" expression => fileexists("$(_devices_src)"); + + "_have_devices" expression => fileexists("$(_devices_src)"); # CPU vendor classes for platform-specific compliance conditions. # /proc/cpuinfo vendor_id: "GenuineIntel" or "AuthenticAMD". @@ -87,6 +110,7 @@ bundle agent inventory_fwupd_main scope => "namespace", meta => { "report" }, expression => regline("vendor_id.*GenuineIntel", "/proc/cpuinfo"); + "fwupd_cpu_vendor_amd" scope => "namespace", meta => { "report" }, @@ -98,15 +122,17 @@ bundle agent inventory_fwupd_main "fwupd_oem_vendor_hp" scope => "namespace", meta => { "report" }, - expression => regline("(HP Inc\.|Hewlett-Packard)", - "/sys/class/dmi/id/sys_vendor"); + expression => regline( + "(HP Inc\.|Hewlett-Packard)", "/sys/class/dmi/id/sys_vendor" + ); linux.have_fwupdmgr:: - "_updates_stale" - not => fileexists("$(_updates_src)"); + "_updates_stale" not => fileexists("$(_updates_src)"); + "_updates_stale" expression => isgreaterthan("$(_updates_age)", "$(_updates_ttl)"), if => fileexists("$(_updates_src)"); + # Force refresh after a reboot: a pre-boot cache may still list # devices whose updates have been activated by the boot, and # consumers (manage-fwupd) would otherwise repeatedly re-apply @@ -115,8 +141,8 @@ bundle agent inventory_fwupd_main expression => islessthan("$(_updates_mtime)", "$(_boot_mtime)"), if => fileexists("$(_updates_src)"); - "_security_stale" - not => fileexists("$(_security_src)"); + "_security_stale" not => fileexists("$(_security_src)"); + "_security_stale" expression => isgreaterthan("$(_security_age)", "$(_security_ttl)"), if => fileexists("$(_security_src)"); @@ -125,53 +151,69 @@ bundle agent inventory_fwupd_main # Module-protocol cache must be rebuilt when any of the source JSON # files is newer than the cache itself, or when the cache is missing. "_cache_missing" not => fileexists("$(_cache)"); + "_cache_stale_devices" expression => isgreaterthan("$(_devices_mtime)", "$(_cache_mtime)"); + "_cache_stale_updates" expression => isgreaterthan("$(_updates_mtime)", "$(_cache_mtime)"), if => "have_fwupdmgr"; + "_cache_stale_security" expression => isgreaterthan("$(_security_mtime)", "$(_cache_mtime)"), if => "have_fwupdmgr"; + "_rebuild_cache" - or => { "_cache_missing", "_cache_stale_devices", - "_cache_stale_updates", "_cache_stale_security" }; + or => { + "_cache_missing", + "_cache_stale_devices", + "_cache_stale_updates", + "_cache_stale_security", + }; vars: linux.have_fwupdmgr._updates_stale:: "_updates_raw" string => execresult("$(fwupdmgr) get-updates --json", "noshell"); + "_updates_payload" - string => ifelse(regcmp("\s*\{.*", "$(_updates_raw)"), - "$(_updates_raw)", - '{"Devices":[]}'); + string => ifelse( + regcmp("\s*\{.*", "$(_updates_raw)"), + "$(_updates_raw)", + '{"Devices":[]}' + ); linux.have_fwupdmgr._security_stale:: "_security_raw" string => execresult("$(fwupdmgr) security --json", "noshell"); + "_security_payload" - string => ifelse(regcmp("\s*\{.*", "$(_security_raw)"), - "$(_security_raw)", - '{"SecurityAttributes":[]}'); + string => ifelse( + regcmp("\s*\{.*", "$(_security_raw)"), + "$(_security_raw)", + '{"SecurityAttributes":[]}' + ); files: linux:: - "$(_fwupd_dir)/." - create => "true"; + "$(_fwupd_dir)/." create => "true"; linux.have_fwupdmgr._updates_stale:: - "$(_updates_src)" - content => "$(_updates_payload)"; + "$(_updates_src)" content => "$(_updates_payload)"; linux.have_fwupdmgr._security_stale:: - "$(_security_src)" - content => "$(_security_payload)"; + "$(_security_src)" content => "$(_security_payload)"; methods: linux._have_devices._rebuild_cache:: - "render" usebundle => inventory_fwupd_render( - "$(_devices_src)", "$(_updates_src)", "$(_security_src)", - "$(_template)", "$(_cache)"); + "render" + usebundle => inventory_fwupd_render( + "$(_devices_src)", + "$(_updates_src)", + "$(_security_src)", + "$(_template)", + "$(_cache)" + ); linux.have_fwupdmgr:: # HSI rollup is small (typically <40 attributes) and computed inline. @@ -179,17 +221,20 @@ bundle agent inventory_fwupd_main # cache because filtering objects out of a data container and reshaping # them into a mustache-iterable list is more code than just iterating # and tagging the few results with inventory meta. - "hsi" usebundle => inventory_fwupd_hsi("$(_security_src)"), + "hsi" + usebundle => inventory_fwupd_hsi("$(_security_src)"), if => fileexists("$(_security_src)"); # Per-device pending firmware update inventory, emitted natively # from the updates JSON cache. Mirrors the HSI bundle idiom. - "updates" usebundle => inventory_fwupd_updates("$(_updates_src)"), + "updates" + usebundle => inventory_fwupd_updates("$(_updates_src)"), if => fileexists("$(_updates_src)"); # Per-device firmware inventory, emitted natively from the devices # JSON cache. Mirrors the HSI bundle idiom. - "devices" usebundle => inventory_fwupd_devices("$(_devices_src)"), + "devices" + usebundle => inventory_fwupd_devices("$(_devices_src)"), if => fileexists("$(_devices_src)"); classes: @@ -221,65 +266,70 @@ bundle agent inventory_fwupd_render(devices_src, updates_src, security_src, temp # caller then loads every inventory variable in one shot. { vars: - "_template_body" string => readfile("$(template)", "inf"); - - "_devices_json" data => readjson("$(devices_src)"); - "_dev_count" int => length("_devices_json[Devices]"); - - "_updates_json" - data => readjson("$(updates_src)"), - if => fileexists("$(updates_src)"); - "_updates_count" - int => length("_updates_json[Devices]"), - if => isvariable("_updates_json[Devices]"); - - "_security_json" - data => readjson("$(security_src)"), - if => fileexists("$(security_src)"); - - # Default counters when fwupdmgr-derived data is not present. - "_updates_count" - int => "0", - if => not(isvariable("_updates_count")); - - # Status rollup - "_status" - string => ifelse( - isgreaterthan("$(_updates_count)", "0"), "UPDATES_AVAILABLE", - isgreaterthan("$(_dev_count)", "0"), "OK", - "NO_DEVICES"); - - # HSI inventory is emitted directly by inventory_fwupd_hsi rather than - # threaded through this cache, since reshaping filtered objects into a - # mustache-iterable list is more code than just tagging them in policy. - "_extra_json" string => format( - '{ "status": "%s" }', - "$(_status)"); - "_extra" data => parsejson("$(_extra_json)"); - - # Measurements file: one key=value per line, read by - # inventory_fwupd_monitor for time-series tracking. - "_measurements_path" string => "$(sys.statedir)/fwupd/inventory_measurements"; - "_measurements_body" string => format( + "_template_body" string => readfile("$(template)", "inf"); + "_devices_json" data => readjson("$(devices_src)"); + "_dev_count" int => length("_devices_json[Devices]"); + + "_updates_json" + data => readjson("$(updates_src)"), + if => fileexists("$(updates_src)"); + + "_updates_count" + int => length("_updates_json[Devices]"), + if => isvariable("_updates_json[Devices]"); + + "_security_json" + data => readjson("$(security_src)"), + if => fileexists("$(security_src)"); + + # Default counters when fwupdmgr-derived data is not present. + "_updates_count" + int => "0", + if => not(isvariable("_updates_count")); + + # Status rollup + "_status" + string => ifelse( + isgreaterthan("$(_updates_count)", "0"), + "UPDATES_AVAILABLE", + isgreaterthan("$(_dev_count)", "0"), + "OK", + "NO_DEVICES" + ); + + # HSI inventory is emitted directly by inventory_fwupd_hsi rather than + # threaded through this cache, since reshaping filtered objects into a + # mustache-iterable list is more code than just tagging them in policy. + "_extra_json" string => format('{ "status": "%s" }', "$(_status)"); + "_extra" data => parsejson("$(_extra_json)"); + + # Measurements file: one key=value per line, read by + # inventory_fwupd_monitor for time-series tracking. + "_measurements_path" + string => "$(sys.statedir)/fwupd/inventory_measurements"; + + "_measurements_body" + string => format( "firmware_devices_total=%d$(const.n)firmware_updates_available=%d", - "$(_dev_count)", "$(_updates_count)"); + "$(_dev_count)", + "$(_updates_count)" + ); - # Mergedata combines device data, status counters, and optional - # extra top-level keys into a single data structure for mustache rendering. - # Note: pending-update inventory is emitted natively via - # inventory_fwupd_updates() rather than threaded through this cache, - # because Releases[0].Version cannot be accessed from mustache templates. - "_merged" data => mergedata("_devices_json", "_extra"); + # Mergedata combines device data, status counters, and optional + # extra top-level keys into a single data structure for mustache rendering. + # Note: pending-update inventory is emitted natively via + # inventory_fwupd_updates() rather than threaded through this cache, + # because Releases[0].Version cannot be accessed from mustache templates. + "_merged" data => mergedata("_devices_json", "_extra"); files: - "$(cache)" - create => "true", - template_method => "inline_mustache", - edit_template_string => "$(_template_body)", - template_data => @(_merged); - - "$(_measurements_path)" - content => "$(_measurements_body)"; + "$(cache)" + create => "true", + template_method => "inline_mustache", + edit_template_string => "$(_template_body)", + template_data => @(_merged); + + "$(_measurements_path)" content => "$(_measurements_body)"; } bundle agent inventory_fwupd_hsi(security_src) @@ -303,90 +353,117 @@ bundle agent inventory_fwupd_hsi(security_src) # An attribute is failing when its HsiResult differs from HsiResultSuccess. { classes: - "inventory_fwupd_hsi_failing_$(_idxes)" - not => strcmp("$(_result[$(_idxes)])", "$(_success[$(_idxes)])"); + "inventory_fwupd_hsi_failing_$(_idxes)" + not => strcmp("$(_result[$(_idxes)])", "$(_success[$(_idxes)])"); + + # Per-level failure/success classes for the HSI rollup. + # If ANY attribute at level N fails, _hsi_LN_fail is defined. + # If ANY attribute at level N passes, _hsi_LN_pass is defined. + "_hsi_L$(_level[$(_idxes)])_fail" + expression => "inventory_fwupd_hsi_failing_$(_idxes)"; - # Per-level failure/success classes for the HSI rollup. - # If ANY attribute at level N fails, _hsi_LN_fail is defined. - # If ANY attribute at level N passes, _hsi_LN_pass is defined. - "_hsi_L$(_level[$(_idxes)])_fail" - expression => "inventory_fwupd_hsi_failing_$(_idxes)"; - "_hsi_L$(_level[$(_idxes)])_pass" - not => "inventory_fwupd_hsi_failing_$(_idxes)"; + "_hsi_L$(_level[$(_idxes)])_pass" + not => "inventory_fwupd_hsi_failing_$(_idxes)"; vars: - "_sec" data => readjson("$(security_src)"); - "_idxes" slist => getindices("_sec[SecurityAttributes]"); - - "_name[$(_idxes)]" - string => "$(_sec[SecurityAttributes][$(_idxes)][Name])"; - "_level[$(_idxes)]" - string => "$(_sec[SecurityAttributes][$(_idxes)][HsiLevel])"; - "_result[$(_idxes)]" - string => "$(_sec[SecurityAttributes][$(_idxes)][HsiResult])"; - "_success[$(_idxes)]" - string => "$(_sec[SecurityAttributes][$(_idxes)][HsiResultSuccess])"; - - "_status[$(_idxes)]" - string => ifelse(strcmp("$(_result[$(_idxes)])", "$(_success[$(_idxes)])"), - "PASS", "FAIL"); - - # Normalized name for per-attribute inventory: the CSME version - # attribute has a dynamic Name containing the firmware version - # (e.g. "csme v0:16.1.40.2765") which would create a different - # inventory attribute on every host. Normalize it to a fixed name - # so compliance conditions can reference it statically. - "_inv_name[$(_idxes)]" - string => ifelse(regcmp("csme v.*", "$(_name[$(_idxes)])"), - "CSME version", - "$(_name[$(_idxes)])"); - - # Normalized level for per-attribute inventory: fwupd marks some - # attributes as HsiLevel 0 with a "runtime-issue" flag even though - # they contribute to scored HSI levels. Map them to their HSI spec - # level so inventory attribute names match compliance conditions. - # UEFI secure boot (org.fwupd.hsi.Uefi.SecureBoot) → HSI:1 - # CET OS Support (org.fwupd.hsi.IntelCet.Active) → HSI:3 - "_inv_level[$(_idxes)]" - string => ifelse(strcmp("$(_name[$(_idxes)])", "UEFI secure boot"), - "1", - strcmp("$(_name[$(_idxes)])", "CET OS Support"), - "3", - "$(_level[$(_idxes)])"); - - # Per-attribute inventory: one string variable per HSI check, - # named "Firmware HSI L: " with value PASS or FAIL. - # This enables per-check compliance report conditions. - "fwupd_hsi_check[$(_idxes)]" - string => "$(_status[$(_idxes)])", - meta => { "inventory", - "attribute_name=Firmware HSI L$(_inv_level[$(_idxes)]): $(_inv_name[$(_idxes)])" }; - - "fwupd_hsi_attr[$(_idxes)]" - string => "$(_name[$(_idxes)]) (HSI L$(_level[$(_idxes)])): $(_result[$(_idxes)]) [$(_status[$(_idxes)])]", - meta => { "inventory", "attribute_name=Firmware HSI attributes" }; - - "fwupd_hsi_failing_count" - int => countclassesmatching("inventory_fwupd_hsi_failing_[0-9]+"); - - # Rolled-up HSI level: highest level with a pass where no level - # at or below it has a failure. Checks highest first so the - # first match wins. Mirrors fwupd's fu_security_attrs_calculate_hsi(). - "fwupd_hsi_level" - string => ifelse( - and("_hsi_L4_pass", not("_hsi_L1_fail"), not("_hsi_L2_fail"), not("_hsi_L3_fail"), not("_hsi_L4_fail")), "HSI:4", - and("_hsi_L3_pass", not("_hsi_L1_fail"), not("_hsi_L2_fail"), not("_hsi_L3_fail")), "HSI:3", - and("_hsi_L2_pass", not("_hsi_L1_fail"), not("_hsi_L2_fail")), "HSI:2", - and("_hsi_L1_pass", not("_hsi_L1_fail")), "HSI:1", - "HSI:0"), - meta => { "inventory", "attribute_name=Firmware HSI level" }; + "_sec" data => readjson("$(security_src)"); + "_idxes" slist => getindices("_sec[SecurityAttributes]"); + "_name[$(_idxes)]" string => "$(_sec[SecurityAttributes][$(_idxes)][Name])"; + + "_level[$(_idxes)]" + string => "$(_sec[SecurityAttributes][$(_idxes)][HsiLevel])"; + + "_result[$(_idxes)]" + string => "$(_sec[SecurityAttributes][$(_idxes)][HsiResult])"; + + "_success[$(_idxes)]" + string => "$(_sec[SecurityAttributes][$(_idxes)][HsiResultSuccess])"; + + "_status[$(_idxes)]" + string => ifelse( + strcmp("$(_result[$(_idxes)])", "$(_success[$(_idxes)])"), + "PASS", + "FAIL" + ); + + # Normalized name for per-attribute inventory: the CSME version + # attribute has a dynamic Name containing the firmware version + # (e.g. "csme v0:16.1.40.2765") which would create a different + # inventory attribute on every host. Normalize it to a fixed name + # so compliance conditions can reference it statically. + "_inv_name[$(_idxes)]" + string => ifelse( + regcmp("csme v.*", "$(_name[$(_idxes)])"), + "CSME version", + "$(_name[$(_idxes)])" + ); + + # Normalized level for per-attribute inventory: fwupd marks some + # attributes as HsiLevel 0 with a "runtime-issue" flag even though + # they contribute to scored HSI levels. Map them to their HSI spec + # level so inventory attribute names match compliance conditions. + # UEFI secure boot (org.fwupd.hsi.Uefi.SecureBoot) → HSI:1 + # CET OS Support (org.fwupd.hsi.IntelCet.Active) → HSI:3 + "_inv_level[$(_idxes)]" + string => ifelse( + strcmp("$(_name[$(_idxes)])", "UEFI secure boot"), + "1", + strcmp("$(_name[$(_idxes)])", "CET OS Support"), + "3", + "$(_level[$(_idxes)])" + ); + + # Per-attribute inventory: one string variable per HSI check, + # named "Firmware HSI L: " with value PASS or FAIL. + # This enables per-check compliance report conditions. + "fwupd_hsi_check[$(_idxes)]" + string => "$(_status[$(_idxes)])", + meta => { + "inventory", + "attribute_name=Firmware HSI L$(_inv_level[$(_idxes)]): $(_inv_name[$(_idxes)])", + }; + + "fwupd_hsi_attr[$(_idxes)]" + string => "$(_name[$(_idxes)]) (HSI L$(_level[$(_idxes)])): $(_result[$(_idxes)]) [$(_status[$(_idxes)])]", + meta => { "inventory", "attribute_name=Firmware HSI attributes" }; + + "fwupd_hsi_failing_count" + int => countclassesmatching("inventory_fwupd_hsi_failing_[0-9]+"); + + # Rolled-up HSI level: highest level with a pass where no level + # at or below it has a failure. Checks highest first so the + # first match wins. Mirrors fwupd's fu_security_attrs_calculate_hsi(). + "fwupd_hsi_level" + string => ifelse( + and( + "_hsi_L4_pass", + not("_hsi_L1_fail"), + not("_hsi_L2_fail"), + not("_hsi_L3_fail"), + not("_hsi_L4_fail") + ), + "HSI:4", + and( + "_hsi_L3_pass", + not("_hsi_L1_fail"), + not("_hsi_L2_fail"), + not("_hsi_L3_fail") + ), + "HSI:3", + and("_hsi_L2_pass", not("_hsi_L1_fail"), not("_hsi_L2_fail")), + "HSI:2", + and("_hsi_L1_pass", not("_hsi_L1_fail")), + "HSI:1", + "HSI:0" + ), + meta => { "inventory", "attribute_name=Firmware HSI level" }; files: - # Write HSI failing count to its own measurements file so - # cf-monitord can track it as a time-series metric. - "$(sys.statedir)/fwupd/measurements_hsi" - content => "firmware_hsi_failing_attributes=$(fwupd_hsi_failing_count)", - if => isvariable("fwupd_hsi_failing_count"); + # Write HSI failing count to its own measurements file so + # cf-monitord can track it as a time-series metric. + "$(sys.statedir)/fwupd/measurements_hsi" + content => "firmware_hsi_failing_attributes=$(fwupd_hsi_failing_count)", + if => isvariable("fwupd_hsi_failing_count"); } bundle agent inventory_fwupd_updates(updates_src) @@ -402,17 +479,18 @@ bundle agent inventory_fwupd_updates(updates_src) # into JSON arrays, so we flatten it natively in CFEngine). { vars: - "_upd" data => readjson("$(updates_src)"); - "_idxes" slist => getindices("_upd[Devices]"); - - "_did[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][DeviceId])"; - "_name[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][Name])"; - "_oldv[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][Version])"; - "_newv[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][Releases][0][Version])"; - - "fwupd_dev_pending[$(_did[$(_idxes)])]" - string => "$(_name[$(_idxes)]): $(_oldv[$(_idxes)]) -> $(_newv[$(_idxes)])", - meta => { "inventory", "attribute_name=Firmware device pending update" }; + "_upd" data => readjson("$(updates_src)"); + "_idxes" slist => getindices("_upd[Devices]"); + "_did[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][DeviceId])"; + "_name[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][Name])"; + "_oldv[$(_idxes)]" string => "$(_upd[Devices][$(_idxes)][Version])"; + + "_newv[$(_idxes)]" + string => "$(_upd[Devices][$(_idxes)][Releases][0][Version])"; + + "fwupd_dev_pending[$(_did[$(_idxes)])]" + string => "$(_name[$(_idxes)]): $(_oldv[$(_idxes)]) -> $(_newv[$(_idxes)])", + meta => { "inventory", "attribute_name=Firmware device pending update" }; } bundle agent inventory_fwupd_devices(devices_src) @@ -425,19 +503,18 @@ bundle agent inventory_fwupd_devices(devices_src) # Name silently skip via the if => not(strcmp(...)) guard. { vars: - "_dev" data => readjson("$(devices_src)"); - "_idxes" slist => getindices("_dev[Devices]"); - - "_did[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][DeviceId])"; - "_name[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Name])"; - "_vend[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Vendor])"; - "_ver[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Version])"; - "_plug[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Plugin])"; - - "fwupd_dev[$(_did[$(_idxes)])]" - string => "$(_name[$(_idxes)]) | $(_vend[$(_idxes)]) | v$(_ver[$(_idxes)]) | [$(_plug[$(_idxes)])]", - meta => { "inventory", "attribute_name=Firmware devices" }, - if => not(strcmp("$(_name[$(_idxes)])", "")); + "_dev" data => readjson("$(devices_src)"); + "_idxes" slist => getindices("_dev[Devices]"); + "_did[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][DeviceId])"; + "_name[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Name])"; + "_vend[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Vendor])"; + "_ver[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Version])"; + "_plug[$(_idxes)]" string => "$(_dev[Devices][$(_idxes)][Plugin])"; + + "fwupd_dev[$(_did[$(_idxes)])]" + string => "$(_name[$(_idxes)]) | $(_vend[$(_idxes)]) | v$(_ver[$(_idxes)]) | [$(_plug[$(_idxes)])]", + meta => { "inventory", "attribute_name=Firmware devices" }, + if => not(strcmp("$(_name[$(_idxes)])", "")); } bundle monitor inventory_fwupd_monitor @@ -481,12 +558,12 @@ bundle monitor inventory_fwupd_monitor body match_value inventory_fwupd_kv(key) { - select_line_matching => "$(key)=.*"; - extraction_regex => "$(key)=(\d+)"; + select_line_matching => "$(key)=.*"; + extraction_regex => "$(key)=(\d+)"; } bundle agent __main__ { methods: - "main" usebundle => inventory_fwupd_main; + "main" usebundle => inventory_fwupd_main; } diff --git a/inventory/inventory-smartctl/cfbs.json b/inventory/inventory-smartctl/cfbs.json index 6916e94..2babe4e 100644 --- a/inventory/inventory-smartctl/cfbs.json +++ b/inventory/inventory-smartctl/cfbs.json @@ -3,9 +3,7 @@ "description": "Inventory SMART drive health, temperature, and wear data", "tags": ["inventory", "monitoring", "hardware", "storage", "smartctl"], "version": "0.1.0", - "steps": [ - "copy ./policy.cf services/inventory/smartctl.cf" - ], + "steps": ["copy ./policy.cf services/inventory/smartctl.cf"], "dependencies": [], "subdirectory": "inventory/inventory-smartctl" } diff --git a/inventory/inventory-smartctl/policy.cf b/inventory/inventory-smartctl/policy.cf index bafd762..7aae330 100644 --- a/inventory/inventory-smartctl/policy.cf +++ b/inventory/inventory-smartctl/policy.cf @@ -1,6 +1,6 @@ body file control { - namespace => "inventory_smartctl"; + namespace => "inventory_smartctl"; } bundle agent main @@ -22,25 +22,35 @@ bundle agent main { vars: linux:: - "_smartctl" string => ifelse( - fileexists("/usr/sbin/smartctl"), "/usr/sbin/smartctl", - fileexists("/sbin/smartctl"), "/sbin/smartctl", - "/usr/sbin/smartctl" # default fallback - ); - "_sdir" string => "$(sys.statedir)"; - "_cache_ttl" string => "3600"; # 1 hour - + "_smartctl" + string => ifelse( + fileexists("/usr/sbin/smartctl"), + "/usr/sbin/smartctl", + fileexists("/sbin/smartctl"), + "/sbin/smartctl", + "/usr/sbin/smartctl" + # default fallback + ); + + "_sdir" string => "$(sys.statedir)"; + "_cache_ttl" string => "3600"; + + # 1 hour # Enumerate drives - extract first field from each line of smartctl --scan "_scan_lines" slist => splitstring( - execresult("$(_smartctl) --scan 2>/dev/null", "useshell"), - "\n", 32); + execresult("$(_smartctl) --scan 2>/dev/null", "useshell"), "\n", 32 + ); "_drives" - slist => maplist(regex_replace("$(this)", "^(\S+).*", "\1", ""), "_scan_lines"); + slist => maplist( + regex_replace("$(this)", "^(\S+).*", "\1", ""), "_scan_lines" + ); "_id[${_drives}]" string => canonify("${_drives}"); - "_cache[${_drives}]" string => "$(_sdir)/inventory_smartctl_${_id[${_drives}]}.json"; + + "_cache[${_drives}]" + string => "$(_sdir)/inventory_smartctl_${_id[${_drives}]}.json"; linux._have_smartctl:: # Rolled-up status: OK or DEGRADED (SMARTCTL_MISSING when smartctl absent) @@ -115,20 +125,23 @@ bundle agent main "_cache_stale_${_id[${_drives}]}" expression => isgreaterthan( eval("$(sys.systime) - $(filestat(${_cache[${_drives}]}, mtime))"), - "$(_cache_ttl)"), + "$(_cache_ttl)" + ), if => fileexists("${_cache[${_drives}]}"); # Refresh if missing or stale "_refresh_${_id[${_drives}]}" or => { "_cache_missing_${_id[${_drives}]}", - "_cache_stale_${_id[${_drives}]}" + "_cache_stale_${_id[${_drives}]}", }; files: linux._have_smartctl:: "${_cache[${_drives}]}" - content => execresult("$(_smartctl) -j -a ${_drives}", "noshell", "stdout"), + content => execresult( + "$(_smartctl) -j -a ${_drives}", "noshell", "stdout" + ), if => "_refresh_${_id[${_drives}]}"; methods: @@ -142,6 +155,7 @@ bundle agent main reports: linux._have_smartctl.verbose_mode:: "inventory_smartctl: monitoring ${_drives}"; + "inventory_smartctl: ${_drives} health=${_d_${_id[${_drives}]}[health]}" if => isvariable("_d_${_id[${_drives}]}[health]"); @@ -153,58 +167,82 @@ bundle agent parse(drive, cache_file) # @brief Parse smartctl JSON and return key metrics via bundle_return_value_index { vars: - "_json" data => readjson("$(cache_file)"); + "_json" data => readjson("$(cache_file)"); + + # Extract metrics directly from JSON + "_health" + string => ifelse( + strcmp("${_json[smart_status][passed]}", "true"), "PASSED", "FAILED" + ), + if => isvariable("_json[smart_status][passed]"); + + "_model" + string => "${_json[model_name]}", + if => isvariable("_json[model_name]"); + + "_temp" + string => "${_json[temperature][current]}", + if => isvariable("_json[temperature][current]"); + + "_hours" + string => "${_json[power_on_time][hours]}", + if => isvariable("_json[power_on_time][hours]"); + + "_nvme_spare" + string => "${_json[nvme_smart_health_information_log][available_spare]}", + if => isvariable( + "_json[nvme_smart_health_information_log][available_spare]" + ); - # Extract metrics directly from JSON - "_health" - string => ifelse(strcmp("${_json[smart_status][passed]}", "true"), "PASSED", "FAILED"), - if => isvariable("_json[smart_status][passed]"); + "_nvme_pct_used" + string => "${_json[nvme_smart_health_information_log][percentage_used]}", + if => isvariable( + "_json[nvme_smart_health_information_log][percentage_used]" + ); - "_model" - string => "${_json[model_name]}", - if => isvariable("_json[model_name]"); + "_nvme_media_errors" + string => "${_json[nvme_smart_health_information_log][media_errors]}", + if => isvariable( + "_json[nvme_smart_health_information_log][media_errors]" + ); - "_temp" - string => "${_json[temperature][current]}", - if => isvariable("_json[temperature][current]"); + reports: + "$(_health)" + bundle_return_value_index => "health", + if => isvariable("_health"); - "_hours" - string => "${_json[power_on_time][hours]}", - if => isvariable("_json[power_on_time][hours]"); + "$(_model)" + bundle_return_value_index => "model", + if => isvariable("_model"); - "_nvme_spare" - string => "${_json[nvme_smart_health_information_log][available_spare]}", - if => isvariable("_json[nvme_smart_health_information_log][available_spare]"); + "$(_temp)" + bundle_return_value_index => "temp", + if => isvariable("_temp"); - "_nvme_pct_used" - string => "${_json[nvme_smart_health_information_log][percentage_used]}", - if => isvariable("_json[nvme_smart_health_information_log][percentage_used]"); + "$(_hours)" + bundle_return_value_index => "hours", + if => isvariable("_hours"); - "_nvme_media_errors" - string => "${_json[nvme_smart_health_information_log][media_errors]}", - if => isvariable("_json[nvme_smart_health_information_log][media_errors]"); + "$(_nvme_spare)" + bundle_return_value_index => "nvme_spare", + if => isvariable("_nvme_spare"); - reports: - "$(_health)" bundle_return_value_index => "health", - if => isvariable("_health"); - "$(_model)" bundle_return_value_index => "model", - if => isvariable("_model"); - "$(_temp)" bundle_return_value_index => "temp", - if => isvariable("_temp"); - "$(_hours)" bundle_return_value_index => "hours", - if => isvariable("_hours"); - "$(_nvme_spare)" bundle_return_value_index => "nvme_spare", - if => isvariable("_nvme_spare"); - "$(_nvme_pct_used)" bundle_return_value_index => "nvme_pct_used", - if => isvariable("_nvme_pct_used"); - "$(_nvme_media_errors)" bundle_return_value_index => "nvme_media_errors", - if => isvariable("_nvme_media_errors"); + "$(_nvme_pct_used)" + bundle_return_value_index => "nvme_pct_used", + if => isvariable("_nvme_pct_used"); + + "$(_nvme_media_errors)" + bundle_return_value_index => "nvme_media_errors", + if => isvariable("_nvme_media_errors"); } -body file control { namespace => "default"; } +body file control +{ + namespace => "default"; +} bundle agent __main__ { methods: - "inventory_smartctl:main"; + "inventory_smartctl:main"; } diff --git a/inventory/inventory-windows-services/inventory-windows-services.cf b/inventory/inventory-windows-services/inventory-windows-services.cf index ca7b25f..d37ff9e 100644 --- a/inventory/inventory-windows-services/inventory-windows-services.cf +++ b/inventory/inventory-windows-services/inventory-windows-services.cf @@ -5,24 +5,21 @@ bundle agent inventory_windows_services_running vars: windows:: "_cache" string => "$(sys.statedir)/windows-services-running.json"; - "_data" data => readjson("$(_cache)"); "_indices" slist => getindices(_data); "i[$(_indices)]" string => "$(_data[$(_indices)][DisplayName])", - meta => { "inventory", "attribute_name=Windows services running"}; - + meta => { "inventory", "attribute_name=Windows services running" }; commands: windows:: "Get-Service | Where-Object {$_.Status -eq 'Running'} | ConvertTo-Json | Set-Content -Path '${_cache}'" contain => powershell; - } bundle agent __main__ { methods: - "inventory_windows_services_running"; + "inventory_windows_services_running"; } diff --git a/management/autorun-bundles/def.json b/management/autorun-bundles/def.json index 045031b..385c3e7 100644 --- a/management/autorun-bundles/def.json +++ b/management/autorun-bundles/def.json @@ -1,5 +1,3 @@ { - "classes": { - "services_autorun_bundles": ["any"] - } + "classes": { "services_autorun_bundles": ["any"] } } diff --git a/management/autorun-inputs/def.json b/management/autorun-inputs/def.json index 90faea3..c44ff2a 100644 --- a/management/autorun-inputs/def.json +++ b/management/autorun-inputs/def.json @@ -1,5 +1,3 @@ { - "classes": { - "services_autorun_inputs": ["any"] - } + "classes": { "services_autorun_inputs": ["any"] } } diff --git a/management/autorun/def.json b/management/autorun/def.json index d2090d2..193a0b3 100644 --- a/management/autorun/def.json +++ b/management/autorun/def.json @@ -1,5 +1,3 @@ { - "classes": { - "services_autorun": ["any"] - } + "classes": { "services_autorun": ["any"] } } diff --git a/management/command-dispatcher/main.cf b/management/command-dispatcher/main.cf index 3f96805..2a30996 100644 --- a/management/command-dispatcher/main.cf +++ b/management/command-dispatcher/main.cf @@ -2,18 +2,16 @@ body file control { namespace => "command_dispatcher"; } + bundle agent main { classes: - "enabled" - expression => isvariable("commands_to_run"); - "run_$(i)" - expression => "$(_condition[$(i)])"; + "enabled" expression => isvariable("commands_to_run"); + "run_$(i)" expression => "$(_condition[$(i)])"; vars: enabled:: - "i" - slist => getindices(commands_to_run); + "i" slist => getindices(commands_to_run); "_command[$(i)]" string => "$(commands_to_run[$(i)][command])", @@ -23,17 +21,20 @@ bundle agent main string => ifelse( not(strcmp("$(commands_to_run[$(i)][condition])", "")), "$(commands_to_run[$(i)][condition])", - "any"); + "any" + ); "_ifelapsed[$(i)]" string => ifelse( not(strcmp("$(commands_to_run[$(i)][ifelapsed])", "")), "$(commands_to_run[$(i)][ifelapsed])", - "5"); + "5" + ); reports: enabled:: "Command [$(i)]: $(_command[$(i)]), condition: $(_condition[$(i)]), ifelapsed: $(_ifelapsed[$(i)])"; + !enabled:: "Command-dispatcher: commands_to_run variable not found"; @@ -44,20 +45,24 @@ bundle agent main action => ifelapsed("$(_ifelapsed[$(i)])"), contain => in_shell; } + body contain in_shell { useshell => "true"; exec_owner => "root"; exec_timeout => "300"; } + body action ifelapsed(x) { ifelapsed => "$(x)"; } + body file control { namespace => "default"; } + bundle agent __main__ { methods: diff --git a/management/demo/def.json b/management/demo/def.json index ea609c9..ed6de96 100644 --- a/management/demo/def.json +++ b/management/demo/def.json @@ -1,14 +1,14 @@ { - "classes": { - "mpf_augments_control_enabled": ["any"], - "cfengine_mp_fr_dependencies_auto_install": ["any"] - }, - "vars": { - "acl": ["0.0.0.0/0", "::/0"], - "default_data_select_host_monitoring_include": [".*"], - "default_data_select_policy_hub_monitoring_include": [".*"], - "control_executor_splaytime": "1", - "control_executor_schedule": ["any"], - "control_hub_hub_schedule": ["any"] - } + "classes": { + "mpf_augments_control_enabled": ["any"], + "cfengine_mp_fr_dependencies_auto_install": ["any"] + }, + "vars": { + "acl": ["0.0.0.0/0", "::/0"], + "default_data_select_host_monitoring_include": [".*"], + "default_data_select_policy_hub_monitoring_include": [".*"], + "control_executor_splaytime": "1", + "control_executor_schedule": ["any"], + "control_hub_hub_schedule": ["any"] + } } diff --git a/management/disable-automatic-key-trust/def.json b/management/disable-automatic-key-trust/def.json index 6dde153..3a57315 100644 --- a/management/disable-automatic-key-trust/def.json +++ b/management/disable-automatic-key-trust/def.json @@ -1 +1,3 @@ -{ "variables": {"default:def.trustkeysfrom": []} } +{ + "variables": { "default:def.trustkeysfrom": [] } +} diff --git a/management/disable-recommendations/def.json b/management/disable-recommendations/def.json index 715b0b4..48f8364 100644 --- a/management/disable-recommendations/def.json +++ b/management/disable-recommendations/def.json @@ -1,8 +1,8 @@ { - "classes": { - "default:cfengine_recommendations_disabled": { - "class_expressions": [ "any::" ], - "comment": "We disabled all recommendations emitted by the MPF to quiet policy output." - } + "classes": { + "default:cfengine_recommendations_disabled": { + "class_expressions": ["any::"], + "comment": "We disabled all recommendations emitted by the MPF to quiet policy output." } + } } diff --git a/management/every-minute/def.json b/management/every-minute/def.json index 0b32978..9f4fbbb 100644 --- a/management/every-minute/def.json +++ b/management/every-minute/def.json @@ -1,7 +1,7 @@ { - "vars": { - "control_executor_splaytime": "1", - "control_executor_schedule": ["any"], - "control_hub_hub_schedule": ["any"] - } + "vars": { + "control_executor_splaytime": "1", + "control_executor_schedule": ["any"], + "control_hub_hub_schedule": ["any"] + } } diff --git a/management/manage-fwupd/main.cf b/management/manage-fwupd/main.cf index c9d5e7a..6c651c3 100644 --- a/management/manage-fwupd/main.cf +++ b/management/manage-fwupd/main.cf @@ -12,20 +12,20 @@ bundle agent allowed # via CMDB or augments to control firmware update behavior. { vars: - "apply_updates" - string => "!any", - if => not(isvariable("apply_updates")), - comment => "Default disabled; set to a class expression to enable firmware updates"; - - "device_name_reglist" - slist => {}, - if => not(isvariable("device_name_reglist")), - comment => "Default empty allow-list; override via CMDB or augments"; - - "reboot_after_update" - string => "!any", - if => not(isvariable("reboot_after_update")), - comment => "Default disabled; set to a class expression to reboot after firmware update"; + "apply_updates" + string => "!any", + if => not(isvariable("apply_updates")), + comment => "Default disabled; set to a class expression to enable firmware updates"; + + "device_name_reglist" + slist => {}, + if => not(isvariable("device_name_reglist")), + comment => "Default empty allow-list; override via CMDB or augments"; + + "reboot_after_update" + string => "!any", + if => not(isvariable("reboot_after_update")), + comment => "Default disabled; set to a class expression to reboot after firmware update"; } bundle agent main @@ -60,18 +60,20 @@ bundle agent main { vars: linux:: - "_update_marker" - string => "$(sys.statedir)/fwupd/update_applied"; + "_update_marker" string => "$(sys.statedir)/fwupd/update_applied"; "_systemd_run" - string => ifelse(isexecutable("/bin/systemd-run"), "/bin/systemd-run", - isexecutable("/usr/bin/systemd-run"), "/usr/bin/systemd-run", - ""), + string => ifelse( + isexecutable("/bin/systemd-run"), + "/bin/systemd-run", + isexecutable("/usr/bin/systemd-run"), + "/usr/bin/systemd-run", + "" + ), comment => "Path to systemd-run when available (empty string otherwise)"; linux.default:have_fwupdmgr.manage_fwupd:apply_updates:: - "_updates_cache" - string => "$(sys.statedir)/fwupd/inventory_updates.json"; + "_updates_cache" string => "$(sys.statedir)/fwupd/inventory_updates.json"; "_updates" data => readjson("$(_updates_cache)"), @@ -114,7 +116,10 @@ bundle agent main linux.default:have_fwupdmgr.manage_fwupd:apply_updates:: "_device_allowed_$(_dev_idx)" - expression => regcmp("$(manage_fwupd:allowed.device_name_reglist)", "$(_dev_name[$(_dev_idx)])"), + expression => regcmp( + "$(manage_fwupd:allowed.device_name_reglist)", + "$(_dev_name[$(_dev_idx)])" + ), comment => "Device $(_dev_name[$(_dev_idx)]) matches allow-list entry"; packages: @@ -128,7 +133,6 @@ bundle agent main "fwupd-refresh.timer" service_policy => "enabled", comment => "Ensure the fwupd metadata refresh timer is enabled so the LVFS firmware catalog stays current"; - # --- Stale marker cleanup ---------------------------------------- files: linux:: @@ -136,17 +140,21 @@ bundle agent main delete => default:tidy, if => not("_update_applied"), comment => "Remove stale marker from a previous boot cycle"; - # --- Apply firmware updates -------------------------------------- commands: linux.default:have_fwupdmgr.manage_fwupd:apply_updates:: "$(default:inventory_fwupd_main.fwupdmgr)" - arglist => { "update", "--no-reboot-check", "$(_dev_id[$(_dev_idx)])" }, - handle => canonify("manage_fwupd_apply_device_$(_dev_idx)_$(_dev_name[$(_dev_idx)])"), + arglist => { + "update", "--no-reboot-check", "$(_dev_id[$(_dev_idx)])" + }, + handle => canonify( + "manage_fwupd_apply_device_$(_dev_idx)_$(_dev_name[$(_dev_idx)])" + ), if => and("_device_allowed_$(_dev_idx)", not("_update_applied")), - classes => default:results("bundle", "manage_fwupd_update_$(_dev_idx)"), + classes => default:results( + "bundle", "manage_fwupd_update_$(_dev_idx)" + ), comment => "Apply firmware update to allowed device $(_dev_name[$(_dev_idx)])"; - # --- Post-update marker and reboot -------------------------------- files: linux.default:have_fwupdmgr.manage_fwupd:apply_updates:: @@ -166,18 +174,20 @@ bundle agent main arglist => { "--unit=cfengine-fwupd-reboot", "--description=Reboot after cf-agent exits for firmware update", - "/bin/bash", "-c", - "while kill -0 $(this.promiser_pid) 2>/dev/null; do sleep 1; done; /sbin/shutdown -r now 'Rebooting for firmware update applied by CFEngine'" + "/bin/bash", + "-c", + "while kill -0 $(this.promiser_pid) 2>/dev/null; do sleep 1; done; /sbin/shutdown -r now 'Rebooting for firmware update applied by CFEngine'", }, handle => "manage_fwupd_reboot_after_update", comment => "Deferred reboot: polls for cf-agent to exit, then reboots immediately"; manage_fwupd:_update_applied.manage_fwupd:reboot_after_update.!manage_fwupd:_have_systemd_run:: "/sbin/shutdown" - arglist => { "-r", "+1", "Rebooting for firmware update applied by CFEngine" }, + arglist => { + "-r", "+1", "Rebooting for firmware update applied by CFEngine" + }, handle => "manage_fwupd_reboot_after_update_fallback", comment => "Fallback reboot for non-systemd systems (shutdown -r +1)"; - # --- Inventory -------------------------------------------------- vars: linux.default:have_fwupdmgr:: diff --git a/management/package-method-ansible-galaxy-collection/package-method-ansible-galaxy-collections.cf b/management/package-method-ansible-galaxy-collection/package-method-ansible-galaxy-collections.cf index 1720036..0cb0ab2 100644 --- a/management/package-method-ansible-galaxy-collection/package-method-ansible-galaxy-collections.cf +++ b/management/package-method-ansible-galaxy-collection/package-method-ansible-galaxy-collections.cf @@ -1,15 +1,12 @@ body package_method ansible_galaxy_collection { - package_changes => "bulk"; - package_name_convention => "$(name)"; - package_delete_convention => "$(name)"; - - package_installed_regex => ".*"; - package_list_name_regex => '^"([^"]*)",.*'; - package_list_version_regex => '.*,"([^"]*)".*'; - - - package_list_command => "ansible-galaxy collection list"; - package_delete_command => 'echo "Deleting an Ansible Galaxy Collection is not supported"'; - package_add_command => "ansible-galaxy collection install "; + package_changes => "bulk"; + package_name_convention => "$(name)"; + package_delete_convention => "$(name)"; + package_installed_regex => ".*"; + package_list_name_regex => '^"([^"]*)",.*'; + package_list_version_regex => '.*,"([^"]*)".*'; + package_list_command => "ansible-galaxy collection list"; + package_delete_command => 'echo "Deleting an Ansible Galaxy Collection is not supported"'; + package_add_command => "ansible-galaxy collection install "; } diff --git a/management/package-method-winget/package-method-winget.cf b/management/package-method-winget/package-method-winget.cf index 8c3db90..1da97b8 100644 --- a/management/package-method-winget/package-method-winget.cf +++ b/management/package-method-winget/package-method-winget.cf @@ -2,54 +2,57 @@ # TODO: fix case sensitive package names? ^^^ body package_method winget { - package_changes => "bulk"; - package_name_convention => "$(name)"; - package_delete_convention => "$(name)"; - - package_installed_regex => ".*"; - # Note that package_list_name_regex does not allow for commas inside of package names as parsing that from ConvertTo-Csv below would be too complex - # an example of output of the package_list_command below is - # - # "Microsoft.WindowsTerminal","1.21.2361.0" - # - # so the matches below simply grab the thing before or after the comma separating Id and InstalledVersion fields. - package_list_name_regex => '^"([^"]*)",.*'; - package_list_version_regex => '.*,"([^"]*)".*'; - - - # Here we use the Get-WinGetPackage Cmdlet because it is easier to produce easily parsed information that way - package_list_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Get-WinGetPackage | Select Id,InstalledVersion | ConvertTo-Csv "; - package_delete_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Uninstall-WinGetPackage "; - - # Here we use winget instead of PowerShell Cmdlets because we can provide the --accept-source-agreements and --accept-package-agreements this way which gets around dialog prompts - package_method_winget:accept_source_agreements.package_method_winget:accept_package_agreements:: - package_add_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"winget install --accept-source-agreements --accept-package-agreements "; - !package_method_winget:accept_source_agreements|!package_method_winget:accept_package_agreements:: - # the package name is appended to the end of this command, so we try here to make a command which conveys information only - package_add_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Write-Host You must set some vars for package-method-winget to work;exit 1; rem Trying to add package:"; + package_changes => "bulk"; + package_name_convention => "$(name)"; + package_delete_convention => "$(name)"; + package_installed_regex => ".*"; + # Note that package_list_name_regex does not allow for commas inside of package names as parsing that from ConvertTo-Csv below would be too complex + # an example of output of the package_list_command below is + # + # "Microsoft.WindowsTerminal","1.21.2361.0" + # + # so the matches below simply grab the thing before or after the comma separating Id and InstalledVersion fields. + package_list_name_regex => '^"([^"]*)",.*'; + package_list_version_regex => '.*,"([^"]*)".*'; + # Here we use the Get-WinGetPackage Cmdlet because it is easier to produce easily parsed information that way + package_list_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Get-WinGetPackage | Select Id,InstalledVersion | ConvertTo-Csv "; + package_delete_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Uninstall-WinGetPackage "; + # Here we use winget instead of PowerShell Cmdlets because we can provide the --accept-source-agreements and --accept-package-agreements this way which gets around dialog prompts + package_method_winget:accept_source_agreements.package_method_winget:accept_package_agreements:: + package_add_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"winget install --accept-source-agreements --accept-package-agreements "; + !package_method_winget:accept_source_agreements|!package_method_winget:accept_package_agreements:: + # the package name is appended to the end of this command, so we try here to make a command which conveys information only + package_add_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Write-Host You must set some vars for package-method-winget to work;exit 1; rem Trying to add package:"; } - # switch to module specific namespace to avoid name collisions body file control { namespace => "package_method_winget"; } - # package_method_winget bundle's purpose is to look at inputs/data for acceptance of source and package agreements # these MUST be agreed to in order for this package method to work properly. bundle agent package_method_winget { classes: - "accept_source_agreements" expression => regcmp("^[yY][eE]?[sS]?", "${data:package_method_winget.accept_source_agreements}"), + "accept_source_agreements" + expression => regcmp( + "^[yY][eE]?[sS]?", + "${data:package_method_winget.accept_source_agreements}" + ), scope => "namespace"; - "accept_package_agreements" expression => regcmp("^[yY][eE]?[sS]?", "${data:package_method_winget.accept_package_agreements}"), + + "accept_package_agreements" + expression => regcmp( + "^[yY][eE]?[sS]?", + "${data:package_method_winget.accept_package_agreements}" + ), scope => "namespace"; reports: windows:: "Please specify if you wish to --accept-source-agreements when using winget package method promises with the cfbs inputs or the variable data:package_method_winget.accept_source_agreements having the value yes or no" if => "!accept_source_agreements"; + "Please specify if you wish to --accept-package-agreements when using winget package method promises with cfbs inputs or the variable data:package_method_winget.accept_package_agreements having the value yes or no" if => "!accept_package_agreements"; } - diff --git a/management/package-method-winget/winget-installed.cf b/management/package-method-winget/winget-installed.cf index a14363e..2d558ad 100644 --- a/management/package-method-winget/winget-installed.cf +++ b/management/package-method-winget/winget-installed.cf @@ -7,29 +7,45 @@ bundle agent winget_installed { classes: windows:: - "winget_not_installed" expression => not(returnszero("winget -v | out-null", "powershell")); - "winget_cli_not_installed" expression => not(returnszero("Get-WinGetPackage | out-null", "powershell")); - "allow_powershell_execution_policy_change" expression => regcmp("^[yY][eE]?[sS]?", "${data:winget_installed.allow_powershell_execution_policy_change}"), + "winget_not_installed" + expression => not(returnszero("winget -v | out-null", "powershell")); + + "winget_cli_not_installed" + expression => not( + returnszero("Get-WinGetPackage | out-null", "powershell") + ); + + "allow_powershell_execution_policy_change" + expression => regcmp( + "^[yY][eE]?[sS]?", + "${data:winget_installed.allow_powershell_execution_policy_change}" + ), scope => "namespace"; commands: windows.!winget_installed.execution_policy_ok:: "powershell.exe -File '${this.promise_dirname}/install-winget.ps1'" contain => default:powershell; + windows.!winget_cli_installed.execution_policy_ok:: "powershell.exe -File '${this.promise_dirname}/install-winget-cli.ps1'" contain => default:powershell; methods: windows.(winget_not_installed|winget_cli_not_installed).allow_powershell_execution_policy_change:: - "powershell_execution_policy_set" usebundle => default:powershell_execution_policy_set("LocalMachine", "Unrestricted"), + "powershell_execution_policy_set" + usebundle => default:powershell_execution_policy_set( + "LocalMachine", "Unrestricted" + ), classes => default:if_ok("execution_policy_ok"); reports: windows.winget_not_installed:: "In order for package-module-winget to function properly, winget must be installed."; + windows.winget_cli_not_installed:: "In order for package-module-winget to function properly, winget-cli must be installed and imported."; + windows.(winget_not_installed|winget_cli_not_installed).!allow_powershell_execution_policy_change:: "package-module-winget needs winget and/or winget-cli installed. Opt-in for this to be automated by this policy by setting the variable data:winget_installed.allow_powershell_execution_policy_change to 'yes'. This can be accomplished via cfbs inputs, group/host data or augments."; } diff --git a/management/powershell-execution-policy/powershell-execution-policy.cf b/management/powershell-execution-policy/powershell-execution-policy.cf index 4f65904..5544ec9 100644 --- a/management/powershell-execution-policy/powershell-execution-policy.cf +++ b/management/powershell-execution-policy/powershell-execution-policy.cf @@ -4,29 +4,37 @@ bundle agent powershell_execution_policy_inventory { vars: windows:: - "execution_policy_csv_file" string => "${sys.statedir}${const.dirsep}powershell_execution_policy_list_cache.csv"; - "execution_policy_list_cache_command" string => "Get-ExecutionPolicy -list | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${execution_policy_csv_file}'"; + "execution_policy_csv_file" + string => "${sys.statedir}${const.dirsep}powershell_execution_policy_list_cache.csv"; + + "execution_policy_list_cache_command" + string => "Get-ExecutionPolicy -list | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${execution_policy_csv_file}'"; + "csv" data => readcsv("${execution_policy_csv_file}"); "i" slist => getindices("csv"); - "execution_policy_${csv[${i}][0]}" string => "${csv[${i}][0]}:${csv[${i}][1]}", + + "execution_policy_${csv[${i}][0]}" + string => "${csv[${i}][0]}:${csv[${i}][1]}", meta => { "inventory", "attribute_name=PowerShell Execution Policy" }; commands: windows:: - "${execution_policy_list_cache_command}" - contain => powershell; + "${execution_policy_list_cache_command}" contain => powershell; } - # see link below for valid values for scope and policy # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.4 # This bundle runs a powershell command: Set-ExecutionPolicy -ExecutionPolicy -Scope bundle agent powershell_execution_policy_set(scope, desired_policy) { classes: - "policy_not_ok" expression => returnszero("if((Get-ExecutionPolicy ${scope}) -ne '${desired_policy}'){exit 0}else{exit 1}", "powershell"); + "policy_not_ok" + expression => returnszero( + "if((Get-ExecutionPolicy ${scope}) -ne '${desired_policy}'){exit 0}else{exit 1}", + "powershell" + ); commands: windows.policy_not_ok:: "Set-ExecutionPolicy -ExecutionPolicy ${desired_policy} -Scope ${scope}" - contain => powershell; + contain => powershell; } diff --git a/management/windows-capability/windows-capability.cf b/management/windows-capability/windows-capability.cf index 739bb23..c1d8ad2 100644 --- a/management/windows-capability/windows-capability.cf +++ b/management/windows-capability/windows-capability.cf @@ -1,12 +1,19 @@ bundle agent windows_capability_installed(capability_name) { methods: - "Installed" usebundle => windows_capability:_windows_capability_state("${capability_name}", "Installed"); + "Installed" + usebundle => windows_capability:_windows_capability_state( + "${capability_name}", "Installed" + ); } + bundle agent windows_optionial_capability_notpresent(capability_name) { methods: - "NotPresent" usebundle => windows_capability:_windows_capability_state("${capability_name}", "NotPresent"); + "NotPresent" + usebundle => windows_capability:_windows_capability_state( + "${capability_name}", "NotPresent" + ); } bundle agent windows_capability @@ -20,7 +27,6 @@ body file control { namespace => "windows_capability"; } - # https://learn.microsoft.com/en-us/powershell/module/dism/get-windowscapability?view=windowsserver2022-ps # https://learn.microsoft.com/en-us/powershell/module/dism/remove-windowscapability?view=windowsserver2022-ps # https://learn.microsoft.com/en-us/powershell/module/dism/add-windowscapability?view=windowsserver2022-ps @@ -28,12 +34,17 @@ bundle agent _inventory { vars: windows:: - "cache_file" string => "${sys.statedir}${const.dirsep}${this.namespace}_cache.csv"; - "command" string => "Get-WindowsCapability -Online | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${cache_file}'"; + "cache_file" + string => "${sys.statedir}${const.dirsep}${this.namespace}_cache.csv"; + + "command" + string => "Get-WindowsCapability -Online | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${cache_file}'"; "csv" data => readcsv("${cache_file}"); "i" slist => getindices("csv"); - "${this.namespace}[${i}]" string => "${csv[${i}][0]}:${csv[${i}][1]}", + + "${this.namespace}[${i}]" + string => "${csv[${i}][0]}:${csv[${i}][1]}", meta => { "inventory", "attribute_name=Windows Capability" }; files: @@ -42,20 +53,27 @@ bundle agent _inventory delete => default:tidy; commands: - windows:: - "${command}" - if => not(fileexists("${cache_file}")), - contain => default:powershell; + windows:: + "${command}" + if => not(fileexists("${cache_file}")), + contain => default:powershell; } - bundle agent _windows_capability_state(capability_name, desired_state) { vars: - "operation" string => ifelse(strcmp("${desired_state}", "Installed"), "Add", "Remove"); + "operation" + string => ifelse( + strcmp("${desired_state}", "Installed"), "Add", "Remove" + ); + classes: windows:: - "state_not_ok" expression => returnszero("if((Get-WindowsCapability -Online -Name ${capability_name} | select-object -expandproperty state) -ne '${desired_state}'){exit 0}else{exit 1}", "powershell"); + "state_not_ok" + expression => returnszero( + "if((Get-WindowsCapability -Online -Name ${capability_name} | select-object -expandproperty state) -ne '${desired_state}'){exit 0}else{exit 1}", + "powershell" + ); commands: windows.state_not_ok:: @@ -65,6 +83,5 @@ bundle agent _windows_capability_state(capability_name, desired_state) files: windows.state_repaired:: - "${_inventory.cache_file}" - delete => default:tidy; + "${_inventory.cache_file}" delete => default:tidy; } diff --git a/management/windows-optional-feature/windows-optional-feature.cf b/management/windows-optional-feature/windows-optional-feature.cf index 27aec9b..0908788 100644 --- a/management/windows-optional-feature/windows-optional-feature.cf +++ b/management/windows-optional-feature/windows-optional-feature.cf @@ -2,17 +2,22 @@ # https://learn.microsoft.com/en-us/powershell/module/dism/disable-windowsoptionalfeature?view=windowsserver2022-ps # https://learn.microsoft.com/en-us/powershell/module/dism/enable-windowsoptionalfeature?view=windowsserver2022-ps # https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v#enable-hyper-v-using-powershell - -bundle agent windows_optional_feature_enabled( feature_name ) +bundle agent windows_optional_feature_enabled(feature_name) { methods: - "Enabled" usebundle => windows_optional_feature:_promise_state("${feature_name}", "Enabled"); + "Enabled" + usebundle => windows_optional_feature:_promise_state( + "${feature_name}", "Enabled" + ); } -bundle agent windows_optional_feature_disabled( feature_name ) +bundle agent windows_optional_feature_disabled(feature_name) { methods: - "Disabled" usebundle => windows_optional_feature:_promise_state("${feature_name}", "Disabled"); + "Disabled" + usebundle => windows_optional_feature:_promise_state( + "${feature_name}", "Disabled" + ); } bundle agent windows_optional_feature @@ -31,11 +36,17 @@ bundle agent _inventory { vars: windows:: - "cache_file" string => "${sys.statedir}${const.dirsep}${this.namespace}_cache.csv"; - "command" string => "Get-WindowsOptionalFeature -Online | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${cache_file}'"; + "cache_file" + string => "${sys.statedir}${const.dirsep}${this.namespace}_cache.csv"; + + "command" + string => "Get-WindowsOptionalFeature -Online | ConvertTo-Csv -notypeinformation | select-object -skip 1 | Set-Content -Path '${cache_file}'"; + "csv" data => readcsv("${cache_file}"); "i" slist => getindices("csv"); - "${this.namespace}[${i}]" string => "${csv[${i}][0]}:${csv[${i}][1]}", + + "${this.namespace}[${i}]" + string => "${csv[${i}][0]}:${csv[${i}][1]}", meta => { "inventory", "attribute_name=Windows Optional Features" }; files: @@ -45,29 +56,37 @@ bundle agent _inventory commands: windows:: - "${command}" - if => not(fileexists("${cache_file}")), - contain => default:powershell; + "${command}" + if => not(fileexists("${cache_file}")), + contain => default:powershell; } bundle agent _promise_state(feature_name, desired_state) { vars: - "operation" string => ifelse(strcmp("${desired_state}", "Enabled"), "Enable", "Disable"); + "operation" + string => ifelse( + strcmp("${desired_state}", "Enabled"), "Enable", "Disable" + ); + classes: windows:: - "state_not_ok" expression => returnszero( "if((Get-WindowsOptionalFeature -Online -FeatureName ${feature_name} | select-object -expandproperty state) -ne '${state_name}'){exit 0}else{exit 1}", "powershell"); + "state_not_ok" + expression => returnszero( + "if((Get-WindowsOptionalFeature -Online -FeatureName ${feature_name} | select-object -expandproperty state) -ne '${state_name}'){exit 0}else{exit 1}", + "powershell" + ); + commands: windows.state_not_ok:: -# -All enables parent features if need be + # -All enables parent features if need be + # -NoRestart so that we don't wait forever for a Yes reply from a user + # then if we ran this command due to needing to, restart below. "${operation}-WindowsOptionalFeature -Online -FeatureName ${feature_name} -NoRestart -All" contain => default:powershell, classes => default:results("bundle", "state"); -# -NoRestart so that we don't wait forever for a Yes reply from a user -# then if we ran this command due to needing to, restart below. files: windows.state_repaired:: - "${_inventory.cache_file}" - delete => default:tidy; + "${_inventory.cache_file}" delete => default:tidy; } diff --git a/promise-types/ansible/example.cf b/promise-types/ansible/example.cf index 6d55e70..29f5428 100644 --- a/promise-types/ansible/example.cf +++ b/promise-types/ansible/example.cf @@ -9,7 +9,7 @@ bundle agent main { ansible: "my_playbook" - playbook => "/tmp/playbook.yaml", + playbook => "/tmp/playbook.yaml", inventory => "/tmp/inventory.yaml", - tags => {"helloworld"}; + tags => { "helloworld" }; } diff --git a/promise-types/appstreams/init.cf b/promise-types/appstreams/init.cf index 24252ab..bad8443 100644 --- a/promise-types/appstreams/init.cf +++ b/promise-types/appstreams/init.cf @@ -1,6 +1,6 @@ promise agent appstreams # @brief Define appstreams promise type { - path => "$(sys.workdir)/modules/promises/appstreams.py"; - interpreter => "/usr/bin/python3"; + path => "$(sys.workdir)/modules/promises/appstreams.py"; + interpreter => "/usr/bin/python3"; } diff --git a/promise-types/git/example.cf b/promise-types/git/example.cf index ea8f9b6..7d710d1 100644 --- a/promise-types/git/example.cf +++ b/promise-types/git/example.cf @@ -9,7 +9,7 @@ bundle agent main { git: "starter_pack_repo" - repository => "https://github.com/cfengine/starter_pack", + repository => "https://github.com/cfengine/starter_pack", destination => "$(this.promise_dirname)/starter-pack", - version => "master"; + version => "master"; } diff --git a/promise-types/git/test.cf b/promise-types/git/test.cf index 6fb482a..ef3fc38 100644 --- a/promise-types/git/test.cf +++ b/promise-types/git/test.cf @@ -2,9 +2,7 @@ body common control { version => "1.0"; } - ####################################################### - bundle agent init { files: @@ -13,8 +11,7 @@ bundle agent init file_select => all, delete => init_delete; - "$(this.promise_dirname)/starter-pack/." - delete => init_delete; + "$(this.promise_dirname)/starter-pack/." delete => init_delete; } body depth_search aggressive @@ -35,15 +32,13 @@ body file_select all body delete init_delete { dirlinks => "delete"; - rmdirs => "true"; + rmdirs => "true"; } - ####################################################### - promise agent git { - path => "$(this.promise_dirname)/git.py"; - interpreter => "/usr/bin/python3"; + path => "$(this.promise_dirname)/git.py"; + interpreter => "/usr/bin/python3"; } bundle agent test @@ -54,34 +49,32 @@ bundle agent test git: "starter_pack_repo" - repository => "https://github.com/cfengine/starter_pack", + repository => "https://github.com/cfengine/starter_pack", destination => "$(this.promise_dirname)/starter-pack", - version => "master"; + version => "master"; classes: - "promise_repaired" - expression => canonify("starter_pack_repo_updated"), - scope => "namespace"; + "promise_repaired" + expression => canonify("starter_pack_repo_updated"), + scope => "namespace"; } - ####################################################### - bundle agent check { classes: - "file_ok" - if => fileexists("$(this.promise_dirname)/starter-pack/.git"); - - "ok" expression => "file_ok.promise_repaired"; + "file_ok" if => fileexists("$(this.promise_dirname)/starter-pack/.git"); + "ok" expression => "file_ok.promise_repaired"; reports: DEBUG.file_ok:: "file_ok"; + DEBUG.promise_repaired:: "promise_repaired"; ok:: "$(this.promise_filename) Pass"; + !ok:: "$(this.promise_filename) FAIL"; } diff --git a/promise-types/groups/groups.cf b/promise-types/groups/groups.cf index f8c60cc..5ab2f38 100644 --- a/promise-types/groups/groups.cf +++ b/promise-types/groups/groups.cf @@ -3,8 +3,6 @@ # Note: As of 3.20.0, custom promise modules support the use of custom bodies. # Versions before 3.20.0 uses JSON strings or data containers to define # members instead. - - promise agent groups # @brief Define groups promise type. { @@ -21,17 +19,16 @@ body members foo exclude => { "malcom" }; } @else + bundle common foo # @breif Define members using JSON string. { vars: - "members" - string => '{ "include": ["alice", "bob"], + "members" + string => '{ "include": ["alice", "bob"], "exclude": ["malcom"] }'; } @endif - - @if minimum_version(3.20) body members bar # @breif Define members for group bar using attribute `only`. @@ -39,58 +36,51 @@ body members bar only => { "alice" }; } @else + bundle common bar # @brief Define members using data container. { vars: - "members" - data => '{ "only": ["alice"] }'; + "members" data => '{ "only": ["alice"] }'; } @endif - bundle agent example_groups # @breif Example groups promise statements. { groups: - "foo" - policy => "present", + "foo" + policy => "present", @if minimum_version(3.20) - members => foo; + members => foo; @else - members => "$(foo.members)"; + members => "$(foo.members)"; @endif - "bar" + "bar" # policy defaults to present @if minimum_version(3.20) - members => bar, + members => bar, @else - members => "@(bar.members)", + members => "@(bar.members)", @endif - gid => "1234"; + gid => "1234"; - "baz" - policy => "absent"; + "baz" policy => "absent"; } - bundle agent example_users # @breif Create users for the groups example. { users: - "alice" - policy => "present"; - "bob" - policy => "present"; - "malcom" - policy => "present"; + "alice" policy => "present"; + "bob" policy => "present"; + "malcom" policy => "present"; } - bundle agent __main__ { methods: - "example_users"; - "example_groups"; + "example_users"; + "example_groups"; } diff --git a/promise-types/http/example.cf b/promise-types/http/example.cf index 1e76909..3fd2050 100644 --- a/promise-types/http/example.cf +++ b/promise-types/http/example.cf @@ -5,20 +5,23 @@ promise agent http interpreter => "/usr/bin/python3"; } -bundle agent backup_file(file) { +bundle agent backup_file(file) +{ http: - "http://localhost:8080/backups/$file" - method => "POST", - payload => "@$(file)", - if => not(canonify(concat("$(this.promiser)", "_POST_request_done"))); + "http://localhost:8080/backups/$file" + method => "POST", + payload => "@$(file)", + if => not(canonify(concat("$(this.promiser)", "_POST_request_done"))); } -bundle agent __main__ { +bundle agent __main__ +{ http: - "https://cfengine.com/images/cfengine-logo.svg" - file => "/var/cfengine/cfengine-logo.svg", - if => not(fileexists("/var/cfengine/cfengine-logo.svg")); + "https://cfengine.com/images/cfengine-logo.svg" + file => "/var/cfengine/cfengine-logo.svg", + if => not(fileexists("/var/cfengine/cfengine-logo.svg")); methods: - "Backup cf-lock.lmdb" usebundle => backup_file("/var/cfengine/state/cf_lock.lmdb"); + "Backup cf-lock.lmdb" + usebundle => backup_file("/var/cfengine/state/cf_lock.lmdb"); } diff --git a/promise-types/iptables/test.cf b/promise-types/iptables/test.cf index 3a7104f..7841410 100755 --- a/promise-types/iptables/test.cf +++ b/promise-types/iptables/test.cf @@ -1,49 +1,44 @@ promise agent iptables { - path => "$(sys.workdir)/modules/promises/iptables.py"; - interpreter => "/usr/bin/python3"; + path => "$(sys.workdir)/modules/promises/iptables.py"; + interpreter => "/usr/bin/python3"; } body common control { - bundlesequence => { - aggressive_policy, - input_flushed, - all_flushed, - }; + bundlesequence => { aggressive_policy, input_flushed, all_flushed }; } bundle agent aggressive_policy { iptables: - "aggressive_policy" - command => "policy", - chain => "INPUT", - target => "DROP"; + "aggressive_policy" + command => "policy", + chain => "INPUT", + target => "DROP"; reports: - "--- ${this.bundle} ---"; + "--- ${this.bundle} ---"; } bundle agent input_flushed { iptables: - "input_flushed" - command => "flush", - chain => "INPUT"; + "input_flushed" + command => "flush", + chain => "INPUT"; reports: - "--- ${this.bundle} ---"; + "--- ${this.bundle} ---"; } bundle agent all_flushed { iptables: - "all_flushed" - command => "flush", - chain => "ALL"; + "all_flushed" + command => "flush", + chain => "ALL"; reports: - "--- ${this.bundle} ---"; + "--- ${this.bundle} ---"; } - diff --git a/promise-types/json/example.cf b/promise-types/json/example.cf index 91d3a84..12a5230 100644 --- a/promise-types/json/example.cf +++ b/promise-types/json/example.cf @@ -8,6 +8,5 @@ promise agent json bundle agent main { json: - "/tmp/myusers.json:name" - string => "John" + "/tmp/myusers.json:name" string => "John"; } diff --git a/promise-types/json/test.cf b/promise-types/json/test.cf index ecb5fca..c5c9c34 100644 --- a/promise-types/json/test.cf +++ b/promise-types/json/test.cf @@ -2,32 +2,34 @@ body common control { inputs => { "$(sys.libdir)/stdlib.cf" }; version => "1.0"; - bundlesequence => { "init", "test", "check", "cleanup"}; + bundlesequence => { "init", "test", "check", "cleanup" }; } - ####################################################### - bundle agent init { vars: "to_overwrite" - data => readjson("$(this.promise_dirname)/tests/to_overwrite.start.json", 100k); - "to_modify" - data => readjson("$(this.promise_dirname)/tests/to_modify.start.json", 100k); + data => readjson( + "$(this.promise_dirname)/tests/to_overwrite.start.json", 100k + ); + + "to_modify" + data => readjson( + "$(this.promise_dirname)/tests/to_modify.start.json", 100k + ); files: - "$(this.promise_dirname)/tests/to_overwrite.json" - create => "true", - content => "$(to_overwrite)"; - "$(this.promise_dirname)/tests/to_modify.json" - create => "true", - content => "$(to_modify)"; - "$(this.promise_dirname)/tests/to_append_1.json" - create => "true"; -} + "$(this.promise_dirname)/tests/to_overwrite.json" + create => "true", + content => "$(to_overwrite)"; -####################################################### + "$(this.promise_dirname)/tests/to_modify.json" + create => "true", + content => "$(to_modify)"; + "$(this.promise_dirname)/tests/to_append_1.json" create => "true"; +} +####################################################### promise agent json { path => "$(this.promise_dirname)/json_promise_type.py"; @@ -37,125 +39,121 @@ promise agent json bundle agent test { vars: - "objects" - data => '{ "bar": [1, 2, 3] }'; - "int_arrays" - data => '[1,2,3]'; - "arrays" - ilist => { "1", "2" }; # slist == rlist == ilist -> lists of string - "numbers" - int => "1"; - "strings" - string => "hello"; - "bools" - string => "true"; - "nulls" - string => "null"; + "objects" data => '{ "bar": [1, 2, 3] }'; + "int_arrays" data => '[1,2,3]'; + "arrays" ilist => { "1", "2" }; + # slist == rlist == ilist -> lists of string + "numbers" int => "1"; + "strings" string => "hello"; + "bools" string => "true"; + "nulls" string => "null"; json: - "$(this.promise_dirname)/tests/to_overwrite.json" - object => "@(objects)"; - - "$(this.promise_dirname)/tests/to_modify.json:Hello" - string => "$(strings)"; + "$(this.promise_dirname)/tests/to_overwrite.json" object => "@(objects)"; + "$(this.promise_dirname)/tests/to_modify.json:Hello" string => "$(strings)"; + "$(this.promise_dirname)/tests/to_append_1.json:a" object => "@(objects)"; - "$(this.promise_dirname)/tests/to_append_1.json:a" - object => "@(objects)"; "$(this.promise_dirname)/tests/to_append_1.json:b" object => "@(int_arrays)"; - "$(this.promise_dirname)/tests/to_append_1.json:c" - array => "@(int_arrays)"; - "$(this.promise_dirname)/tests/to_append_1.json:d" - string => "$(strings)"; - "$(this.promise_dirname)/tests/to_append_1.json:e" - number => "$(numbers)"; - "$(this.promise_dirname)/tests/to_append_1.json:f" - primitive => "$(bools)"; - "$(this.promise_dirname)/tests/to_append_1.json:g" - primitive => "$(nulls)"; + + "$(this.promise_dirname)/tests/to_append_1.json:c" array => "@(int_arrays)"; + "$(this.promise_dirname)/tests/to_append_1.json:d" string => "$(strings)"; + "$(this.promise_dirname)/tests/to_append_1.json:e" number => "$(numbers)"; + "$(this.promise_dirname)/tests/to_append_1.json:f" primitive => "$(bools)"; + "$(this.promise_dirname)/tests/to_append_1.json:g" primitive => "$(nulls)"; "$(this.promise_dirname)/tests/to_append_2.json:a" object => '{ "bar": [1, 2, 3] }'; - "$(this.promise_dirname)/tests/to_append_2.json:b" - object => '[1,2,3]'; - "$(this.promise_dirname)/tests/to_append_2.json:c" - array => '[1,2,3]'; - "$(this.promise_dirname)/tests/to_append_2.json:d" - string => "hello"; - "$(this.promise_dirname)/tests/to_append_2.json:e" - number => "1"; - "$(this.promise_dirname)/tests/to_append_2.json:f" - primitive => "true"; - "$(this.promise_dirname)/tests/to_append_2.json:g" - primitive => "null"; + "$(this.promise_dirname)/tests/to_append_2.json:b" object => '[1,2,3]'; + "$(this.promise_dirname)/tests/to_append_2.json:c" array => '[1,2,3]'; + "$(this.promise_dirname)/tests/to_append_2.json:d" string => "hello"; + "$(this.promise_dirname)/tests/to_append_2.json:e" number => "1"; + "$(this.promise_dirname)/tests/to_append_2.json:f" primitive => "true"; + "$(this.promise_dirname)/tests/to_append_2.json:g" primitive => "null"; } - ####################################################### - bundle agent check { vars: "to_overwrite_content" - data => readjson("$(this.promise_dirname)/tests/to_overwrite.json", 100k); + data => readjson( + "$(this.promise_dirname)/tests/to_overwrite.json", 100k + ); + "to_modify_content" data => readjson("$(this.promise_dirname)/tests/to_modify.json", 100k); + "to_append_1_content" data => readjson("$(this.promise_dirname)/tests/to_append_1.json", 100k); + "to_append_2_content" data => readjson("$(this.promise_dirname)/tests/to_append_2.json", 100k); "to_overwrite_content_true" - data => readjson("$(this.promise_dirname)/tests/to_overwrite.expected.json", 100k); + data => readjson( + "$(this.promise_dirname)/tests/to_overwrite.expected.json", 100k + ); + "to_modify_content_true" - data => readjson("$(this.promise_dirname)/tests/to_modify.expected.json", 100k); + data => readjson( + "$(this.promise_dirname)/tests/to_modify.expected.json", 100k + ); + "to_append_content_true" - data => readjson("$(this.promise_dirname)/tests/to_append.expected.json", 100k); + data => readjson( + "$(this.promise_dirname)/tests/to_append.expected.json", 100k + ); - "to_overwrite_content_indices" - slist => getindices("to_overwrite_content"); - "to_modify_content_indices" - slist => getindices("to_modify_content"); - "to_append_1_content_indices" - slist => getindices("to_append_1_content"); - "to_append_2_content_indices" - slist => getindices("to_append_2_content"); + "to_overwrite_content_indices" slist => getindices("to_overwrite_content"); + "to_modify_content_indices" slist => getindices("to_modify_content"); + "to_append_1_content_indices" slist => getindices("to_append_1_content"); + "to_append_2_content_indices" slist => getindices("to_append_2_content"); "to_overwrite_content_true_indices" slist => getindices("to_overwrite_content_true"); + "to_modify_content_true_indices" slist => getindices("to_modify_content_true"); + "to_append_content_true_indices" slist => getindices("to_append_content_true"); classes: "ok" - expression => and ( - strcmp("$(to_overwrite_content[$(to_overwrite_content_indices)])", "$(to_overwrite_content_true[$(to_overwrite_content_true_indices)])"), - strcmp("$(to_modify_content[$(to_modify_content_indices)])", "$(to_modify_content_true[$(to_modify_content_true_indices)])"), - strcmp("$(to_append_1_content[$(to_append_1_content_indices)])", "$(to_append_2_content[$(to_append_2_content_indices)])"), - strcmp("$(to_append_1_content[$(to_append_1_content_indices)])", "$(to_append_content_true[$(to_append_content_true_indices)])") + expression => and( + strcmp( + "$(to_overwrite_content[$(to_overwrite_content_indices)])", + "$(to_overwrite_content_true[$(to_overwrite_content_true_indices)])" + ), + strcmp( + "$(to_modify_content[$(to_modify_content_indices)])", + "$(to_modify_content_true[$(to_modify_content_true_indices)])" + ), + strcmp( + "$(to_append_1_content[$(to_append_1_content_indices)])", + "$(to_append_2_content[$(to_append_2_content_indices)])" + ), + strcmp( + "$(to_append_1_content[$(to_append_1_content_indices)])", + "$(to_append_content_true[$(to_append_content_true_indices)])" + ) ); reports: ok:: "$(this.promise_filename) Pass"; + !ok:: "$(this.promise_filename) FAIL"; } - # ####################################################### - bundle agent cleanup { files: - "$(this.promise_dirname)/tests/to_overwrite.json" - delete => tidy; - "$(this.promise_dirname)/tests/to_modify.json" - delete => tidy; - "$(this.promise_dirname)/tests/to_append_1.json" - delete => tidy; - "$(this.promise_dirname)/tests/to_append_2.json" - delete => tidy; + "$(this.promise_dirname)/tests/to_overwrite.json" delete => tidy; + "$(this.promise_dirname)/tests/to_modify.json" delete => tidy; + "$(this.promise_dirname)/tests/to_append_1.json" delete => tidy; + "$(this.promise_dirname)/tests/to_append_2.json" delete => tidy; } diff --git a/promise-types/json/tests/to_modify.start.json b/promise-types/json/tests/to_modify.start.json index 02bb47e..c7acc90 100644 --- a/promise-types/json/tests/to_modify.start.json +++ b/promise-types/json/tests/to_modify.start.json @@ -1,3 +1,3 @@ { - "Hello": "World" + "Hello": "World" } diff --git a/promise-types/json/tests/to_overwrite.start.json b/promise-types/json/tests/to_overwrite.start.json index 02bb47e..c7acc90 100644 --- a/promise-types/json/tests/to_overwrite.start.json +++ b/promise-types/json/tests/to_overwrite.start.json @@ -1,3 +1,3 @@ { - "Hello": "World" + "Hello": "World" } diff --git a/promise-types/symlinks/example.cf b/promise-types/symlinks/example.cf index 0fafc2b..c2dc450 100644 --- a/promise-types/symlinks/example.cf +++ b/promise-types/symlinks/example.cf @@ -8,8 +8,6 @@ promise agent symlinks bundle agent main { symlinks: - "/tmp/myfilelink" - file => "tmp/myfile"; - "/tmp/mydirlink" - directory => "tmp/mydirectory"; + "/tmp/myfilelink" file => "tmp/myfile"; + "/tmp/mydirlink" directory => "tmp/mydirectory"; } diff --git a/promise-types/symlinks/test.cf b/promise-types/symlinks/test.cf index 468ac0d..828ab69 100644 --- a/promise-types/symlinks/test.cf +++ b/promise-types/symlinks/test.cf @@ -2,28 +2,19 @@ body common control { inputs => { "$(sys.libdir)/stdlib.cf" }; version => "1.0"; - bundlesequence => { "init", "test", "check", "cleanup"}; + bundlesequence => { "init", "test", "check", "cleanup" }; } - ####################################################### - bundle agent init { files: - "/tmp/my-file" - create => "true"; - "/tmp/my-dir/." - create => "true"; - "/tmp/other-dir/." - create => "true"; - "/tmp/replaced-link" - link_from => ln_s("/tmp/other-dir"); - "/tmp/already-existing-link" - link_from => ln_s("/tmp/other-dir"); + "/tmp/my-file" create => "true"; + "/tmp/my-dir/." create => "true"; + "/tmp/other-dir/." create => "true"; + "/tmp/replaced-link" link_from => ln_s("/tmp/other-dir"); + "/tmp/already-existing-link" link_from => ln_s("/tmp/other-dir"); } - ####################################################### - promise agent symlinks { path => "$(this.promise_dirname)/symlinks.py"; @@ -46,36 +37,33 @@ bundle agent test "/tmp/file-link" file => "/tmp/my-file", classes => outcome("created_file"); + "/tmp/dir-link" directory => "/tmp/my-dir", classes => outcome("created_dir"); + "/tmp/replaced-link" directory => "/tmp/my-dir", classes => outcome("corrected"); + "/tmp/already-existing-link" directory => "/tmp/other-dir", classes => outcome("didnothing"); - } - ####################################################### - bundle agent check { - vars: - "my_file_stat" - string => filestat("/tmp/file-link", "linktarget"); - "my_dir_stat" - string => filestat("/tmp/dir-link", "linktarget"); - "replaced_link_stat" - string => filestat("/tmp/replaced-link", "linktarget"); + "my_file_stat" string => filestat("/tmp/file-link", "linktarget"); + "my_dir_stat" string => filestat("/tmp/dir-link", "linktarget"); + "replaced_link_stat" string => filestat("/tmp/replaced-link", "linktarget"); + "already_existing_link_stat" string => filestat("/tmp/already-existing-link", "linktarget"); classes: "ok" - expression => and ( + expression => and( strcmp("$(my_file_stat)", "/tmp/my-file"), strcmp("$(my_dir_stat)", "/tmp/my-dir"), strcmp("$(replaced_link_stat)", "/tmp/my-dir"), @@ -89,28 +77,19 @@ bundle agent check reports: ok:: "$(this.promise_filename) Pass"; + !ok:: "$(this.promise_filename) FAIL"; - } - # ####################################################### - bundle agent cleanup { files: - "/tmp/file-link" - delete => tidy; - "/tmp/dir-link" - delete => tidy; - "/tmp/my-file" - delete => tidy; - "/tmp/my-dir/." - delete => tidy; - "/tmp/other-dir/." - delete => tidy; - "/tmp/replaced-link" - delete => tidy; - "/tmp/already-existing-link" - delete => tidy; + "/tmp/file-link" delete => tidy; + "/tmp/dir-link" delete => tidy; + "/tmp/my-file" delete => tidy; + "/tmp/my-dir/." delete => tidy; + "/tmp/other-dir/." delete => tidy; + "/tmp/replaced-link" delete => tidy; + "/tmp/already-existing-link" delete => tidy; } diff --git a/promise-types/systemd/example.cf b/promise-types/systemd/example.cf index da3c3da..1a0595b 100644 --- a/promise-types/systemd/example.cf +++ b/promise-types/systemd/example.cf @@ -14,7 +14,7 @@ bundle agent main enabled => "true", state => "restarted", unit_description => "my sample service", - service_exec_start => {"/usr/bin/sleep 86400"}, + service_exec_start => { "/usr/bin/sleep 86400" }, service_type => "simple", - install_wanted_by => {"multi-user.target"}; + install_wanted_by => { "multi-user.target" }; } diff --git a/promise-types/systemd/test.cf b/promise-types/systemd/test.cf index a5b21fc..5a05975 100644 --- a/promise-types/systemd/test.cf +++ b/promise-types/systemd/test.cf @@ -2,20 +2,15 @@ body common control { version => "1.0"; } - ####################################################### - bundle agent init { - } - ####################################################### - promise agent systemd { - path => "$(this.promise_dirname)/systemd.py"; - interpreter => "/usr/bin/python3"; + path => "$(this.promise_dirname)/systemd.py"; + interpreter => "/usr/bin/python3"; } bundle agent test @@ -31,40 +26,36 @@ bundle agent test enabled => "true", state => "restarted", unit_description => "my sample service", - service_exec_start => {"/usr/bin/sleep 86400"}, + service_exec_start => { "/usr/bin/sleep 86400" }, service_type => "simple", - install_wanted_by => {"multi-user.target"}; + install_wanted_by => { "multi-user.target" }; classes: - "promise_repaired" - expression => canonify("sample_restarted"), - scope => "namespace"; + "promise_repaired" + expression => canonify("sample_restarted"), + scope => "namespace"; } - ####################################################### - bundle agent check { classes: - "file_ok" - if => fileexists("/lib/systemd/system/sample.service"); - - "ok" expression => "file_ok.promise_repaired"; + "file_ok" if => fileexists("/lib/systemd/system/sample.service"); + "ok" expression => "file_ok.promise_repaired"; reports: DEBUG.file_ok:: "file_ok"; + DEBUG.promise_repaired:: "promise_repaired"; ok:: "$(this.promise_filename) Pass"; + !ok:: "$(this.promise_filename) FAIL"; } - ####################################################### - bundle agent cleanup { systemd: diff --git a/pyrightconfig.json b/pyrightconfig.json index 3ab6871..c956607 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -1,4 +1,4 @@ { - "reportMissingImports": "none", - "extraPaths": ["libraries/python"] + "reportMissingImports": "none", + "extraPaths": ["libraries/python"] } diff --git a/security/conditional-installer/main.cf b/security/conditional-installer/main.cf index 8493954..996f7e1 100644 --- a/security/conditional-installer/main.cf +++ b/security/conditional-installer/main.cf @@ -7,7 +7,9 @@ bundle agent main { classes: "enabled" - if => and(isvariable(packages_to_install), isvariable(packages_to_uninstall)); + if => and( + isvariable(packages_to_install), isvariable(packages_to_uninstall) + ); vars: # Mock data, should be based on input: @@ -21,14 +23,16 @@ bundle agent main # ]'; enabled:: # Determine packages to install: - "i" - slist => getindices(packages_to_install); + "i" slist => getindices(packages_to_install); + "_packages_to_install_lists[$(i)]" - slist => string_split("$(packages_to_install[$(i)][packages])", ",", 100), + slist => string_split( + "$(packages_to_install[$(i)][packages])", ",", 100 + ), if => "$(packages_to_install[$(i)][condition])", comment => "$(packages_to_install[$(i)][why])"; - "_packages_to_install" - slist => getvalues(_packages_to_install_lists); + + "_packages_to_install" slist => getvalues(_packages_to_install_lists); # Determine packages to uninstall: "_packages_to_uninstall_unfiltered" @@ -36,16 +40,13 @@ bundle agent main "_packages_to_uninstall" slist => difference( - _packages_to_uninstall_unfiltered, - _packages_to_install + _packages_to_uninstall_unfiltered, _packages_to_install ); packages: enabled:: - "$(_packages_to_uninstall)" - policy => "absent"; - "$(_packages_to_install)" - policy => "present"; + "$(_packages_to_uninstall)" policy => "absent"; + "$(_packages_to_install)" policy => "present"; } body file control diff --git a/security/cron-access/cron-access.cf b/security/cron-access/cron-access.cf index 4e8e321..fc2a2b6 100644 --- a/security/cron-access/cron-access.cf +++ b/security/cron-access/cron-access.cf @@ -21,9 +21,11 @@ bundle agent cron_access "$(directories)" perms => mog("700", "root", "root"), if => fileexists("$(this.promiser)"); + "/etc/cron.allow" perms => mog("640", "root", "root"), if => fileexists("$(this.promiser)"); + "/etc/crontab" perms => mog("600", "root", "root"), if => fileexists("$(this.promiser)"); diff --git a/security/delete-home-dotrhosts/policy/main.cf b/security/delete-home-dotrhosts/policy/main.cf index d0500a5..915a75d 100644 --- a/security/delete-home-dotrhosts/policy/main.cf +++ b/security/delete-home-dotrhosts/policy/main.cf @@ -1,6 +1,6 @@ body file control { - namespace => "delete_home_dotrhosts"; + namespace => "delete_home_dotrhosts"; } bundle agent main @@ -9,7 +9,6 @@ bundle agent main # @inventory ~/.rhosts list of ~.rhosts files found. # @inventory ~/.rhosts Exception The string defined that records the details about why a host has an exception for this policy. { - classes: "dotrhosts_management_disabled" or => { @@ -21,30 +20,29 @@ bundle agent main vars: dotrhosts_management_disabled:: - "exception" # Fill in exception reason if missing (class was used) + # Fill in exception reason if missing (class was used) + "exception" string => "Unknown reason", if => not(isvariable("delete_home_dotrhosts:main.exception")); !default:windows:: - # /home and /root are common default home dir roots, but it's not uncommon # to have other home dir roots - "home_dir_roots" slist => { "/home" }, meta => { "noreport" }, - if => not( isvariable( "home_dir_roots" )); + if => not(isvariable("home_dir_roots")); - # Find .rhosts files in the root of peoples home directories. + # Find .rhosts files in the root of peoples home directories. "_found[$(home_dir_roots)]" - slist => findfiles( "$(home_dir_roots)/*/.rhosts" ), - if => isdir( $(home_dir_roots) ); + slist => findfiles("$(home_dir_roots)/*/.rhosts"), + if => isdir($(home_dir_roots)); + "_found[/root]" slist => { "/root/.rhosts" }, - if => fileexists( "/root/.rhosts" ); + if => fileexists("/root/.rhosts"); - "_found" - slist => getvalues( _found ); + "_found" slist => getvalues(_found); # We inventory the found files so that we easily know where they are. # This way, even hosts with exceptions will report the inventory, but not @@ -60,16 +58,15 @@ bundle agent main "inv_exception" string => "$(exception)", - if => isvariable( "exception" ), + if => isvariable("exception"), meta => { "inventory", "attribute_name=~/.rhosts exception reason" }; files: !dotrhosts_management_disabled.!default:windows:: - "$(_found)" - delete => default:tidy; + "$(_found)" delete => default:tidy; reports: dotrhosts_management_disabled.(default:inform_mode|default:verbose_mode):: "Found $(with), but not removing because of exception: $(exception)" - with => join( ", ", _found ); + with => join(", ", _found); } diff --git a/security/delete-home-dotshosts/policy/main.cf b/security/delete-home-dotshosts/policy/main.cf index 1a83630..f4ce639 100644 --- a/security/delete-home-dotshosts/policy/main.cf +++ b/security/delete-home-dotshosts/policy/main.cf @@ -1,6 +1,6 @@ body file control { - namespace => "delete_home_dotshosts"; + namespace => "delete_home_dotshosts"; } bundle agent main @@ -9,7 +9,6 @@ bundle agent main # @inventory ~/.shosts list of ~.shosts files found. # @inventory ~/.shosts Exception The string defined that records the details about why a host has an exception for this policy. { - classes: "dotshosts_management_disabled" or => { @@ -21,30 +20,29 @@ bundle agent main vars: dotshosts_management_disabled:: - "exception" # Fill in exception reason if missing (class was used) + # Fill in exception reason if missing (class was used) + "exception" string => "Unknown reason", if => not(isvariable("delete_home_dotshosts:main.exception")); !default:windows:: - # /home and /root are common default home dir roots, but it's not uncommon # to have other home dir roots - "home_dir_roots" slist => { "/home" }, meta => { "noreport" }, - if => not( isvariable( "home_dir_roots" )); + if => not(isvariable("home_dir_roots")); - # Find .shosts files in the root of peoples home directories. + # Find .shosts files in the root of peoples home directories. "_found[$(home_dir_roots)]" - slist => findfiles( "$(home_dir_roots)/*/.shosts" ), - if => isdir( $(home_dir_roots) ); + slist => findfiles("$(home_dir_roots)/*/.shosts"), + if => isdir($(home_dir_roots)); + "_found[/root]" slist => { "/root/.shosts" }, - if => fileexists( "/root/.shosts" ); + if => fileexists("/root/.shosts"); - "_found" - slist => getvalues( _found ); + "_found" slist => getvalues(_found); # We inventory the found files so that we easily know where they are. # This way, even hosts with exceptions will report the inventory, but not @@ -60,16 +58,15 @@ bundle agent main "inv_exception" string => "$(exception)", - if => isvariable( "exception" ), + if => isvariable("exception"), meta => { "inventory", "attribute_name=~/.shosts exception reason" }; files: !dotshosts_management_disabled.!default:windows:: - "$(_found)" - delete => default:tidy; + "$(_found)" delete => default:tidy; reports: dotshosts_management_disabled.(default:inform_mode|default:verbose_mode):: "Found $(with), but not removing because of exception: $(exception)" - with => join( ", ", _found ); + with => join(", ", _found); } diff --git a/security/dirtyfrag/dirtyfrag.cf b/security/dirtyfrag/dirtyfrag.cf index 80bbdf1..2fc6b10 100644 --- a/security/dirtyfrag/dirtyfrag.cf +++ b/security/dirtyfrag/dirtyfrag.cf @@ -21,8 +21,7 @@ bundle agent main # Minimum patched kernel package versions per distro live in # patched-kernels.json next to this policy. The data file is # walked here; comparison happens in the classes:: block below. - "_data_file" - string => "$(this.promise_dirname)/patched-kernels.json"; + "_data_file" string => "$(this.promise_dirname)/patched-kernels.json"; "_data" data => readjson("${_data_file}"), @@ -47,7 +46,9 @@ bundle agent main string => "${_entries_idx}", if => and( regcmp("${_data[entries][${_entries_idx}][id_match]}", "${_os_id}"), - regcmp("${_data[entries][${_entries_idx}][version_match]}", "${_os_ver}") + regcmp( + "${_data[entries][${_entries_idx}][version_match]}", "${_os_ver}" + ) ); "_esp_patched_ver" @@ -80,8 +81,8 @@ bundle agent main if => not(regcmp("debian|ubuntu", "$(default:sys.os_release[ID])")); # --- Mitigation-conf paths and contents ----------------------- - "_esp_conf_path" string => "/etc/modprobe.d/dirtyfrag-esp.conf"; - "_rxrpc_conf_path" string => "/etc/modprobe.d/dirtyfrag-rxrpc.conf"; + "_esp_conf_path" string => "/etc/modprobe.d/dirtyfrag-esp.conf"; + "_rxrpc_conf_path" string => "/etc/modprobe.d/dirtyfrag-rxrpc.conf"; "_userns_conf_path" string => "/etc/sysctl.d/dirtyfrag-userns.conf"; "_esp_conf_content" @@ -135,15 +136,16 @@ bundle agent main # filter(".+", ...) drops the empties; join glues with ", ". "_esp_loaded_list" slist => { - ifelse("_esp4_loaded", "esp4", ""), - ifelse("_esp6_loaded", "esp6", ""), - ifelse("_ipcomp_loaded", "ipcomp", ""), + ifelse("_esp4_loaded", "esp4", ""), + ifelse("_esp6_loaded", "esp6", ""), + ifelse("_ipcomp_loaded", "ipcomp", ""), ifelse("_ipcomp6_loaded", "ipcomp6", ""), }; "_esp_loaded_names" - string => join(", ", - filter(".+", "_esp_loaded_list", "false", "false", "10")); + string => join( + ", ", filter(".+", "_esp_loaded_list", "false", "false", "10") + ); # --- Status strings ------------------------------------------- "_esp_status" @@ -180,20 +182,29 @@ bundle agent main # the long _esp_status string. ifelse takes first-match order. "_esp_mitigation_method" string => ifelse( - "dirtyfrag_esp_needs_mitigation", "none", - "_esp_kernel_patched", "kernel-patch", - "_esp_admin_patched", "admin-override", - "_esp_conf_exists", "modprobe", - "_userns_conf_exists", "userns", + "dirtyfrag_esp_needs_mitigation", + "none", + "_esp_kernel_patched", + "kernel-patch", + "_esp_admin_patched", + "admin-override", + "_esp_conf_exists", + "modprobe", + "_userns_conf_exists", + "userns", "not-applicable" ); "_rxrpc_mitigation_method" string => ifelse( - "dirtyfrag_rxrpc_needs_mitigation", "none", - "_rxrpc_kernel_patched", "kernel-patch", - "_rxrpc_admin_patched", "admin-override", - "_rxrpc_conf_exists", "modprobe", + "dirtyfrag_rxrpc_needs_mitigation", + "none", + "_rxrpc_kernel_patched", + "kernel-patch", + "_rxrpc_admin_patched", + "admin-override", + "_rxrpc_conf_exists", + "modprobe", "not-applicable" ); @@ -234,12 +245,12 @@ bundle agent main classes: # --- CMDB toggles --------------------------------------------- - "_mitigate_esp" expression => strcmp("true", "$(mitigate_esp)"); - "_mitigate_rxrpc" expression => strcmp("true", "$(mitigate_rxrpc)"); + "_mitigate_esp" expression => strcmp("true", "$(mitigate_esp)"); + "_mitigate_rxrpc" expression => strcmp("true", "$(mitigate_rxrpc)"); "_mitigate_userns" expression => strcmp("true", "$(mitigate_userns)"); # --- Admin override: manually declare host as patched --------- - "_esp_admin_patched" expression => strcmp("true", "$(esp_patched)"); + "_esp_admin_patched" expression => strcmp("true", "$(esp_patched)"); "_rxrpc_admin_patched" expression => strcmp("true", "$(rxrpc_patched)"); # --- Kernel-patch comparison ---------------------------------- @@ -251,18 +262,14 @@ bundle agent main # (tempfile + commands:, or a bundled wrapper script) are heavier # for no real safety gain on a static, internally-built string. # See lessons-learned/version-compare-shell-exception.md. - "_patch_data_matched" - expression => isvariable("_matched_idx"); + "_patch_data_matched" expression => isvariable("_matched_idx"); "_esp_kernel_patched" expression => returnszero( "printf '%s\\n%s\\n' '$(_esp_patched_ver)' '$(_kernel_pkg_ver)' | sort -V -C", "useshell" ), - if => and( - isvariable("_esp_patched_ver"), - isvariable("_kernel_pkg_ver") - ); + if => and(isvariable("_esp_patched_ver"), isvariable("_kernel_pkg_ver")); "_rxrpc_kernel_patched" expression => returnszero( @@ -270,22 +277,20 @@ bundle agent main "useshell" ), if => and( - isvariable("_rxrpc_patched_ver"), - isvariable("_kernel_pkg_ver") + isvariable("_rxrpc_patched_ver"), isvariable("_kernel_pkg_ver") ); # --- Unprivileged user namespace enabled? --------------------- "_userns_disabled" expression => strcmp("0", "${_max_userns}"); - "_userns_enabled" not => "_userns_disabled"; + "_userns_enabled" not => "_userns_disabled"; # --- xfrm-ESP/IPComp modules ---------------------------------- # On-disk presence collapses to: did findfiles return anything? # some(".+", slist) is true when the list has any non-empty element. "_esp_files_present" expression => some(".+", "_esp_module_files"); - - "_esp4_loaded" expression => isdir("/sys/module/esp4"); - "_esp6_loaded" expression => isdir("/sys/module/esp6"); - "_ipcomp_loaded" expression => isdir("/sys/module/ipcomp"); + "_esp4_loaded" expression => isdir("/sys/module/esp4"); + "_esp6_loaded" expression => isdir("/sys/module/esp6"); + "_ipcomp_loaded" expression => isdir("/sys/module/ipcomp"); "_ipcomp6_loaded" expression => isdir("/sys/module/ipcomp6"); "_esp_any_loaded" @@ -293,19 +298,16 @@ bundle agent main "_esp4_loaded", "_esp6_loaded", "_ipcomp_loaded", "_ipcomp6_loaded" }; - "dirtyfrag_esp_present" - or => { "_esp_files_present", "_esp_any_loaded" }; + "dirtyfrag_esp_present" or => { "_esp_files_present", "_esp_any_loaded" }; # --- RxRPC module --------------------------------------------- "_rxrpc_files_present" expression => some(".+", "_rxrpc_module_files"); - "_rxrpc_loaded" expression => isdir("/sys/module/rxrpc"); - - "dirtyfrag_rxrpc_present" - or => { "_rxrpc_files_present", "_rxrpc_loaded" }; + "_rxrpc_loaded" expression => isdir("/sys/module/rxrpc"); + "dirtyfrag_rxrpc_present" or => { "_rxrpc_files_present", "_rxrpc_loaded" }; # --- Mitigation conf files in place? -------------------------- - "_esp_conf_exists" expression => fileexists("${_esp_conf_path}"); - "_rxrpc_conf_exists" expression => fileexists("${_rxrpc_conf_path}"); + "_esp_conf_exists" expression => fileexists("${_esp_conf_path}"); + "_rxrpc_conf_exists" expression => fileexists("${_rxrpc_conf_path}"); "_userns_conf_exists" expression => fileexists("${_userns_conf_path}"); # ESP is mitigated by modprobe blacklist, patched kernel, or @@ -313,18 +315,14 @@ bundle agent main # vulnerability condition (see dirtyfrag_esp_needs_mitigation). "_esp_mitigated" or => { - "_esp_conf_exists", - "_esp_kernel_patched", - "_esp_admin_patched", + "_esp_conf_exists", "_esp_kernel_patched", "_esp_admin_patched", }; # RxRPC is mitigated by the modprobe blacklist, patched kernel, # or admin override. "_rxrpc_mitigated" or => { - "_rxrpc_conf_exists", - "_rxrpc_kernel_patched", - "_rxrpc_admin_patched", + "_rxrpc_conf_exists", "_rxrpc_kernel_patched", "_rxrpc_admin_patched", }; # --- Per-CVE vulnerability checks ----------------------------- @@ -334,13 +332,15 @@ bundle agent main # confs); it's tracked here so disabling userns blocks the # exploit vector directly. "dirtyfrag_esp_needs_mitigation" - and => { "dirtyfrag_esp_present", "!_esp_mitigated", "!_userns_conf_exists" }, - meta => { "report" }, + and => { + "dirtyfrag_esp_present", "!_esp_mitigated", "!_userns_conf_exists" + }, + meta => { "report" }, scope => "namespace"; "dirtyfrag_rxrpc_needs_mitigation" - and => { "dirtyfrag_rxrpc_present", "!_rxrpc_mitigated" }, - meta => { "report" }, + and => { "dirtyfrag_rxrpc_present", "!_rxrpc_mitigated" }, + meta => { "report" }, scope => "namespace"; # --- Composite roll-ups for targeting and querying ------------ @@ -348,18 +348,20 @@ bundle agent main # don't clutter the default Mission Portal inventory columns. Use # for class filters in reports, alerts, and CMDB-style targeting. "dirtyfrag_vulnerable" - or => { "dirtyfrag_esp_needs_mitigation", "dirtyfrag_rxrpc_needs_mitigation" }, - meta => { "report" }, + or => { + "dirtyfrag_esp_needs_mitigation", "dirtyfrag_rxrpc_needs_mitigation" + }, + meta => { "report" }, scope => "namespace"; "dirtyfrag_esp_mitigated" - or => { "_esp_mitigated", "_userns_conf_exists" }, - meta => { "report" }, + or => { "_esp_mitigated", "_userns_conf_exists" }, + meta => { "report" }, scope => "namespace"; "dirtyfrag_rxrpc_mitigated" - or => { "_rxrpc_mitigated" }, - meta => { "report" }, + or => { "_rxrpc_mitigated" }, + meta => { "report" }, scope => "namespace"; files: @@ -368,25 +370,24 @@ bundle agent main # promise detail page so operators can search "CVE-2026-43284" # and find every policy artifact addressing it. # handle gives each promise a stable, queryable name in reports. - _mitigate_esp:: "${_esp_conf_path}" -> { "CVE-2026-43284" } - handle => "dirtyfrag_esp_modprobe_blacklist", - create => "true", + handle => "dirtyfrag_esp_modprobe_blacklist", + create => "true", content => "${_esp_conf_content}", comment => "Blacklist xfrm-ESP/IPComp modules to mitigate Dirty Frag CVE-2026-43284"; _mitigate_rxrpc:: "${_rxrpc_conf_path}" -> { "CVE-2026-43500" } - handle => "dirtyfrag_rxrpc_modprobe_blacklist", - create => "true", + handle => "dirtyfrag_rxrpc_modprobe_blacklist", + create => "true", content => "${_rxrpc_conf_content}", comment => "Blacklist RxRPC module to mitigate Dirty Frag CVE-2026-43500"; _mitigate_userns:: "${_userns_conf_path}" -> { "CVE-2026-43284" } - handle => "dirtyfrag_userns_sysctl_conf", - create => "true", + handle => "dirtyfrag_userns_sysctl_conf", + create => "true", content => "${_userns_conf_content}", comment => "Disable unprivileged user namespaces to block CVE-2026-43284 ESP exploit path"; @@ -398,16 +399,15 @@ bundle agent main # modprobe -r (vs rmmod) tolerates "some of the named modules # aren't loaded", which simplifies the per-module gating to a # single class. - _mitigate_esp._esp_any_loaded:: "/sbin/modprobe" -> { "CVE-2026-43284" } - handle => "dirtyfrag_esp_modprobe_unload", + handle => "dirtyfrag_esp_modprobe_unload", arglist => { "-r", "esp4", "esp6", "ipcomp", "ipcomp6" }, comment => "Unload ESP/IPComp modules while ESP mitigation is active"; _mitigate_rxrpc._rxrpc_loaded:: "/sbin/modprobe" -> { "CVE-2026-43500" } - handle => "dirtyfrag_rxrpc_modprobe_unload", + handle => "dirtyfrag_rxrpc_modprobe_unload", arglist => { "-r", "rxrpc" }, comment => "Unload RxRPC module while RxRPC mitigation is active"; @@ -417,7 +417,7 @@ bundle agent main # boot). _mitigate_userns._userns_enabled:: "/sbin/sysctl" -> { "CVE-2026-43284" } - handle => "dirtyfrag_userns_sysctl_reapply", + handle => "dirtyfrag_userns_sysctl_reapply", arglist => { "--system" }, comment => "Re-apply user.max_user_namespaces=0 while userns is enabled"; @@ -432,7 +432,6 @@ bundle agent main "Dirty Frag CVE-2026-43500: kernel $(_kernel_pkg_ver) >= $(_rxrpc_patched_ver) (PATCHED)"; inform_mode:: - "Dirty Frag CVE-2026-43284 (xfrm-ESP/IPComp): $(_esp_status)"; "Dirty Frag CVE-2026-43500 (RxRPC): $(_rxrpc_status)"; } diff --git a/security/enable-aslr/enable-aslr.cf b/security/enable-aslr/enable-aslr.cf index ef7a84a..7acdbb3 100644 --- a/security/enable-aslr/enable-aslr.cf +++ b/security/enable-aslr/enable-aslr.cf @@ -13,21 +13,23 @@ bundle agent enable_aslr "aslr_mode[0]" string => "Disabled"; "aslr_mode[1]" string => "Conservative Randomization"; "aslr_mode[2]" string => "Full Randomization"; - "aslr_proc_path" string => "/proc/sys/kernel/randomize_va_space"; "aslr_conf_path" string => "/etc/sysctl.d/60-enable-aslr.conf"; "aslr_value" string => readfile("${aslr_proc_path}"); - "randomize_va_space_inventory" string => "${aslr_mode[${aslr_value}]} (${aslr_value})", - meta => { "inventory", "attribute_name=Address space layout randomization (ASLR)" }, + + "randomize_va_space_inventory" + string => "${aslr_mode[${aslr_value}]} (${aslr_value})", + meta => { + "inventory", + "attribute_name=Address space layout randomization (ASLR)", + }, comment => "Report on Address space layout randomization (ASLR) mode"; classes: "aslr_enabled" expression => strcmp("${aslr_value}", "2"); + "aslr_management_disabled" - or => { - "exception_enable_aslr", - "data:exception_enable_aslr", - }; + or => { "exception_enable_aslr", "data:exception_enable_aslr" }; files: !aslr_management_disabled.(linux.!aslr_enabled):: @@ -37,6 +39,5 @@ bundle agent enable_aslr commands: !aslr_management_disabled.(linux.!aslr_enabled):: - "sysctl --load ${aslr_conf_path}" - contain => in_shell; + "sysctl --load ${aslr_conf_path}" contain => in_shell; } diff --git a/security/etc-issue-access/etc-issue-access.cf b/security/etc-issue-access/etc-issue-access.cf index 83c463f..670c445 100644 --- a/security/etc-issue-access/etc-issue-access.cf +++ b/security/etc-issue-access/etc-issue-access.cf @@ -8,7 +8,7 @@ bundle agent etc_issue_access # https://static.open-scap.org/ssg-guides/ssg-rhel7-guide-anssi_nt28_minimal.html { files: - "/etc/issue" -> { "CCE-83717-9", "CCE-83707-0", "CCE-83347-5"} + "/etc/issue" -> { "CCE-83717-9", "CCE-83707-0", "CCE-83347-5" } perms => mog("644", "root", "root"), if => fileexists("$(this.promiser)"); } diff --git a/security/etc-motd-access/etc-motd-access.cf b/security/etc-motd-access/etc-motd-access.cf index 36627b4..3f0f7ec 100644 --- a/security/etc-motd-access/etc-motd-access.cf +++ b/security/etc-motd-access/etc-motd-access.cf @@ -8,7 +8,7 @@ bundle agent etc_motd_access # https://static.open-scap.org/ssg-guides/ssg-rhel7-guide-anssi_nt28_minimal.html { files: - "/etc/motd" -> {"CCE-83737-7", "CCE-83727-8", "CCE-83337-6"} + "/etc/motd" -> { "CCE-83737-7", "CCE-83727-8", "CCE-83337-6" } perms => mog("644", "root", "root"), if => fileexists("$(this.promiser)"); } diff --git a/security/install-aide/install-aide.cf b/security/install-aide/install-aide.cf index 2c3ec47..8871c6e 100644 --- a/security/install-aide/install-aide.cf +++ b/security/install-aide/install-aide.cf @@ -7,16 +7,19 @@ bundle agent install_aide { vars: redhat|suse:: - "pkg_name" slist => { "aide" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "aide" }; + debian:: - "pkg_name" slist => { "aide" }; # name in apt + # Name in apt: + "pkg_name" slist => { "aide" }; packages: - "${pkg_name}" -> { "CCE-27096-7" } - policy => "present", - if => isvariable("pkg_name"); + "${pkg_name}" -> { "CCE-27096-7" } + policy => "present", + if => isvariable("pkg_name"); reports: - "warning: aide package name not known for this platform" - unless => isvariable("pkg_name"); + "warning: aide package name not known for this platform" + unless => isvariable("pkg_name"); } diff --git a/security/inventory-selinux-modules/main.cf b/security/inventory-selinux-modules/main.cf index 84bea63..caad3fb 100644 --- a/security/inventory-selinux-modules/main.cf +++ b/security/inventory-selinux-modules/main.cf @@ -1,58 +1,57 @@ body file control { - namespace => "inventory_selinux"; + namespace => "inventory_selinux"; } bundle agent semodule_list_modules { classes: - "_$(this.namespace)_$(this.bundle)_supported_platform" - if => isexecutable( "$(path[semodule])"); + "_$(this.namespace)_$(this.bundle)_supported_platform" + if => isexecutable("$(path[semodule])"); vars: - "path[semodule]" - string => ifelse( isexecutable("/sbin/semodule"), "/sbin/semodule", - isexecutable("/usr/sbin/semodule"), "/usr/sbin/semodule", - "" ), - meta => { "paths.cf" }; + "path[semodule]" + string => ifelse( + isexecutable("/sbin/semodule"), + "/sbin/semodule", + isexecutable("/usr/sbin/semodule"), + "/usr/sbin/semodule", + "" + ), + meta => { "paths.cf" }; _inventory_selinux_semodule_list_modules_supported_platform:: "hours_cached" string => "1", - if => not( isvariable( hours_cached )); + if => not(isvariable(hours_cached)); "cache_file" string => "$(sys.statedir)/$(this.namespace)_$(this.bundle).txt"; "cache_file_age" - string => filestat( $(cache_file), mtime ), - if => fileexists( "$(cache_file)" ); + string => filestat($(cache_file), mtime), + if => fileexists("$(cache_file)"); # Example $(cache_file) content # 400 cfengine-enterprise pp # 200 container pp # 100 wine pp disabled # 100 wireshark pp + "d" + data => data_readstringarrayidx("$(cache_file)", "", "\s+", inf, inf), + if => fileexists($(cache_file)); - - "d" data => data_readstringarrayidx( "$(cache_file)", - "", - "\s+", - inf, - inf), - if => fileexists( $(cache_file) ); - - "i" slist => getindices( "d" ); + "i" slist => getindices("d"); # Inventory enabled and disabled selinux modules "enabled[$(i)]" string => "$(d[$(i)][1])", - if => strcmp( "$(d[$(i)][3])", "" ), + if => strcmp("$(d[$(i)][3])", ""), meta => { "inventory", "attribute_name=SELinux Modules Enabled" }; "disabled[$(i)]" string => "$(d[$(i)][1])", - if => strcmp( "$(d[$(i)][3])", "disabled" ), + if => strcmp("$(d[$(i)][3])", "disabled"), meta => { "inventory", "attribute_name=SELinux Modules Disabled" }; files: @@ -61,14 +60,17 @@ bundle agent semodule_list_modules "$(cache_file)" delete => default:tidy, if => isgreaterthan( - format( "%d", eval( "$(sys.systime)-$(cache_file_age)" )), # now minus mtime of cache file - format( "%d", eval( "$(hours_cached)*60*60" ))); # cache minutes + # now minus mtime of cache file: + format("%d", eval("$(sys.systime)-$(cache_file_age)")), + # cache minutes: + format("%d", eval("$(hours_cached)*60*60")) + ); + commands: _inventory_selinux_semodule_list_modules_supported_platform:: "/sbin/semodule" - arglist => { "--list-modules=full", - ">", "$(cache_file)" }, - contain => default:in_shell, # Required for redirection - if => not( fileexists( $(cache_file) )); - + arglist => { "--list-modules=full", ">", "$(cache_file)" }, + # Required for redirection: + contain => default:in_shell, + if => not(fileexists($(cache_file))); } diff --git a/security/inventory-unshadowed-users/policy/main.cf b/security/inventory-unshadowed-users/policy/main.cf index ddbfe2a..c1949e2 100644 --- a/security/inventory-unshadowed-users/policy/main.cf +++ b/security/inventory-unshadowed-users/policy/main.cf @@ -1,6 +1,6 @@ body file control { - namespace => "inventory_unshadowed_users"; + namespace => "inventory_unshadowed_users"; } bundle agent main @@ -11,7 +11,15 @@ bundle agent main linux:: "inventory[$(default:parsed_etc_passwd_shadow.all_local_users)]" string => "$(default:parsed_etc_passwd_shadow.all_local_users)", - if => not( strcmp("x", "$(default:parsed_etc_passwd_shadow._passwd_passwd[$(default:parsed_etc_passwd_shadow.all_local_users)])")), - meta => { "inventory", "attribute_name=Local users not using shadowed password" }, + if => not( + strcmp( + "x", + "$(default:parsed_etc_passwd_shadow._passwd_passwd[$(default:parsed_etc_passwd_shadow.all_local_users)])" + ) + ), + meta => { + "inventory", + "attribute_name=Local users not using shadowed password", + }, comment => "Inventory of local user who is not using a shadowed password (lacks 'x' in second field of '/etc/passwd')."; } diff --git a/security/maintainers-in-motd/maintainers-in-motd.cf b/security/maintainers-in-motd/maintainers-in-motd.cf index eae8a07..a43815b 100644 --- a/security/maintainers-in-motd/maintainers-in-motd.cf +++ b/security/maintainers-in-motd/maintainers-in-motd.cf @@ -2,17 +2,37 @@ bundle agent maintainers_in_motd { classes: linux:: - "has_maintainer" or => { - isvariable("data:variables.maintainer"), - isvariable("data:variables.maintainer_email") - }; + "has_maintainer" + or => { + isvariable("data:variables.maintainer"), + isvariable("data:variables.maintainer_email"), + }; vars: has_maintainer:: - "maintainer" string => ifelse(isvariable("data:variables.maintainer"),"${data:variables.maintainer}",""); - "maintainer_email" string => ifelse(isvariable("data:variables.maintainer_email"),"(${data:variables.maintainer_email})", "(email missing)"); - "purpose" string => ifelse(isvariable("data:variables.purpose"),"${data:variables.purpose}", "unspecified"); - "message" string => "::: use this machine for ${purpose}, contact ${maintainer}${maintainer_email} with any questions/issues. :::"; + "maintainer" + string => ifelse( + isvariable("data:variables.maintainer"), + "${data:variables.maintainer}", + "" + ); + + "maintainer_email" + string => ifelse( + isvariable("data:variables.maintainer_email"), + "(${data:variables.maintainer_email})", + "(email missing)" + ); + + "purpose" + string => ifelse( + isvariable("data:variables.purpose"), + "${data:variables.purpose}", + "unspecified" + ); + + "message" + string => "::: use this machine for ${purpose}, contact ${maintainer}${maintainer_email} with any questions/issues. :::"; files: has_maintainer:: diff --git a/security/uninstall-apache/uninstall-apache.cf b/security/uninstall-apache/uninstall-apache.cf index 5a9a1f3..ed55213 100644 --- a/security/uninstall-apache/uninstall-apache.cf +++ b/security/uninstall-apache/uninstall-apache.cf @@ -7,18 +7,21 @@ bundle agent uninstall_apache { vars: redhat|suse:: - "pkg_name" slist => { "httpd" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "httpd" }; + debian:: - "pkg_name" slist => { "apache2" }; # name in apt + # Name in apt: + "pkg_name" slist => { "apache2" }; classes: - "apache_allowed" - or => { - "hardening_apache_allowed", - "data:hardening_apache_allowed", - "exception_uninstall_apache", - "data:exception_uninstall_apache", - }; + "apache_allowed" + or => { + "hardening_apache_allowed", + "data:hardening_apache_allowed", + "exception_uninstall_apache", + "data:exception_uninstall_apache", + }; packages: !apache_allowed:: diff --git a/security/uninstall-bind/uninstall-bind.cf b/security/uninstall-bind/uninstall-bind.cf index 427f0ee..7ee38e4 100644 --- a/security/uninstall-bind/uninstall-bind.cf +++ b/security/uninstall-bind/uninstall-bind.cf @@ -7,18 +7,21 @@ bundle agent uninstall_bind { vars: redhat|suse:: - "pkg_name" slist => { "bind" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "bind" }; + debian:: - "pkg_name" slist => { "bind", "bind9" }; # name in apt + # Name in apt: + "pkg_name" slist => { "bind", "bind9" }; classes: - "bind_allowed" - or => { - "hardening_bind_allowed", - "data:hardening_bind_allowed", - "exception_uninstall_bind", - "data:exception_uninstall_bind", - }; + "bind_allowed" + or => { + "hardening_bind_allowed", + "data:hardening_bind_allowed", + "exception_uninstall_bind", + "data:exception_uninstall_bind", + }; packages: !bind_allowed:: diff --git a/security/uninstall-dhcp/uninstall-dhcp.cf b/security/uninstall-dhcp/uninstall-dhcp.cf index de50b0a..76a13c1 100644 --- a/security/uninstall-dhcp/uninstall-dhcp.cf +++ b/security/uninstall-dhcp/uninstall-dhcp.cf @@ -7,18 +7,21 @@ bundle agent uninstall_dhcp { vars: redhat|suse:: - "pkg_name" slist => { "dhcp" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "dhcp" }; + debian:: - "pkg_name" slist => { "isc-dhcp-server" }; # name in apt + # Name in apt: + "pkg_name" slist => { "isc-dhcp-server" }; classes: - "dhcp_allowed" - or => { - "hardening_dhcp_allowed", - "data:hardening_dhcp_allowed", - "exception_uninstall_dhcp", - "data:exception_uninstall_dhcp", - }; + "dhcp_allowed" + or => { + "hardening_dhcp_allowed", + "data:hardening_dhcp_allowed", + "exception_uninstall_dhcp", + "data:exception_uninstall_dhcp", + }; packages: !dhcp_allowed:: diff --git a/security/uninstall-dovecot/uninstall-dovecot.cf b/security/uninstall-dovecot/uninstall-dovecot.cf index 34e3129..5e5d88a 100644 --- a/security/uninstall-dovecot/uninstall-dovecot.cf +++ b/security/uninstall-dovecot/uninstall-dovecot.cf @@ -7,18 +7,21 @@ bundle agent uninstall_dovecot { vars: redhat|suse:: - "pkg_name" slist => { "dovecot" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "dovecot" }; + debian:: - "pkg_name" slist => { "dovecot-core" }; # name in apt + # Name in apt: + "pkg_name" slist => { "dovecot-core" }; classes: - "dovecot_allowed" - or => { - "hardening_dovecot_allowed", - "data:hardening_dovecot_allowed", - "exception_uninstall_dovecot", - "data:exception_uninstall_dovecot", - }; + "dovecot_allowed" + or => { + "hardening_dovecot_allowed", + "data:hardening_dovecot_allowed", + "exception_uninstall_dovecot", + "data:exception_uninstall_dovecot", + }; packages: !dovecot_allowed:: diff --git a/security/uninstall-packages/main.cf b/security/uninstall-packages/main.cf index cced8d5..83d8d7d 100644 --- a/security/uninstall-packages/main.cf +++ b/security/uninstall-packages/main.cf @@ -6,8 +6,7 @@ body file control bundle agent uninstall_packages { vars: - "i" - slist => getindices(package_names); + "i" slist => getindices(package_names); packages: "$(package_names[$(i)][name])" diff --git a/security/uninstall-rsh-server/uninstall-rsh-server.cf b/security/uninstall-rsh-server/uninstall-rsh-server.cf index b43c04c..d4d6598 100644 --- a/security/uninstall-rsh-server/uninstall-rsh-server.cf +++ b/security/uninstall-rsh-server/uninstall-rsh-server.cf @@ -7,18 +7,21 @@ bundle agent uninstall_rsh_server { vars: redhat|suse:: - "pkg_name" slist => { "rsh-server" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "rsh-server" }; + debian:: - "pkg_name" slist => { "rsh-server" }; # name in apt + # Name in apt: + "pkg_name" slist => { "rsh-server" }; classes: - "rsh_server_allowed" - or => { - "hardening_rsh_server_allowed", - "data:hardening_rsh_server_allowed", - "exception_uninstall_rsh_server", - "data:exception_uninstall_rsh_server", - }; + "rsh_server_allowed" + or => { + "hardening_rsh_server_allowed", + "data:hardening_rsh_server_allowed", + "exception_uninstall_rsh_server", + "data:exception_uninstall_rsh_server", + }; packages: !rsh_server_allowed:: diff --git a/security/uninstall-samba/uninstall-samba.cf b/security/uninstall-samba/uninstall-samba.cf index c8e3aa4..62579d3 100644 --- a/security/uninstall-samba/uninstall-samba.cf +++ b/security/uninstall-samba/uninstall-samba.cf @@ -7,18 +7,21 @@ bundle agent uninstall_samba { vars: redhat|suse:: - "pkg_name" slist => { "samba" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "samba" }; + debian:: - "pkg_name" slist => { "samba" }; # name in apt + # Name in apt: + "pkg_name" slist => { "samba" }; classes: - "samba_allowed" - or => { - "hardening_samba_allowed", - "data:hardening_samba_allowed", - "exception_uninstall_samba", - "data:exception_uninstall_samba", - }; + "samba_allowed" + or => { + "hardening_samba_allowed", + "data:hardening_samba_allowed", + "exception_uninstall_samba", + "data:exception_uninstall_samba", + }; packages: !samba_allowed:: diff --git a/security/uninstall-squid/uninstall-squid.cf b/security/uninstall-squid/uninstall-squid.cf index 7a5b2f8..124877d 100644 --- a/security/uninstall-squid/uninstall-squid.cf +++ b/security/uninstall-squid/uninstall-squid.cf @@ -7,18 +7,21 @@ bundle agent uninstall_squid { vars: redhat|suse:: - "pkg_name" slist => { "squid" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "squid" }; + debian:: - "pkg_name" slist => { "squid" }; # name in apt + # Name in apt: + "pkg_name" slist => { "squid" }; classes: - "squid_allowed" - or => { - "hardening_squid_allowed", - "data:hardening_squid_allowed", - "exception_uninstall_squid", - "data:exception_uninstall_squid", - }; + "squid_allowed" + or => { + "hardening_squid_allowed", + "data:hardening_squid_allowed", + "exception_uninstall_squid", + "data:exception_uninstall_squid", + }; packages: !squid_allowed:: diff --git a/security/uninstall-talk/uninstall-talk.cf b/security/uninstall-talk/uninstall-talk.cf index 71c9b37..1d6f94c 100644 --- a/security/uninstall-talk/uninstall-talk.cf +++ b/security/uninstall-talk/uninstall-talk.cf @@ -7,18 +7,21 @@ bundle agent uninstall_talk { vars: redhat|suse:: - "pkg_name" slist => { "talk", "talk-server" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "talk", "talk-server" }; + debian:: - "pkg_name" slist => { "talk", "talkd" }; # name in apt + # Name in apt: + "pkg_name" slist => { "talk", "talkd" }; classes: - "talk_allowed" - or => { - "hardening_talk_allowed", - "data:hardening_talk_allowed", - "exception_uninstall_talk", - "data:exception_uninstall_talk", - }; + "talk_allowed" + or => { + "hardening_talk_allowed", + "data:hardening_talk_allowed", + "exception_uninstall_talk", + "data:exception_uninstall_talk", + }; packages: !talk_allowed:: diff --git a/security/uninstall-xinetd/uninstall-xinetd.cf b/security/uninstall-xinetd/uninstall-xinetd.cf index 285a9eb..5e8d653 100644 --- a/security/uninstall-xinetd/uninstall-xinetd.cf +++ b/security/uninstall-xinetd/uninstall-xinetd.cf @@ -7,18 +7,21 @@ bundle agent uninstall_xinetd { vars: redhat|suse:: - "pkg_name" slist => { "xinetd" }; # Name in yum + # Name in yum: + "pkg_name" slist => { "xinetd" }; + debian:: - "pkg_name" slist => { "xinetd" }; # name in apt + # Name in apt: + "pkg_name" slist => { "xinetd" }; classes: - "xinetd_allowed" - or => { - "hardening_xinetd_allowed", - "data:hardening_xinetd_allowed", - "exception_uninstall_xinetd", - "data:exception_uninstall_xinetd", - }; + "xinetd_allowed" + or => { + "hardening_xinetd_allowed", + "data:hardening_xinetd_allowed", + "exception_uninstall_xinetd", + "data:exception_uninstall_xinetd", + }; packages: !xinetd_allowed:: diff --git a/software/windows/windows-openssh-server.cf b/software/windows/windows-openssh-server.cf index 25f8f87..6a15fe1 100644 --- a/software/windows/windows-openssh-server.cf +++ b/software/windows/windows-openssh-server.cf @@ -10,10 +10,10 @@ bundle agent windows_openssh_server_installed methods: windows:: "Add OpenSSH.Server Capability" - # NOTE: this version "0.0.1.0" is not the actual version but rather a static number that is mysterious to me. - # the actual installed version will be the "latest" - usebundle => windows_capability_installed("OpenSSH.Server~~~~0.0.1.0"), - classes => classes_generic("openssh"); + # NOTE: this version "0.0.1.0" is not the actual version but rather a static number that is mysterious to me. + # the actual installed version will be the "latest" + usebundle => windows_capability_installed("OpenSSH.Server~~~~0.0.1.0"), + classes => classes_generic("openssh"); services: windows.openssh_ok::