diff --git a/.CFVERSION b/.CFVERSION index 0914443131..77a8973e74 100644 --- a/.CFVERSION +++ b/.CFVERSION @@ -1 +1 @@ -3.25.0 +3.24.5 diff --git a/.github/workflows/bootstrap_policy_run_check.yml b/.github/workflows/bootstrap_policy_run_check.yml index c356cfd3ff..ec9ea7bc7b 100644 --- a/.github/workflows/bootstrap_policy_run_check.yml +++ b/.github/workflows/bootstrap_policy_run_check.yml @@ -3,11 +3,29 @@ on: jobs: bootstrap_policy_run_check: + strategy: + fail-fast: false + matrix: + cfengine_version: [ "3.21.8", "3.24.3", "3.27.0", "master" ] + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 with: path: masterfiles + - name: Get Togethers + uses: cfengine/together-javascript-action@main + id: together + with: + myToken: ${{ secrets.GITHUB_TOKEN }} + - name: Checkout Core + if: ${{ steps.together.outputs.core != null }} + uses: actions/checkout@v4 + with: + repository: cfengine/core + path: core + ref: ${{steps.together.outputs.core || github.base_ref || github.ref}} + submodules: recursive - name: Install, bootstrap, policy run - run: masterfiles/ci/docker-bootstrap-policy-run.sh + run: masterfiles/ci/docker-bootstrap-policy-run.sh ${{ matrix.cfengine_version }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91959ceb8d..b143b97367 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: # run this workflow on pull_request activity # this includes opening and pushing more commits pull_request: - branches: [ master, 3.21.x, 3.18.x ] + branches: [ master, 3.24.x, 3.21.x ] jobs: style_check: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab18a66d9c..8182b01d51 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,7 @@ jobs: - name: Prepare Artifacts for Uploading run: tar -zcvf /tmp/workspace.tgz ./ && mv /tmp/workspace.tgz ./ - name: Upload The Workspace as Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: workspace path: workspace.tgz diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 1287c009d5..3a3050975c 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -22,7 +22,7 @@ jobs: ref: ${{steps.together.outputs.core || github.base_ref || github.ref}} submodules: recursive - name: Install dependencies - run: sudo apt-get update -y && sudo apt-get install -y libssl-dev libpam0g-dev liblmdb-dev byacc curl libyaml-dev valgrind + run: sudo apt-get update -y && sudo apt-get install -y libssl-dev libpam0g-dev liblmdb-dev byacc curl libyaml-dev valgrind librsync-dev # - name: Install CFEngine with cf-remote # run: | # pip3 install cf-remote diff --git a/CHANGELOG.md b/CHANGELOG.md index 96ae68cc48..7595c35c12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,900 +1,981 @@ -3.24.0: - - AIX watchdog now handles stale pids (CFE-4335) - - Added ability to configure Mission Portal Apache SSLCACertificateFile via Augments - (ENT-11421) - - Added ability to configure SSLCipherSuite via Augments (ENT-11393) - - Added ability to influence default package manager and inventory via Augments - (CFE-3612) - - Added freebsd package_module and package_inventory since we have pkg packages module available - (CFE-4345) - - Added no_backup_cp_compare copy_from body to stdlib - Like the existing no_backup_cp this copy_from body is used to copy files locally - without making backups but with the additional ability to specify the comparison - used. (ENT-10962) - - Added recommendation for installing gnu parallel on federated reporting superhubs - (ENT-8785) - - Added set_escaped_user_field complementing set_user_field (CFE-4377) - - Added setup-feeder option to distributed cleanup script (ENT-11844) - - Aligned ownership and permission expectations between Mission Portal and MPF - (ENT-11941) - - Changed mission-portal apache restart to graceful to minimize service interruptions - (ENT-11526) - - Federated reporting policy now properly fixes SELinux context of the - ~cftransport/.ssh directory and its contents in a single agent - run. (ENT-11136) - - Fixed comparison that caused control_executor_mailfilter_*_configured to never be set - (CFE-4374) - - Fixed distributed_cleanup policy for feeders and rhel-8 superhubs - (ENT-10960) - - Fixed restoration of Mission Portal application to packaged content when modified - (ENT-10962) - - Freebsd service management now uses one prefixed service commands - (CFE-4323) - - Improved federation policy handling of cftransport selinux configuration - (ENT-10959) - - Improved instructions and added report to instruct users how to disable recommendations - (ENT-11523) - - Inventory view is now refreshed in cf-reactor instead of through policy - (ENT-11763) - - Made enterprise federated reporting dump interval configurable via Augments - (ENT-10900) - - Policy now manages Mission Portals httpd.conf ownership and permissions - (ENT-11096) - - Refactored AWS IMDS retrieval to support both IMDSv1 and IMDSv2 - (ENT-10988) - - Refactored extraction of home directory from parsing getent output to getuserinfo() - (CFE-4375) - - Removed hour delay between CFEngine Enterprise PostgreSQL recommendation checks - (ENT-11480) - - Squashed common error logged by Apache related to IPv6 (ENT-10646) - - When failing to detect platform, inventory attribute "OS" now - defaults to PRETTY_NAME from os-release as a fallback (CFE-4342) - -3.23.0: - - Added ability to disable plain http for CFEngine Enterprise Mission Portal - (ENT-10411) - - Added ability to enable backup archives during policy update - (ENT-10481) - - Added ability to extend without overriding filename patterns to copy during policy update - (ENT-10480) - - Added bundle to facilitate migration of ignore_interfaces.rx from inputdir to workdir - (ENT-9402) - - Added self upgrade support for Amazon Linux 2 (ENT-10820) - - Added ss to paths for linux (ENT-10413) - - Aligned systemd service templates with core - WantedBy=cfengine3.service was removed from systemd service templates - for individual components. It was un-necessary as cfengine3.service already - wants the individual services. - https://github.com/cfengine/core/pull/5362 - Ticket: (CFE-3982) - - Avoided deleting python symlink when sys.bindir is not /var/cfengine/bin - (CFE-4146) - - Changed default self upgrade target version to be that of Hubs binary version - (ENT-10664) - - Fixed OS inventory for Amazon Linux 2 (ENT-10817) - - Fixed apache listening on port 80 by default (ENT-10672) - - Fixed cfe_autorun_inventory_aws_ec2_metadata_cache file creation - Ticket: (CFE-4221) - - Removed jq dependency and fixed lib/testing.cf tap output (CFE-4245, CFE-4246, CFE-4223) - - Fixed self-upgrade for Debian and Ubuntu aarch64 clients (ENT-10816) - - Guard against /sys/hypervisor/uuid not being readable (ENT-9931) - - Made Mission Portal Apache SSLProtocol configurable via augments - (ENT-10412) - - Made allowconnects and allowallconnects configurable via Augments - (ENT-10212) - - Made lastseenexpireafter in body common control configurable via Augments - (ENT-10414) - - Removed considerations for old versions from bundle agent cfe_autorun_inventory_aws_ec2_metadata_cache - (CFE-4222) - - Stopped filtering $(sys.bindir) from dynamically determined python path - (CFE-4223) - - Fixed recommendation policy execution (ENT-10915) - - Fixed postgresql.conf recommendations (ENT-10916) - - Added rendering of custom mustache templates to $(sys.workdir)/modules (ENT-10793) - - Fixed support for automatically installing semanage on el9 for federated reporting (ENT-10918) - - Improved failure logging during federated reporting schema import (ENT-10789) - - Added default:cfengine_mp_fr_debug_import class for federated reporting import debugging (ENT-10896) - - Made $(sys.policy_hub) always be included in default:def.acl, allowconnects, and allowallconnects unless explicitly disabled - (ENT-10951) - -3.22.0: - - Added inventory for policy version (ENT-9806) - - Added condition to runalerts service to require stamp directory - (ENT-9711) - - Added guards against using regline() in cases where a file may not exist - (ENT-9933) - - Added self upgrade support for Ubuntu 22.04, Debian 11, and EL9 - (ENT-10290) - - Added ssl_request_log to list of hub log files (ENT-10192) - - Added support for Rocky Linux in self upgrade policy (ENT-10335) - - Adjusted dump.sh for multiple runs in between superhub imports - (ENT-10274) - - Aligned module build result with release artifact (ENT-10345) - - Fixed body perms system_owned to account for Windows (ENT-9778) - - Fixed SUSE package_inventory defaults (ENT-10248) - - Improved federated reporting dump concurrency with database - (ENT-10214) - - Made TLS settings for components other than cf-serverd configurable via augments - (ENT-10198) - - Made agentfacility in body agent control configurable via Augments - (ENT-10209) - - Made allowciphers in body server control configurable via Augments - (ENT-10182) - - Made allowtlsversion in body server control configurable via Augments - (ENT-10182) - - Made body maxmaillines in body executor control configurable via Augments - (ENT-9614) - - Made mailsubject, mailfilter_include, and mailfilter_exclude configurable via Augments - (ENT-10210) - - Made package cache refresh for common_knowledge.list_update_ifelapsed configurable - This change makes the number of minutes to wait between package cache updates - for some package_method bodies configurable via augments. - The package_method bodies affected by this include: - - body package_method pip(flags) - - body package_method npm(dir) - - body package_method npm_g - - body package_method brew(user) - - body package_method apt - - body package_method apt_get - - body package_method apt_get_permissive - - body package_method apt_get_release(release) - - body package_method dpkg_version(repo) - - body package_method rpm_version(repo) - - body package_method yum - - body package_method yum_rpm - - body package_method yum_rpm_permissive - - body package_method yum_rpm_enable_repo(repoid) - - body package_method yum_group - - body package_method rpm_filebased(path) - - body package_method ips - - body package_method smartos - - body package_method opencsw - - body package_method emerge - - body package_method pacman - - body package_method zypper - - body package_method generic - Additionally note that the package related bundles use the package_method bodies - mentioned above and are similarly influenced. - - bundle agent package_present(package) - - bundle agent package_latest(package) - - bundle agent package_specific_present(packageorfile, package_version, package_arch) - - bundle agent package_specific_absent(packageorfile, package_version, package_arch) - - bundle agent package_specific_latest(packageorfile, package_version, package_arch), - - bundle agent package_specific(package_name, desired, package_version, package_arch) - (CFE-4178) - - Prevented management of runagent socket users when no users are listed - (ENT-9535) - - Removed specific old CFEngine version package module handling for windows - (ENT-9948) - - Started inventorying currently mounted file system types and mount points - (ENT-8338) - -3.21.0: - - Added inventory for Raspberry Pi and DeviceTree devices (ENT-8628) - - Added policy to enforce proper permissions on Mission Portal ldap directory (ENT-9693) - - Added check to make sure cf-execd is running after attempting self upgrade on Windows - - Added exception for ldap directory perms for settings.ldap.php (ENT-9697) - (ENT-9573) - - Added date to known paths for linux (CFE-4069) - - Added fallback to top-level feeder dump directory (ENT-8936) - - Added self upgrade knowledge for Suse 12, 15 and opensuse leap 15 - (ENT-9209) - - Added self upgrade knowledge for debian 11 (ENT-9210) - - Added ssh in paths.cf so that policy writers can use $(paths.ssh) - (CFE-4037) - - Added support for multiple superhubs per feeder (ENT-8936) - - Amazon Linux now uses --setopt-exit_on_lock=True in redhat_no_locking_knowledge - (ENT-9057) - - Avoided error stopping apache when no pid file exists (ENT-9108) - - Disabled explicit setting for SSLCompression for Mission Portal Apache. - OpenSSL3 does not provide compression capability, when enabled - Apache will not start. - (ENT-8933) - - Fixed deleting multiple hosts with distributed cleanup utility - (ENT-8979) - - Fixed directory in which windows agents source packages for upgrade - (ENT-9010) - - Fixed services_autorun_inputs working independently from services_autorun - (CFE-4017) - - Fixed set_line_based() for case when edit_defaults.empty_before_use is true - (ENT-5866) - - Made proc inventory configurable via Augments (CFE-4056) - - Make device-tree inventory quieter in containers (ENT-9063) - - Stopped applying locks to masterfiles-stage (ENT-9625) - - Stopped loading several Apache modules on Enterprise Hubs by default: - mod_auth_basic, mod_authz_host, mod_authz_owner, mod_dbd, - mod_authn_file, mod_authz_dbm (ENT-8607, ENT-8602, ENT-8706, - ENT-8609, ENT-9072, ENT-8605) - - Updated filename conventions for AIX and Solaris packages (ENT-9095) - - Fixed detection of location for httpd.pid (ENT-9603) - - Added policy to manage permissions for php/runalerts-stamp (ENT-9703) - - Ensured manual edits to httpd.conf are reverted (ENT-9686) - -3.20.0: - - Renamed bundle agent main to bundle agent mpf_main (CFE-3947) - - Added prelink to paths.cf - - Added Enterprise Hub postgresql.conf to files monitored for diffs by default - (ENT-8618) - - Added PostgreSQL tunables for Federated Reporting (ENT-8617) - - Added lib/templates to packaged assets (ENT-8533) - - Added policy to patch apachectl for more robust stopping on Enterprise Hubs - (ENT-8823) - - Added policy update exclusion for directories named .no-distrib - (ENT-8079) - - Added support for 'option' option in pkg module (CFE-3568) - - Added support for Amazon Linux in standalone self upgrade (ENT-8274) - - Added support for downloading windows packages as part of self upgrade - (ENT-8283) - - Adjusted MPF to handle rxdirs default from true to false (CFE-951) - - 755 perms on hub htdocs dir are now enforced (ENT-8212) - - Proper owner and perms on docroot are now enforced(ENT-8280) - - Prevented def.dir_masterfiles/.no-distrib from being copied - (ENT-8079) - - Cleaned up policy related to versions prior to 3.12 (CFE-3920) - - Removed policy deprecated by sys.os_release (CFE-3933) - - Updated bundle names and wording to reflect current tooling - (CFE-3921) - - Enabled setting environment attribute in body agent control via augments - (CFE-3925) - - Fixed inclusion of distributed cleanup python files during install - (ENT-8393) - - Fixed inventory for OS on Rocky Linux (ENT-8292) - - Fixed promise status from package upgrade when architecture specified in promise - (CFE-3568) - - Made body classes u_kept_successful_command_results inherit_from u_results - (CFE-3917) - - Made CMDB update ignore locks (ENT-8847) - - Updating host-specific CMDB data files now happens asynchronously - (ENT-7357) - - Fixed issue with apt_get package module on Ubuntu 22 (CFE-3976) - - Fixed parsing of options attribute and added repo alias for repository option in pkg module - (CFE-3568) - - Fixed pkg module parsing input when values include equals (=) - (CFE-3568) - - Warn about missing dependencies for Distributed Cleanup utility - (ENT-8832) - - Fixed AIX watchdog default threshold for number of cf-execd processes - (CFE-3915) - - Stopped lowercasing software inventory on Windows (ENT-8424) - - Fixed windows unattended self upgrade on Windows 2008 (ENT-8066) - - Invalid feeder dump files are now skipped during import (ENT-8229) - - Fixed FR clean bundle when off state (ENT-7969) - - Fixed psql not found while FR import (ENT-8353) - - Now clean_when_off FR bundle is only run when needed (ENT-8294) - -3.19.0: - - Added interpreter attribute to standalone self upgrade package_module bodies - (CFE-3703, ENT-5752) - - Added almalinux as a know derivative of rhel (ENT-7644) - - Added class to prevent hub from seeding binary packages for use in self upgrade - (ENT-7544) - - Added cleanup of database and status semaphore when federation target_state is off - (ENT-7233) - - Added custom promise python library - - Added distributed_cleanup utility for Federated Reporting (ENT-7215) - - Added fallback logic for determining installed software version on Windows - (ENT-7501) - - Added lsmod to well known paths (CFE-3790) - - Added script to cleanup artifacts after cfbs build (CFE-3781) - - Added self upgrade support for SUSE (ENT-7446) - - Added separate classes for controlling autorun inputs and bundles - The class services_autorun continues to enable both automatic inclusion of .cf - files in services/autorun and the running of bundles tagged with autorun. - This change adds the classes services_autorun_inputs and - services_autorun_bundles for independently enabling addition of .cf files in - services/autorun and automatic execution of bundles tagged with autorun - respectively. (CFE-3715) - - Added support for downloading community packages on hub in preparation for binary upgrades - - Added variable for excluding files from Policy Analyzer (ENT-7684) - - Adjusted badges for 3.18.0 release (ENT-6713) - - Adjusted permissions for Mission Portal public tmp files (ENT-7261) - - Autorun bundles now run regardless of locks - Previously, when the autorun feature was enabled to automatically run bundles - tagged with autorun the bundle actuation was affected by promise locking. The - effect of this is that agent runs that happen close together would skip running - bundles run within the last minute. Now autorun bundles no longer wait for a - lock to expire, they will be actuated each agent execution. Note, promises - within those bundles have their own locks which still apply. (CFE-3795) - - Dropped un-necessary local variable - The use of this local variable triggers a bug that prevents datastate() from - printing. Since the variable is un-necessary, it's been removed and the - parameter is used directly. (CFE-3776) - - Enforced permissions for Postgres log (ENT-7961) - - Fixed package module augments settings usage for pre 3.15.3 binaries - (ENT-7356, ENT-7358) - - Fixed path in permissions and ownership promise for application log dir - (ENT-7731) - - Fixed services_autorun_bundles only case (CFE-3799) - - Fixup zypper package module script to work properly with interpreter attribute - (ENT-7442) - - Gave cfapache group full access to docroot (ENT-8065) - - Insured exported reports from Mission Portal are in the correct location - (ENT-7465) - - Made apache restart more robust (ENT-8045) - - Moved httpd.pid to root of httpd workdir (ENT-7966) - - Physical Memory (MB) inventory now handles dmidecode MB or GB units - (ENT-7714) - - Promised permissions for Mission Portal application and Apache log files - This change ensures that both Mission Portal and Apache log files have - restrictive permissions. Previously this was un-managed. (ENT-7730) - - Reduced scope of report informing of missing systemd service - (CFE-290, ENT-7360) - - Removed build dir from install/dist targets (ENT-7359) - - Removed stale CMDB inventory policy (CFE-3712) - - Set apache umask to 0177 (ENT-7948) - - State changes of systemd services during agent run are now properly registered - (CFE-3753) - - Stopped enforcing permissions of modules in inputs - This change removes explicit enforcement of permissions for modules in inputs. - Instead of explicitly enforcing permissions in inputs, we rely on the default - permissions (600). The previous explicit permissions (755) are un-necessary as - modules are not executed from within the inputs directory and have resulted in - permission flip-flopping in some environments. Permissions on modules in the - modules dir (sys.workdir)/modules are still enforced. (ENT-7733) - - Switched from using package_method generic to default package_module - for windows software inventory (ENT-2589) - - Improved the reliability when detecting a Red Hat system. - Now if the ID field in /etc/os-release is set to rhel, the redhat_pure class - will be defined. - If the variable sys.os_release does not exist, redhat_pure is defined if we have already - defined redhat and we do not find classes for well known derivatives - - rocky, a class defined on Rocky Linux was added to the list of well known derivatives - (ENT-7628) - - Added advisory lock for Federated Reporting operations (ENT-7474) - - controls/cf_serverd.cf no longer specifies explicit - default for bindtointerface and relies on the default - binding to both :: and 0.0.0.0 on IPV6-enabled hosts - (ENT-7362) - - setup-status.json is no longer being repaired over and over on FR feeder hubs - (ENT-7967) - -3.18.0: - - Added .ps1 to list of file patterns considered during policy update - (ENT-4094) - - Added ability to specify additional directories to add autorun policy from - (CFE-3524) - - Added default cf_version_release of 1 when sys var missing (ENT-6219) - - Added description of psql_lock_wait_before_acquisition measurement - (ENT-6841) - - Added inventory of Setgid files and Setgid files that are root owned - (ENT-6793) - - Added inventory of users and hosts allowed to use cf-runagent - (ENT-6666) - - Added measurement of entropy available on linux systems (ENT-6495) - - Added missing packages modules scripts in makefile (ENT-6814) - - Added new interface for controlling users allowed to initiate cf-agent via cf-runagent - (CFE-3544) - - Added policy for permissions on cf-execd sockets on Enterprise Hubs - (ENT-6777) - - Added redirect to remove index.php from Mission Portal's URL - (ENT-6464) - - Added standalone self upgrade capability for Windows agents - (ENT-6219, ENT-6823) - - Added tail & tail_n to standard library (CFE-3558) - - Added vars.mpf_admit_cf_runagent_shell to control admission for cf-runagent requests - (ENT-6673) - - Added verbose logfile for msiexec package module file installs - (ENT-6220, ENT-6824) - - Changed default behavior of policy update to keep inputs in sync with masterfiles - Prior to this change, the default behavior of the MPF was to only ensure that - files in masterfiles were up to date with the files in inputs. Files in inputs - that did not exist in masterfiles were left undisturbed. To enable sync - behavior (a common user expectation) you had to explicitly define - 'cfengine_internal_purge_policies'. Now, if you wish to return to the previous - default behavior, define the class 'cfengine_internal_purge_policies_disabled'. - Ticket: (CFE-3662) - - Changed msiexec package module install logs to be unique for each msi file - (ENT-6824) - - Disabled TLSv1 by default for Mission Portal's web server (ENT-6783) - - Do not apply redirect from index.php to internal APIs (ENT-6464) - - Enabled packages promises using package_module without bundle def - (CFE-3504) - - Fixed ability to define users authorized for using cf-runagent on policy servers - (CFE-3546) - - Fixed alpine apk packages module to parse names properly (CFE-3585) - - Fixed cfengine_mp_fr_handle_duplicate_hostkeys class usage in policy - (ENT-7094) - - Fixed docs describing xdev behavior in depth_search bodies (CFE-3541) - - Fixed loading of platform specific inventory on AIX (CFE-3614) - - Made Enterprise CMDB data update after policy update (ENT-6788) - - Prevent setgid files from causing continual repair related to setuid file inventory - (ENT-6782) - - Removed stale unused copy of u_kept_successful_command body. If you - receive an error about undefined body, alter your policy to use - kept_successful_command instead (CFE-3617) - - Removed unused plugins directory (CFE-3618) - - Renamed python symlink to cfengine-selected-python (CFE-3512) - - Shortened Inventory OS attribute to be more readable (ENT-6536) - - Suppressed inform output from Enterprise Hub database maintenance operations - (ENT-6563) - - Suppressed output from watchdog on AIX to prevent the mail spool from filling up - (CFE-3630) - - Added ability to specify a list of bundles to run before autorun (for classification) (ENT-6603) - - Update policy now moves obstructions (CFE-2984) - - Use VBScript to enumerate installed packages (ENT-4669) - - add /usr/bin/yum to paths.cf for aix (CFE-3615) - - service status on FreeBSD now uses onestatus (CFE-3515) - - Guard again enforcing root ownership for CFEngine files on Windows (ENT-4628) - -3.17.0: - - Added .csv to the list of file extensions considered by default during - policy update (CFE-3425) - - Added ability to extend known paths without modifying vendored policy - (CFE-3426) - - Added apk package module support for alpinelinux (CFE-3451) - - Added bundle edit_line converge_prepend with same behavior as bundle - edit_line converge, but inserting at start of content. (CFE-3483) - - Added inventory for Timezone and GMT Offset (ENT-6161) - - Added inventory for policy servers (ENT-6212) - - Added maintenance policy to update health diagnostics failures table on - enterprise hubs (ENT-6228) - - Added optional handle duplicates step in federated reporting import - (ENT-6035) - - Added replace_uncommented_substrings (ENT-6117) - - Added service states "active" and "inactive" for systemd (ENT-6074) - - Added watchdog for Windows (ENT-5538) - - Adjusted package_module and paths for termux platform (CFE-3288) - - Aligned systemd services behavior for service_policy => "enable|enabled|disable|disabled" - (ENT-6073) - - Changed bundle server access_rules to mpf_default_access_rules - (CFE-3427) - - Cleaned up Mission Portal OS variable (inventory_os.description) on RHEL 5 & 6 - (ENT-6124) - - De-duplicated license headers (ENT-6040) - - Fixed converge edit_line bundle not deleting lines containing marker - (CFE-3482) - - Fixed interpretation of cf-hub --show-license from REPAIRED to KEPT - (ENT-6473) - - Inventory OS variable (inventory_os.description in policy) is now based on os-release - - Made git_stash only stash untracked files when capable (CFE-3383) - - Moved systemd service management to own bundle (CFE-3381) - - Removed delay in refreshing software installed inventory (ENT-6154) - - Removed unnecessary packages promise on SuSE (ENT-5480, ENT-6375) - - Replaced @ignore with useful doc strings (CFE-3378) - -3.16.0: - - /var/cfengine/bin/python symlink creation on SLES was fixed - - Added 'data' shortcut to cf-serverd, defaults to sys.workdir/data - - Added inventory for CFEngine Enterprise License information - (ENT-5089, ENT-5279) - - Added inventory of NFS servers in use (from /proc/mounts, on linux) - (CFE-3259) - - Added inventory of license owner on enterprise hubs (ENT-5337) - - Added paths support for opensuse (CFE-3283) - - Added use of services promise for FR PostgreSQL reconfig in case of - systemd (ENT-5420) - - Added zypper as default package manager for opensuse (CFE-3284) - - Admitted ::1 as a query source on Enterprise hubs (ENT-5531) - - Aligned unattended self upgrade package map with current state - (ENT-6010) - - Always copy modules from masterfiles (CFE-3237) - - Changed DocumentRoot of Mission Portal in httpd.conf to - `/path/to/cfengine/httpd/htdocs/public` (ENT-5372) - - Changed group for state dir files promise to match defaults per OS - (CFE-3362) - - Changed m_inventory dumping behavior to exclude when values is null - (ENT-5562) - - Corrected application/logs path to outside of docroot (ENT-5255) - - Deleted deprecated __PromiseExecutionsLog from process that cleans - log tables (ENT-5170) - - Fixed dmi inventory to prefer sysfs to dmidecode for most variables - for improved performance and to handle CoreOS hosts that don't - have dmidecode. (CFE-3249) - - Fixed permission flipping when policy analyzer is enabled (ENT-5235) - - Fixed runalerts processes promise on non-systemd systems (ENT-5432) - - Fixed selection of standard_services when used from non-default - namespace (ENT-5406) - - Fixed system UUID inventory for certain VMWare VMs where dmidecode - gives UUID bytes in wrong order. (CFE-3249) - - Fixed typo preventing recommendation bundles from running (CFE-3305) - - HA setups no longer have flipping permissions on - /opt/cfengine/notification_scripts - - Improved resilience of cron watchdog for linux (CFE-3258) - - Inventory refresh is no longer part of agent run on the hub - (ENT-4864) - - Made python symlink fall back to platform-python (CFE-3291) - - Made set_variable_values_ini prefer whitespace around = (CFE-3221) - - Modified cftransport cleanup to avoid errors (ENT-5555) - - Moved 'selinux_enabled' class to config bundle and namespace scope it - - Prevented inventory of unresolved variables for diskfree and loadavg - (ENT-5190) - - Release number was added to MPF tarballs (ENT-5429) - - Standard services now considers systemd services in - ActiveState=activating active (CFE-3238) - - Stopped continual repair of ha_enabled semaphore (ENT-4715) - - Stopped disabling disabled systemd unit each run when disabled state - requested (CFE-3367) - - Stopped trying to edit fields in manage_variable_values_ini - (CFE-3372) - - Suppressed useless inform output from /bin/true in ec2 inventory - (ENT-5233) - - Switched from hardcoded path to /bin/true to use paths from stdlib - (ENT-5278) - - The zypper module is now fully compatible with Python 3 (CFE-3364) - - Whitespace is now allowed at the beginning of ini key-values - (CFE-3244) - - apt_get package module now checks package state (CFE-3233) - -3.15.0: - - Added package_module for snap (CFE-2811) - - Fixed pkgsrc in case where multiple Prefix paths are returned for pkg_install (CFE-3152) - - Fixed pkgsrc module on Solaris/NetBSD (CFE-3151) - - Moved zypper package module errors to the cf-agent output (CFE-3154) - - Added new class mpf_enable_cfengine_systemd_component_management to enable - component management on systemd hosts. When defined on systemd hosts policy - will render systemd unit files in /etc/systemd/system for managed services - and that all units are enabled unless explicitly disabled. When this class - is not defined on systemd hosts the policy will not actively mange cfengine - service units (no change from previous behavior) (CFE-2429) - - Fixed detection of service state on FreeBSD (CFE-3167) - - Added known paths for true and false on linux - (ENT-5060) - - Fixed path for restorecon on redhat systems to /sbin/restorecon - - Added usermod to known paths for redhat systems - - Added policy to manage federated reporting with CFEngine Enterprise - - Introduced augments variable `control_hub_query_timeout` to control cf-hub query timeout. - (ENT-3153) - - Added OOTB inventory for IPv6 addresses (sans ::1 loopback) - (ENT-4987) - - Added and transitioned to using master_software_updates shortcut in self upgrade policy - (ENT-4953) - - Added brief descriptions to bodies and bundles in cfe_internal/CFE_cfengine.cf - (CFE-3220) - - Added support for SUSE 11, 12 in standalone self upgrade (ENT-5045, ENT-5152) - - Changed policy triggering cleanup of __lastseenhostlogs to target only - 3.12.x, 3.13.x and 3.14.x. From 3.15.0 on the table is absent. (ENT-5052) - - Fixed agent disabling on systemd systems (CFE-2429, CFE-3416) - - Ensured directory for custom action scripts is present (ENT-5070) - - Excluded Enterprise federation policy parsing on incompatible versions - (CFE-3193) - - Extended watchdog for AIX (ENT-4995) - - Fixed cleanup of future timestamps from status table - (ENT-4331, ENT-4992) - - Fixed re-spawning of cf-execd or cf-monitord after remediating duplicate concurrent processes - (CFE-3150) - - Replaced /var/cfengine with proper $(sys.*) vars (ENT-4800) - - Fixed selection of standard_services when used from non-default namespace (ENT-5406) - -3.15.0b1: - - Added continual checking for policy_server state (CFE-3073) - - Added monitoring for PostgreSQL lock acquisition times (ENT-4753) - - Added support for 'awk' filters in the FR dump-import process (ENT-4839) - - Added support for configuring abortclasses and abortbundleclasses via - augments (ENT-4823) - - Added support for filtering in both dump and import phases of the FR - ETL process (ENT-4839) - - Added support for ordering FR awk and sed scripts (ENT-4839) - - Added support for setting periodic package inventory refresh interval - via augments (CFE-2771) - - Changed FR policy to honor target_state properly (ENT-4874) - - Copy .awk and .sed files from masterfiles to inputs (ENT-4839) - - Fixed Python 3 incompatibility in yum package module - - Fixed synchronization of important configuration files from active to - passive hub (ENT-4944) - - Made keys of all types from feeder hubs trusted on a superhub (ENT-4917) - - Speeded-up FR import process by merging INSERT INTO statements (ENT-4839) - - Suppressed stderr output from lldpctl when using path defined by - def.lldpctl_json (CFE-3109) - - Added SQL to update feeder update timestamp during import (ENT-4776) - - Added ssh_home_t type to cftransport .ssh dir (ENT-4906) - - fix use of _stdlib_path_exists_ in FR transport_user policy - bundle (ENT-4906) - - partitioned __inventory table for federated reporting (ENT-4842) - - psql_wrapper needed full path to psql binary (ENT-4912) - - yum package_module gets updates available from online repos if local - cache fails (CFE-3094) - -3.14.0: - - Fixed isvariable syntax error in update_def.cf (CFE-2953) - - Added path support for setfacl, timedatectl and journalctl (CFE-3013) - - Added trailing slash to access promises expecting directories - (CFE-3024) - - Added scripts and templates for Federated Reporting (ENT-4473) - - rpm python module is no longer required to check zypper version - - Changed cleanup consumer status SQL query (ENT-4365) - - Conditioned use of curl for ec2 metadata cache on curl binary being executable - (CFE-3049) - - Added augments variables to control cf-hub (ENT-4269) - - Prevented DB maintenance tasks on a passive High Availability hub (ENT-4706) - - Repair outcome for starting cf-monitord or cf-execd is no longer suppressed - (CFE-2964) - - Restrictive permissions on hub install log are now enforced (ENT-4506) - - Ensured that asynchronous query API semaphores are writable (ENT-4551) - - Fixed standalone_self_upgrade not triggering because of stale data - (ENT-4317) - - Fixed maintenance policy for promise log cleanup to respect history_length_days - (ENT-4588) - - Improved efficiency and error handling of user specified policy update bundle - - Log version of Enterprise agent outside of state (ENT-4352) - - Added package module for managing windows packages using msiexec (ENT-3719) - - Prevented inventorying un-expanded memory values from cf-monitord (ENT-4522) - - Prevented performance overhead on hubs that don't enable license utilization logging - (ENT-4333) - - Collection status records in the future are now purged (ENT-4362) - - Reduced cost of knowing when setopt is available in yum (CFE-2993) - - runalerts is now restarted if modified (ENT-4273) - - Separated kill signals from restart class to avoid warning (CFE-2974) - - Separated termination and observation promises for cf-monitord - (CFE-2963) - - Set default access promises for directories to only share if directory exists - (CFE-3060) - - Set default value for purge_scheduled_reports_older_than_days - (ENT-4404) - - Added more accurate and descriptive daemon classes - - collect_window in body server control can now be set from augments - (ENT-4283) - - Guarded vars promises in cfe_internal_enterprise_mission_portal_apache - Constrain vars promises in cfe_internal_enterprise_mission_portal_apache - to policy_server.enterprise_edition::, otherwise "cf-promises --show-vars" - includes a dump of the entire datastate from the "data" variable in - cfe_internal_enterprise_mission_portal_apache (line over 100K long). - (CFE-3011) - - redhat_pure is no longer defined on Fedora hosts (CFE-3022) - -3.13.0: - - Add Debian 9 to the self upgrade package map (ENT-4255) - - Add 'system-uuid' to default dmidecode inventory (CFE-2925) - - Add inventory of AWS EC2 linux instances (CFE-2924) - - Add ubuntu 18 to package map for self upgrade (ENT-4118) - - Allow dmidefs inventory to be overridden via augments (CFE-2927) - - Analyze yum return code before parsing its output (CFE-2868) - - Fixed issue when promise to edit file that does not exist caused "promise - not kept" condition (ENT-3965) - - Avoid trying to read /proc/meminfo when it doesn't exist (CFE-2922) - - Avoid use of $(version) for package_version in legacy implementation - (ENT-3963) - - Cleanup old report data relative to the most recent changetimestamp - (ENT-4807) - - Clear `__lastseenhostslogs` every 5 minutes. (ENT-3550) - - Configure Enterprise hub pull collection schedule via augments - (ENT-3834) - - Configure agent_expireafter from augments (ENT-4308) - - Create desired version tracking data when necessary (ENT-3937) - - Cron based watchdog for cf-execd on AIX (ENT-3963) - - Detect systemd service enablement for non native services (CFE-2932) - - Document how def.acl is used and how to configure it (CFE-2861) - - Fix augments control state paths to work on windows (ENT-3839) - - Fix package_latest detecting larger version in some cases (CFE-1743) - - Fix standalone self upgrade when path contains spaces (ENT-4117) - - Fix unattended self upgrade on AIX (ENT-3972) - - Fix services starting on windows (ENT-3883) - - Improve performance of enterprise license utilization logging - - Inventory Memory on HPUX (ENT-4188) - - Inventory Physical Memory MB when dmidecode is found (CFE-2896) - - Inventory Setuid Files (ENT-4158) - - Inventory memory on Windows (ENT-4187) - - Make recommendations about postgresql.conf (ENT-3958) - - Only consider files that exist for rotation (ENT-3946) - - Prevent noise when a service that should be disabled is missing. - (CFE-2690) - - Prevent standalone self upgrade from triggering un-necessarily - (ENT-4092) - - Remove Design Center related policies - Design center never left beta and has been deprecated. Supporting policies have - been removed. If you wish to continue using design center sketches you must - incorporate them into inputs and the bundlesequence manually. - (ENT-4050) - - Remove unicode characters (ENT-3823) - - Remove templates for deprecated components (ENT-3781) - - Remove un-necessary agent run during self upgrade (ENT-4116) - - Slackware package module support (CFE-2827) - - Specify scope => "namespace" when using persistent classes (CFE-2860) - - Store the epoch of packages in cache db with zypper - - Sync cf-runalerts override unit template with package (ENT-3923) - - Update policy can now skip local copy optimization on policy servers - (CFE-2932) - - Updated yum package module to take arbitrary options (ENT-4177) - - Use default for package arch on aix (ENT-3963) - - Use rpmvercmp for version comparison on AIX (ENT-3963) - - Users allowed to request execution via cf-runagent can be configured - (ENT-4054) - - apt_get package module includes held packages when listing updates - (CFE-2855) - -3.12.0b1: - - Avoid executing self upgrade policy unnecessarily (ENT-3592) - - Add amazon_linux class to yum package module - - Introduce ability to set policy update bundle via augments (CFE-2687) - - Localize delete tidy in ha update policy (ENT-3659) - - Improve context notifying user of missing policy update bundle - (ENT-3624) - - Configure ignore_missing_inputs and ignore_missing_bundles via augments - (CFE-2773) - - Change class identifying runagent initiated executions from cfruncommand to cf_runagent_initiated - - Support enablerepo and disablerepo options in yum package_module - (CFE-2806) - - Fix cf-runagent during 3.7.x -> 3.10.x migration - (CFE-2776, CFE-2781, CFE-2782) - - Makes it possible to tune policy master_location via augments in update policy - (ENT-3692) - - Fix inventory for total memory on AIX (CFE-2797) - - Do not manage redis since it's no longer used (ENT-2797) - - Server control maxconnections can be configured via augments - (CFE-2660) - - Allow configuration of allowlegacyconnects from augments (ENT-3375) - - Fix ability for zypper package_module to downgrade packages - - Splaytime in body executor control can now be configured via augments - (CFE-2699) - - Add maintenance policy to refresh events table on enterprise hubs - (ENT-3537) - - Add apache config for new LDAP API (ENT-3265) - - update.cf bundlesequence can be configured via augments (CFE-2521) - - Update policy inputs can be extended via augments (CFE-2702) - - Add oracle linux support to standalone self upgrade - - Add bundle to track component variables to restart when necessary - (CFE-2326) - - Retention of files found in log directories can now be configured via augments - (CFE-2539) - - Allow multiple sections in insert_ini_section (CFE-2721) - - Add lines_present edit_lines bundle - - Schedule in body executor control can now be configured via augments - (CFE-2508) - - Include scheduled report assets in self maintenance (ENT-3558) - - Remove unused body action aggregator and body file_select folder - - Remove unused body process_count check_process - - Prevent yum from locking in package_methods when possible - (CFE-2759) - - Render variables tagged for inventory from agent host_info_report - (CFE-2750) - - Make apt_get package module work with repositories containing spaces in the label - (ENT-3438) - - Allow hubs to collect from themselves over loopback (ENT-3329) - - Log file max size and rotation limits can now be configured via augments - (CFE-2538) - - Change: Do not silence Enterprise hub maintenance - - Ensure HA standby hubs have am_policy_hub state marker (ENT-3328) - - Add support for 32bit rpms in standalone self upgrade (ENT-3377) - - Add enterprise maintenance bundles to host info report (ENT-3537) - - Removed unnecessary promises for OOTB package inventory - - Add external watchdog support for stuck cf-execd (ENT-3251) - - Be less noisy when a promised service is not found (CFE-2690) - - Ignore empty options in apt_get module (CFE-2685) - - Add postgres.log to enterprise log file rotation (ENT-3191) - - Removed unnecessary support for including 3.6 controls - - Fix systemctl path detection - - Policy Release Id is now inventoried by default (CFE-2097) - - Fix to frequent logging of enterprise license utilization (ENT-3390) - - Maintain access to exported CSV reports in older versions (ENT-3572) - - cf-execd service override template now only kills cf-execd on stop - (ENT-3395) - - Fix self upgrade for hosts older than 3.7.4 (ENT-3368) - - Avoid self upgrade from triggering during bootstrap (ENT-3394) - - Add json templates for rendering serial and multiline data (CFE-2713) - - Removed unused libraries and controls - - Fixed an error in the file_make_mustache_*, incorrect variable name used - (CFE-2714) - -3.11.0: - - Rename enable_client_initiated_reporting to client_initiated_reporting_enabled - - Directories for ubuntu 16 and centos 7 should exist in master_software_updates - (ENT-3136) - - Fix: Automatic client upgrades for deb hosts - - Add AIX OOTB oslevel inventory (ENT-3117) - - Disable package inventory via modules on redhat like systems with unsupported python versions - (CFE-2602) - - Make stock policy update more resilient (CFE-2587) - - Configure networks allowed to initiate report collection (client initiated reporting) via augments (#910) - (CFE-2624) - - apt_get package module: Fix bug which prevented updates - from being picked up if there was more than one source listed in the - 'apt upgrade' output, without a comma in between (CFE-2605) - - Enable specification of monitoring_include via augments (CFE-2505) - - Configure call_collect_interval from augments (enable_client_initiated_reporting) (#905) - (CFE-2623) - - Add templates shortcut (CFE-2582) - - Behaviour change: when used with CFEngine 3.10.0 or greater, - bundles set_config_values() and set_line_based() are appending a - trailing space when inserting a configuration option with empty value - (CFE-2466) - - Add default report collection exclusion based on promise handle - (ENT-3061) - - Fix ability to select INI region with metachars (CFE-2519) - - Change: Verify transferred files during policy update - - Change select_region INI_section to match end of section or end of file - (CFE-2519) - - Add class to enable post transfer verification during policy updates - - Add: prunetree bundle to stdlib - The prunetree bundle allows you to delete files and directories up to a - specified depth older than a specified number of days - - Do not symlink agents to /usr/local/bin on CoreOS (ENT-3047) - - Add: Ability to set default_repository via augments - - Enable settig def.max_client_history_size via augments (CFE-2560) - - Change self upgrade now uses standalone policy (ENT-3155) - - Fix apt_get package module incorrectly using interactive mode - - Add ability to append to bundlesequnece with def.json (CFE-2460) - - Enable paths to POSIX tools by default instead of native tools - - Remove bundle agent cfe_internal_bins (CFE-2636) - - Include previous_state and untracked reports when client clear a buildup of unreported data - (ENT-3161) - - Fix command to restart apache on config change (ENT-3134) - - cf-serverd listens on ipv4 and ipv6 by default (CFE-528) - - FixesMake apt_get module compatible with Ubuntu 16.04 (CFE-2445) - - Fix rare bug that would sometimes prevent redis-server from launching - - Add oslevel to well known paths (ENT-3121) - - Add policy to track CFEngine Enterprise license utilization - (ENT-3186) - - Ensure MP SSL Cert is readable (ENT-3050) - -3.10.0: - - Add: Classes body tailored for use with diff - - Change: Session Cookies use HTTPOnly and secure attributes (ENT-2781) - - Change: Verify transferred files during policy update - - Add: Inventory for system product name (model) (ENT-2780) - - Add: Ensure appropriate permissions for SSL files (ENT-760) - - Fix rare bug that would sometimes prevent redis-server from launching. - - Change: Enable strict transport security - - Add: Definition of from_cfexecd for cf-execd initiated runs - (CFE-2386) - - Add testing jUnit and TAP bundles and include them in stdlib.cf - - Change: Rename duplicate bodies in ha_update.cf (ENT-2753) - - Change: Disable RC4 Cipher for ssl in Mission Portal - - Pass package promise options to underlying apt-get call (#802) - (CFE-2468) - - Change: Enable agent component management policy on systemd hosts - (CFE-2429) - - Add: Enterprise appliaction log dir to rotation - - Change: re-enable hub process maintenance - - Add: edit_line contains_literal_string to stdlib - - Fix: Services starting or stopping unnecessarily (CFE-2421) - - Allow specifying agent maxconnections via def.json (CFE-2461) - - Change: Disable http TRACE method - - Change: Reduce Enteprise webserver info - - Change: cronjob bundle tolerates different spacing - - Fix: CFEngine choking on standard services (CFE-2806) - - Change select_region INI_section to match end of section or end of file - (CFE-2519) - - Fix ability to manage INI sections with metachars for - manage_variable_values_ini and set_variable_values_ini (CFE-2519) - - Fix apt_get package module incorrectly using interactive mode. - - Add ability to append to bundlesequnece with def.json (CFE-2460) - - Behaviour change: when used with CFEngine 3.10.0 or greater, - bundles set_config_values() and set_line_based() are appending a - trailing space when inserting a configuration option with empty value. - (CFE-2466) - -3.7.0: - - Support for user specified overriding of framework defaults without modifying - policy supplied by the framework itself (see example_def.json) - - Support for def.json class augmentation in update policy - - Run vacuum operation on PostgreSQL every night as a part of maintenance. - - Add measure_promise_time action body to lib (3.5, 3.6, 3.7, 3.8) - - New negative class guard `cfengine_internal_disable_agent_email` so that - agent email can be easily disabled by augmenting def.json - - Relocate def.cf to controls/VER/ - - Relocate update_def to controls/VER - - Relocate all controls to controls/VER - - Only load cf_hub and reports.cf on CFEngine Enterprise installs - - Relocate acls related to report collection from bundle server access_rules - to controls/VER/reports.cf into bundle server report_access_rules - - Re-organize cfe_internal splitting core from enterprise specific policies - and loading the appropriate inputs only when necessary - - Moved update directory into cfe_internal as it is not generally intended to - be modified - - services/autorun.cf moved to lib/VER/ as it is not generally intended to be - modified - - To improve predictibility autorun bundles are activated in lexicographical - order - - Relocate services/file_change.cf to cfe_internal/enterprise. This policy is - most useful for a good OOTB experience with CFEngine Enterprise Mission - Portal. - - Relocate service_catalogue from promises.cf to services/main.cf. It is - intended to be a user entry. This name change correlates with the main - bundle being activated by default if there is no bundlesequence specified. - - Reduce benchmarks sample history to 1 day. - - Update policy no longer generates a keypair if one is not found. (Redmine: #7167) - - Relocate cfe_internal_postgresql_maintenance bundle to lib/VER/ - - Set postgresql_monitoring_maintenance only for versions 3.6.0 and 3.6.1 - - Move hub specific bundles from lib/VER/cfe_internal.cf into lib/VER/cfe_internal_hub.cf - and load them only if policy_server policy if set. - - Re-organize lib/VER/stdlib.cf from lists into classic array for use with getvalues - - inform_mode classes changed to DEBUG|DEBUG_$(this.bundle):: (Redmine: #7191) - - Enabled limit_robot_agents in order to work around multiple cf-execd - processes after upgrade. (Redmine #7185) - - Remove Diff reporting on /etc/shadow (Enterprise) - - Update policy from promise.cf inputs. There is no reason to include the - update policy into promises.cf, update.cf is the entry for the update policy - - _not_repaired outcome from classes_generic and scoped_classes generic (Redmine: # 7022) - - standard_services now restarts the service if it was not already running - when using service_policy => restart with chkconfig (Redmine #7258) - - Fix process_result logic to match the purpose of body process_select - days_older_than (Redmine #3009) +## 3.24.4: + +- Added dnf package module (ENT-11784) +- Added workaround for set_variable_values_ini with missing sections + (CFE-3866) +- Fixed bad regex in packages promise method for pip (ENT-13667) +- Fixed incorrect previous fix for timeout for php processing to allow for longer running API requests (3.24) + (ENT-13291, ENT-13625) +- Inhibit management of share config.php file when mpf_disable_mission_portal_docroot_sync_from_share_gui is defined + (ENT-12658) +- Made system_log_level configurable via Augments (CFE-4452) +- Fixed maximum recursion errors in modules_presence for CFEngine versions + unaffected by CFE-4623 (CFE-2852) +- Added dnf_group package module for managing DNF package groups (CFE-2852) +- standard_services bundle no longer invokes `systemctl` with `--global` + with is mutually exclusive from `--system` (CFE-4639) + +## 3.24.3 + +- Fixed cfruncommand for Windows causing "Too many arguments" error (ENT-13530) +- Added dmidecode to well known paths for Red Hat (ENT-12988) +- Added recommendation about nfs server and consistent use of root dot + (ENT-13223) +- Changed NFS Server inventory to report only unique servers + (ENT-13223) +- Fixed duplicate bundlesequence_end when bundlesequence_classification not defined + (CFE-4588) +- Fixed path to lsof on Red Hat 7 and greater (ENT-12987) +- Increased timeout for php processing to allow for longer running API requests + (ENT-13291) +- Made protocol_version configurable via Augments (CFE-4543) +- Prevented nfs server inventory from doing unnecessary extra work + (ENT-13210) +- Removed duplicate well known paths for ls and lsof on opensuse + (ENT-12990) +- Switched to using current process ID to investigate proc filesystem to workaround in-container non-root owned symlinks + (CFE-3429) + +## 3.24.2 + +- Added paths for the dmsetup, fdisk, and lshw commands (ENT-12560) +- Fixed issue loading images from raw.github.com in Mission Portal Build application(ENT-12531) +- Fixed issue with yum package module regarding packages with epoch not + validating (ENT-12538) +- Fixed location of Mission Portal application logs for log_dir cleanup + (ENT-12556) + +## 3.24.1 + +- Added inline docs showing valid values for method (field_operation) in body edit_field quoted_var + (CFE-4426) +- Added support for AIX System Resource Controller services promises + (CFE-4447) +- Added trailing /. to files promises targeting local_software_dir + (ENT-12116) +- Adjusted CSP in httpd.conf to suit ACE javascript editor (ENT-12010) +- Data dumping on Federated Reporting feeders no longer + uses an AWK filter to merge INSERT lines in the dumps +- Fixed failed to open /dev/tty errors when using systemd unit management + (CFE-4445) + +## 3.24.0 + +- AIX watchdog now handles stale pids (CFE-4335) +- Added ability to configure Mission Portal Apache SSLCACertificateFile via Augments + (ENT-11421) +- Added ability to configure SSLCipherSuite via Augments (ENT-11393) +- Added ability to influence default package manager and inventory via Augments + (CFE-3612) +- Added freebsd package_module and package_inventory since we have pkg packages module available + (CFE-4345) +- Added no_backup_cp_compare copy_from body to stdlib + Like the existing no_backup_cp this copy_from body is used to copy files locally + without making backups but with the additional ability to specify the comparison + used. (ENT-10962) +- Added recommendation for installing gnu parallel on federated reporting superhubs + (ENT-8785) +- Added set_escaped_user_field complementing set_user_field (CFE-4377) +- Added setup-feeder option to distributed cleanup script (ENT-11844) +- Aligned ownership and permission expectations between Mission Portal and MPF + (ENT-11941) +- Changed mission-portal apache restart to graceful to minimize service interruptions + (ENT-11526) +- Federated reporting policy now properly fixes SELinux context of the + ~cftransport/.ssh directory and its contents in a single agent + run. (ENT-11136) +- Fixed comparison that caused `control_executor_mailfilter_*_configured` to never be set + (CFE-4374) +- Fixed distributed_cleanup policy for feeders and rhel-8 superhubs + (ENT-10960) +- Fixed restoration of Mission Portal application to packaged content when modified + (ENT-10962) +- Freebsd service management now uses one prefixed service commands + (CFE-4323) +- Improved federation policy handling of cftransport selinux configuration + (ENT-10959) +- Improved instructions and added report to instruct users how to disable recommendations + (ENT-11523) +- Inventory view is now refreshed in cf-reactor instead of through policy + (ENT-11763) +- Made enterprise federated reporting dump interval configurable via Augments + (ENT-10900) +- Policy now manages Mission Portals httpd.conf ownership and permissions + (ENT-11096) +- Refactored AWS IMDS retrieval to support both IMDSv1 and IMDSv2 + (ENT-10988) +- Refactored extraction of home directory from parsing getent output to getuserinfo() + (CFE-4375) +- Removed hour delay between CFEngine Enterprise PostgreSQL recommendation checks + (ENT-11480) +- Squashed common error logged by Apache related to IPv6 (ENT-10646) +- When failing to detect platform, inventory attribute "OS" now + defaults to PRETTY_NAME from os-release as a fallback (CFE-4342) + +## 3.23.0 + +- Added ability to disable plain http for CFEngine Enterprise Mission Portal + (ENT-10411) +- Added ability to enable backup archives during policy update + (ENT-10481) +- Added ability to extend without overriding filename patterns to copy during policy update + (ENT-10480) +- Added bundle to facilitate migration of ignore_interfaces.rx from inputdir to workdir + (ENT-9402) +- Added self upgrade support for Amazon Linux 2 (ENT-10820) +- Added ss to paths for linux (ENT-10413) +- Aligned systemd service templates with core + WantedBy=cfengine3.service was removed from systemd service templates + for individual components. It was un-necessary as cfengine3.service already + wants the individual services. + https://github.com/cfengine/core/pull/5362 + Ticket: (CFE-3982) +- Avoided deleting python symlink when sys.bindir is not /var/cfengine/bin + (CFE-4146) +- Changed default self upgrade target version to be that of Hubs binary version + (ENT-10664) +- Fixed OS inventory for Amazon Linux 2 (ENT-10817) +- Fixed apache listening on port 80 by default (ENT-10672) +- Fixed cfe_autorun_inventory_aws_ec2_metadata_cache file creation + Ticket: (CFE-4221) +- Removed jq dependency and fixed lib/testing.cf tap output (CFE-4245, CFE-4246, CFE-4223) +- Fixed self-upgrade for Debian and Ubuntu aarch64 clients (ENT-10816) +- Guard against /sys/hypervisor/uuid not being readable (ENT-9931) +- Made Mission Portal Apache SSLProtocol configurable via augments + (ENT-10412) +- Made allowconnects and allowallconnects configurable via Augments + (ENT-10212) +- Made lastseenexpireafter in body common control configurable via Augments + (ENT-10414) +- Removed considerations for old versions from bundle agent cfe_autorun_inventory_aws_ec2_metadata_cache + (CFE-4222) +- Stopped filtering $(sys.bindir) from dynamically determined python path + (CFE-4223) +- Fixed recommendation policy execution (ENT-10915) +- Fixed postgresql.conf recommendations (ENT-10916) +- Added rendering of custom mustache templates to $(sys.workdir)/modules (ENT-10793) +- Fixed support for automatically installing semanage on el9 for federated reporting (ENT-10918) +- Improved failure logging during federated reporting schema import (ENT-10789) +- Added default:cfengine_mp_fr_debug_import class for federated reporting import debugging (ENT-10896) +- Made $(sys.policy_hub) always be included in default:def.acl, allowconnects, and allowallconnects unless explicitly disabled + (ENT-10951) + +## 3.22.0 + +- Added inventory for policy version (ENT-9806) +- Added condition to runalerts service to require stamp directory + (ENT-9711) +- Added guards against using regline() in cases where a file may not exist + (ENT-9933) +- Added self upgrade support for Ubuntu 22.04, Debian 11, and EL9 + (ENT-10290) +- Added ssl_request_log to list of hub log files (ENT-10192) +- Added support for Rocky Linux in self upgrade policy (ENT-10335) +- Adjusted dump.sh for multiple runs in between superhub imports + (ENT-10274) +- Aligned module build result with release artifact (ENT-10345) +- Fixed body perms system_owned to account for Windows (ENT-9778) +- Fixed SUSE package_inventory defaults (ENT-10248) +- Improved federated reporting dump concurrency with database + (ENT-10214) +- Made TLS settings for components other than cf-serverd configurable via augments + (ENT-10198) +- Made agentfacility in body agent control configurable via Augments + (ENT-10209) +- Made allowciphers in body server control configurable via Augments + (ENT-10182) +- Made allowtlsversion in body server control configurable via Augments + (ENT-10182) +- Made body maxmaillines in body executor control configurable via Augments + (ENT-9614) +- Made mailsubject, mailfilter_include, and mailfilter_exclude configurable via Augments + (ENT-10210) +- Made package cache refresh for common_knowledge.list_update_ifelapsed configurable + This change makes the number of minutes to wait between package cache updates + for some package_method bodies configurable via augments. + The package_method bodies affected by this include: + - body package_method pip(flags) + - body package_method npm(dir) + - body package_method npm_g + - body package_method brew(user) + - body package_method apt + - body package_method apt_get + - body package_method apt_get_permissive + - body package_method apt_get_release(release) + - body package_method dpkg_version(repo) + - body package_method rpm_version(repo) + - body package_method yum + - body package_method yum_rpm + - body package_method yum_rpm_permissive + - body package_method yum_rpm_enable_repo(repoid) + - body package_method yum_group + - body package_method rpm_filebased(path) + - body package_method ips + - body package_method smartos + - body package_method opencsw + - body package_method emerge + - body package_method pacman + - body package_method zypper + - body package_method generic + + Additionally note that the package related bundles use the package_method bodies + mentioned above and are similarly influenced. + - bundle agent package_present(package) + - bundle agent package_latest(package) + - bundle agent package_specific_present(packageorfile, package_version, package_arch) + - bundle agent package_specific_absent(packageorfile, package_version, package_arch) + - bundle agent package_specific_latest(packageorfile, package_version, package_arch), + - bundle agent package_specific(package_name, desired, package_version, package_arch) + + (CFE-4178) + +- Prevented management of runagent socket users when no users are listed + (ENT-9535) +- Removed specific old CFEngine version package module handling for windows + (ENT-9948) +- Started inventorying currently mounted file system types and mount points + (ENT-8338) + +## 3.21.0 + +- Added inventory for Raspberry Pi and DeviceTree devices (ENT-8628) +- Added policy to enforce proper permissions on Mission Portal ldap directory (ENT-9693) +- Added check to make sure cf-execd is running after attempting self upgrade on Windows +- Added exception for ldap directory perms for settings.ldap.php (ENT-9697) + (ENT-9573) +- Added date to known paths for linux (CFE-4069) +- Added fallback to top-level feeder dump directory (ENT-8936) +- Added self upgrade knowledge for Suse 12, 15 and opensuse leap 15 + (ENT-9209) +- Added self upgrade knowledge for debian 11 (ENT-9210) +- Added ssh in paths.cf so that policy writers can use $(paths.ssh) + (CFE-4037) +- Added support for multiple superhubs per feeder (ENT-8936) +- Amazon Linux now uses --setopt-exit_on_lock=True in redhat_no_locking_knowledge + (ENT-9057) +- Avoided error stopping apache when no pid file exists (ENT-9108) +- Disabled explicit setting for SSLCompression for Mission Portal Apache. + OpenSSL3 does not provide compression capability, when enabled + Apache will not start. + (ENT-8933) +- Fixed deleting multiple hosts with distributed cleanup utility + (ENT-8979) +- Fixed directory in which windows agents source packages for upgrade + (ENT-9010) +- Fixed services_autorun_inputs working independently from services_autorun + (CFE-4017) +- Fixed set_line_based() for case when edit_defaults.empty_before_use is true + (ENT-5866) +- Made proc inventory configurable via Augments (CFE-4056) +- Made device-tree inventory quieter in containers (ENT-9063) +- Stopped applying locks to masterfiles-stage (ENT-9625) +- Stopped loading several Apache modules on Enterprise Hubs by default: + mod_auth_basic, mod_authz_host, mod_authz_owner, mod_dbd, + mod_authn_file, mod_authz_dbm (ENT-8607, ENT-8602, ENT-8706, + ENT-8609, ENT-9072, ENT-8605) +- Updated filename conventions for AIX and Solaris packages (ENT-9095) +- Fixed detection of location for httpd.pid (ENT-9603) +- Added policy to manage permissions for php/runalerts-stamp (ENT-9703) +- Ensured manual edits to httpd.conf are reverted (ENT-9686) + +## 3.20.0 + +- Renamed bundle agent main to bundle agent mpf_main (CFE-3947) +- Added prelink to paths.cf +- Added Enterprise Hub postgresql.conf to files monitored for diffs by default + (ENT-8618) +- Added PostgreSQL tunables for Federated Reporting (ENT-8617) +- Added lib/templates to packaged assets (ENT-8533) +- Added policy to patch apachectl for more robust stopping on Enterprise Hubs + (ENT-8823) +- Added policy update exclusion for directories named .no-distrib + (ENT-8079) +- Added support for `option` option in pkg module (CFE-3568) +- Added support for Amazon Linux in standalone self upgrade (ENT-8274) +- Added support for downloading windows packages as part of self upgrade + (ENT-8283) +- Adjusted MPF to handle rxdirs default from true to false (CFE-951) +- 755 perms on hub htdocs dir are now enforced (ENT-8212) +- Proper owner and perms on docroot are now enforced(ENT-8280) +- Prevented def.dir_masterfiles/.no-distrib from being copied + (ENT-8079) +- Cleaned up policy related to versions prior to 3.12 (CFE-3920) +- Removed policy deprecated by sys.os_release (CFE-3933) +- Updated bundle names and wording to reflect current tooling + (CFE-3921) +- Enabled setting environment attribute in body agent control via augments + (CFE-3925) +- Fixed inclusion of distributed cleanup python files during install + (ENT-8393) +- Fixed inventory for OS on Rocky Linux (ENT-8292) +- Fixed promise status from package upgrade when architecture specified in promise + (CFE-3568) +- Made body classes u_kept_successful_command_results inherit_from u_results + (CFE-3917) +- Made CMDB update ignore locks (ENT-8847) +- Updating host-specific CMDB data files now happens asynchronously + (ENT-7357) +- Fixed issue with apt_get package module on Ubuntu 22 (CFE-3976) +- Fixed parsing of options attribute and added repo alias for repository option in pkg module + (CFE-3568) +- Fixed pkg module parsing input when values include equals (=) + (CFE-3568) +- Warn about missing dependencies for Distributed Cleanup utility + (ENT-8832) +- Fixed AIX watchdog default threshold for number of cf-execd processes + (CFE-3915) +- Stopped lowercasing software inventory on Windows (ENT-8424) +- Fixed windows unattended self upgrade on Windows 2008 (ENT-8066) +- Invalid feeder dump files are now skipped during import (ENT-8229) +- Fixed FR clean bundle when off state (ENT-7969) +- Fixed psql not found while FR import (ENT-8353) +- Now clean_when_off FR bundle is only run when needed (ENT-8294) + +## 3.19.0 + +- Added interpreter attribute to standalone self upgrade package_module bodies + (CFE-3703, ENT-5752) +- Added almalinux as a know derivative of rhel (ENT-7644) +- Added class to prevent hub from seeding binary packages for use in self upgrade + (ENT-7544) +- Added cleanup of database and status semaphore when federation target_state is off + (ENT-7233) +- Added custom promise python library +- Added distributed_cleanup utility for Federated Reporting (ENT-7215) +- Added fallback logic for determining installed software version on Windows + (ENT-7501) +- Added lsmod to well known paths (CFE-3790) +- Added script to cleanup artifacts after cfbs build (CFE-3781) +- Added self upgrade support for SUSE (ENT-7446) +- Added separate classes for controlling autorun inputs and bundles + The class services_autorun continues to enable both automatic inclusion of .cf + files in services/autorun and the running of bundles tagged with autorun. + This change adds the classes services_autorun_inputs and + services_autorun_bundles for independently enabling addition of .cf files in + services/autorun and automatic execution of bundles tagged with autorun + respectively. (CFE-3715) +- Added support for downloading community packages on hub in preparation for binary upgrades +- Added variable for excluding files from Policy Analyzer (ENT-7684) +- Adjusted badges for 3.18.0 release (ENT-6713) +- Adjusted permissions for Mission Portal public tmp files (ENT-7261) +- Autorun bundles now run regardless of locks + Previously, when the autorun feature was enabled to automatically run bundles + tagged with autorun the bundle actuation was affected by promise locking. The + effect of this is that agent runs that happen close together would skip running + bundles run within the last minute. Now autorun bundles no longer wait for a + lock to expire, they will be actuated each agent execution. Note, promises + within those bundles have their own locks which still apply. (CFE-3795) +- Dropped un-necessary local variable + The use of this local variable triggers a bug that prevents datastate() from + printing. Since the variable is un-necessary, it's been removed and the + parameter is used directly. (CFE-3776) +- Enforced permissions for Postgres log (ENT-7961) +- Fixed package module augments settings usage for pre 3.15.3 binaries + (ENT-7356, ENT-7358) +- Fixed path in permissions and ownership promise for application log dir + (ENT-7731) +- Fixed services_autorun_bundles only case (CFE-3799) +- Fixup zypper package module script to work properly with interpreter attribute + (ENT-7442) +- Gave cfapache group full access to docroot (ENT-8065) +- Insured exported reports from Mission Portal are in the correct location + (ENT-7465) +- Made apache restart more robust (ENT-8045) +- Moved httpd.pid to root of httpd workdir (ENT-7966) +- Physical Memory (MB) inventory now handles dmidecode MB or GB units + (ENT-7714) +- Promised permissions for Mission Portal application and Apache log files + This change ensures that both Mission Portal and Apache log files have + restrictive permissions. Previously this was un-managed. (ENT-7730) +- Reduced scope of report informing of missing systemd service + (CFE-290, ENT-7360) +- Removed build dir from install/dist targets (ENT-7359) +- Removed stale CMDB inventory policy (CFE-3712) +- Set apache umask to 0177 (ENT-7948) +- State changes of systemd services during agent run are now properly registered + (CFE-3753) +- Stopped enforcing permissions of modules in inputs + This change removes explicit enforcement of permissions for modules in inputs. + Instead of explicitly enforcing permissions in inputs, we rely on the default + permissions (600). The previous explicit permissions (755) are un-necessary as + modules are not executed from within the inputs directory and have resulted in + permission flip-flopping in some environments. Permissions on modules in the + modules dir (sys.workdir)/modules are still enforced. (ENT-7733) +- Switched from using package_method generic to default package_module + for windows software inventory (ENT-2589) +- Improved the reliability when detecting a Red Hat system. + Now if the ID field in /etc/os-release is set to rhel, the redhat_pure class + will be defined. + If the variable sys.os_release does not exist, redhat_pure is defined if we have already + defined redhat and we do not find classes for well known derivatives +- rocky, a class defined on Rocky Linux was added to the list of well known derivatives + (ENT-7628) +- Added advisory lock for Federated Reporting operations (ENT-7474) +- controls/cf_serverd.cf no longer specifies explicit + default for bindtointerface and relies on the default + binding to both :: and 0.0.0.0 on IPV6-enabled hosts + (ENT-7362) +- setup-status.json is no longer being repaired over and over on FR feeder hubs + (ENT-7967) + +## 3.18.0 + +- Added .ps1 to list of file patterns considered during policy update + (ENT-4094) +- Added ability to specify additional directories to add autorun policy from + (CFE-3524) +- Added default cf_version_release of 1 when sys var missing (ENT-6219) +- Added description of psql_lock_wait_before_acquisition measurement + (ENT-6841) +- Added inventory of Setgid files and Setgid files that are root owned + (ENT-6793) +- Added inventory of users and hosts allowed to use cf-runagent + (ENT-6666) +- Added measurement of entropy available on linux systems (ENT-6495) +- Added missing packages modules scripts in makefile (ENT-6814) +- Added new interface for controlling users allowed to initiate cf-agent via cf-runagent + (CFE-3544) +- Added policy for permissions on cf-execd sockets on Enterprise Hubs + (ENT-6777) +- Added redirect to remove index.php from Mission Portal's URL + (ENT-6464) +- Added standalone self upgrade capability for Windows agents + (ENT-6219, ENT-6823) +- Added tail & tail_n to standard library (CFE-3558) +- Added vars.mpf_admit_cf_runagent_shell to control admission for cf-runagent requests + (ENT-6673) +- Added verbose logfile for msiexec package module file installs + (ENT-6220, ENT-6824) +- Changed default behavior of policy update to keep inputs in sync with masterfiles + Prior to this change, the default behavior of the MPF was to only ensure that + files in masterfiles were up to date with the files in inputs. Files in inputs + that did not exist in masterfiles were left undisturbed. To enable sync + behavior (a common user expectation) you had to explicitly define + `cfengine_internal_purge_policies`. Now, if you wish to return to the previous + default behavior, define the class `cfengine_internal_purge_policies_disabled`. + Ticket: (CFE-3662) +- Changed msiexec package module install logs to be unique for each msi file + (ENT-6824) +- Disabled TLSv1 by default for Mission Portal's web server (ENT-6783) +- Do not apply redirect from index.php to internal APIs (ENT-6464) +- Enabled packages promises using package_module without bundle def + (CFE-3504) +- Fixed ability to define users authorized for using cf-runagent on policy servers + (CFE-3546) +- Fixed alpine apk packages module to parse names properly (CFE-3585) +- Fixed cfengine_mp_fr_handle_duplicate_hostkeys class usage in policy + (ENT-7094) +- Fixed docs describing xdev behavior in depth_search bodies (CFE-3541) +- Fixed loading of platform specific inventory on AIX (CFE-3614) +- Made Enterprise CMDB data update after policy update (ENT-6788) +- Prevent setgid files from causing continual repair related to setuid file inventory + (ENT-6782) +- Removed stale unused copy of u_kept_successful_command body. If you + receive an error about undefined body, alter your policy to use + kept_successful_command instead (CFE-3617) +- Removed unused plugins directory (CFE-3618) +- Renamed python symlink to cfengine-selected-python (CFE-3512) +- Shortened Inventory OS attribute to be more readable (ENT-6536) +- Suppressed inform output from Enterprise Hub database maintenance operations + (ENT-6563) +- Suppressed output from watchdog on AIX to prevent the mail spool from filling up + (CFE-3630) +- Added ability to specify a list of bundles to run before autorun (for classification) (ENT-6603) +- Update policy now moves obstructions (CFE-2984) +- Use VBScript to enumerate installed packages (ENT-4669) +- Added /usr/bin/yum to paths.cf for aix (CFE-3615) +- service status on FreeBSD now uses onestatus (CFE-3515) +- Guard again enforcing root ownership for CFEngine files on Windows (ENT-4628) + +## 3.17.0 + +- Added .csv to the list of file extensions considered by default during + policy update (CFE-3425) +- Added ability to extend known paths without modifying vendored policy + (CFE-3426) +- Added apk package module support for alpinelinux (CFE-3451) +- Added bundle edit_line converge_prepend with same behavior as bundle + edit_line converge, but inserting at start of content. (CFE-3483) +- Added inventory for Timezone and GMT Offset (ENT-6161) +- Added inventory for policy servers (ENT-6212) +- Added maintenance policy to update health diagnostics failures table on + enterprise hubs (ENT-6228) +- Added optional handle duplicates step in federated reporting import + (ENT-6035) +- Added replace_uncommented_substrings (ENT-6117) +- Added service states "active" and "inactive" for systemd (ENT-6074) +- Added watchdog for Windows (ENT-5538) +- Adjusted package_module and paths for termux platform (CFE-3288) +- Aligned systemd services behavior for service_policy => "enable|enabled|disable|disabled" + (ENT-6073) +- Changed bundle server access_rules to mpf_default_access_rules + (CFE-3427) +- Cleaned up Mission Portal OS variable (inventory_os.description) on RHEL 5 & 6 + (ENT-6124) +- De-duplicated license headers (ENT-6040) +- Fixed converge edit_line bundle not deleting lines containing marker + (CFE-3482) +- Fixed interpretation of cf-hub --show-license from REPAIRED to KEPT + (ENT-6473) +- Inventory OS variable (inventory_os.description in policy) is now based on os-release +- Made git_stash only stash untracked files when capable (CFE-3383) +- Moved systemd service management to own bundle (CFE-3381) +- Removed delay in refreshing software installed inventory (ENT-6154) +- Removed unnecessary packages promise on SuSE (ENT-5480, ENT-6375) +- Replaced @ignore with useful doc strings (CFE-3378) + +## 3.16.0 + +- /var/cfengine/bin/python symlink creation on SLES was fixed +- Added `data` shortcut to cf-serverd, defaults to sys.workdir/data +- Added inventory for CFEngine Enterprise License information + (ENT-5089, ENT-5279) +- Added inventory of NFS servers in use (from /proc/mounts, on linux) + (CFE-3259) +- Added inventory of license owner on enterprise hubs (ENT-5337) +- Added paths support for opensuse (CFE-3283) +- Added use of services promise for FR PostgreSQL reconfig in case of + systemd (ENT-5420) +- Added zypper as default package manager for opensuse (CFE-3284) +- Admitted ::1 as a query source on Enterprise hubs (ENT-5531) +- Aligned unattended self upgrade package map with current state + (ENT-6010) +- Always copy modules from masterfiles (CFE-3237) +- Changed DocumentRoot of Mission Portal in httpd.conf to + `/path/to/cfengine/httpd/htdocs/public` (ENT-5372) +- Changed group for state dir files promise to match defaults per OS + (CFE-3362) +- Changed m_inventory dumping behavior to exclude when values is null + (ENT-5562) +- Corrected application/logs path to outside of docroot (ENT-5255) +- Deleted deprecated `__PromiseExecutionsLog` from process that cleans + log tables (ENT-5170) +- Fixed dmi inventory to prefer sysfs to dmidecode for most variables + for improved performance and to handle CoreOS hosts that don't + have dmidecode. (CFE-3249) +- Fixed permission flipping when policy analyzer is enabled (ENT-5235) +- Fixed runalerts processes promise on non-systemd systems (ENT-5432) +- Fixed selection of standard_services when used from non-default + namespace (ENT-5406) +- Fixed system UUID inventory for certain VMWare VMs where dmidecode + gives UUID bytes in wrong order. (CFE-3249) +- Fixed typo preventing recommendation bundles from running (CFE-3305) +- HA setups no longer have flipping permissions on + /opt/cfengine/notification_scripts +- Improved resilience of cron watchdog for linux (CFE-3258) +- Inventory refresh is no longer part of agent run on the hub + (ENT-4864) +- Made python symlink fall back to platform-python (CFE-3291) +- Made set_variable_values_ini prefer whitespace around = (CFE-3221) +- Modified cftransport cleanup to avoid errors (ENT-5555) +- Moved `selinux_enabled` class to config bundle and namespace scope it +- Prevented inventory of unresolved variables for diskfree and loadavg + (ENT-5190) +- Release number was added to MPF tarballs (ENT-5429) +- Standard services now considers systemd services in + ActiveState=activating active (CFE-3238) +- Stopped continual repair of ha_enabled semaphore (ENT-4715) +- Stopped disabling disabled systemd unit each run when disabled state + requested (CFE-3367) +- Stopped trying to edit fields in manage_variable_values_ini + (CFE-3372) +- Suppressed useless inform output from /bin/true in ec2 inventory + (ENT-5233) +- Switched from hardcoded path to /bin/true to use paths from stdlib + (ENT-5278) +- The zypper module is now fully compatible with Python 3 (CFE-3364) +- Whitespace is now allowed at the beginning of ini key-values + (CFE-3244) +- apt_get package module now checks package state (CFE-3233) + +## 3.15.0 + +- Added package_module for snap (CFE-2811) +- Fixed pkgsrc in case where multiple Prefix paths are returned for pkg_install (CFE-3152) +- Fixed pkgsrc module on Solaris/NetBSD (CFE-3151) +- Moved zypper package module errors to the cf-agent output (CFE-3154) +- Added new class mpf_enable_cfengine_systemd_component_management to enable + component management on systemd hosts. When defined on systemd hosts policy + will render systemd unit files in /etc/systemd/system for managed services + and that all units are enabled unless explicitly disabled. When this class + is not defined on systemd hosts the policy will not actively mange cfengine + service units (no change from previous behavior) (CFE-2429) +- Fixed detection of service state on FreeBSD (CFE-3167) +- Added known paths for true and false on linux + (ENT-5060) +- Fixed path for restorecon on redhat systems to /sbin/restorecon +- Added usermod to known paths for redhat systems +- Added policy to manage federated reporting with CFEngine Enterprise +- Introduced augments variable `control_hub_query_timeout` to control cf-hub query timeout. + (ENT-3153) +- Added OOTB inventory for IPv6 addresses (sans ::1 loopback) + (ENT-4987) +- Added and transitioned to using master_software_updates shortcut in self upgrade policy + (ENT-4953) +- Added brief descriptions to bodies and bundles in cfe_internal/CFE_cfengine.cf + (CFE-3220) +- Added support for SUSE 11, 12 in standalone self upgrade (ENT-5045, ENT-5152) +- Changed policy triggering cleanup of `__lastseenhostlogs` to target only + 3.12.x, 3.13.x and 3.14.x. From 3.15.0 on the table is absent. (ENT-5052) +- Fixed agent disabling on systemd systems (CFE-2429, CFE-3416) +- Ensured directory for custom action scripts is present (ENT-5070) +- Excluded Enterprise federation policy parsing on incompatible versions + (CFE-3193) +- Extended watchdog for AIX (ENT-4995) +- Fixed cleanup of future timestamps from status table + (ENT-4331, ENT-4992) +- Fixed re-spawning of cf-execd or cf-monitord after remediating duplicate concurrent processes + (CFE-3150) +- Replaced /var/cfengine with proper `$(sys.*)` vars (ENT-4800) + - Fixed selection of standard_services when used from non-default namespace (ENT-5406) + +## 3.15.0b1 + +- Added continual checking for policy_server state (CFE-3073) +- Added monitoring for PostgreSQL lock acquisition times (ENT-4753) +- Added support for `awk` filters in the FR dump-import process (ENT-4839) +- Added support for configuring abortclasses and abortbundleclasses via + augments (ENT-4823) +- Added support for filtering in both dump and import phases of the FR + ETL process (ENT-4839) +- Added support for ordering FR awk and sed scripts (ENT-4839) +- Added support for setting periodic package inventory refresh interval + via augments (CFE-2771) +- Changed FR policy to honor target_state properly (ENT-4874) +- Copy .awk and .sed files from masterfiles to inputs (ENT-4839) +- Fixed Python 3 incompatibility in yum package module +- Fixed synchronization of important configuration files from active to + passive hub (ENT-4944) +- Made keys of all types from feeder hubs trusted on a superhub (ENT-4917) +- Speeded-up FR import process by merging INSERT INTO statements (ENT-4839) +- Suppressed stderr output from lldpctl when using path defined by + def.lldpctl_json (CFE-3109) +- Added SQL to update feeder update timestamp during import (ENT-4776) +- Added ssh_home_t type to cftransport .ssh dir (ENT-4906) +- fix use of _stdlib_path_exists_ in FR transport_user policy + bundle (ENT-4906) +- partitioned `__inventory` table for federated reporting (ENT-4842) +- psql_wrapper needed full path to psql binary (ENT-4912) +- yum package_module gets updates available from online repos if local + cache fails (CFE-3094) + +## 3.14.0 + +- Fixed isvariable syntax error in update_def.cf (CFE-2953) +- Added path support for setfacl, timedatectl and journalctl (CFE-3013) +- Added trailing slash to access promises expecting directories + (CFE-3024) +- Added scripts and templates for Federated Reporting (ENT-4473) +- rpm python module is no longer required to check zypper version +- Changed cleanup consumer status SQL query (ENT-4365) +- Conditioned use of curl for ec2 metadata cache on curl binary being executable + (CFE-3049) +- Added augments variables to control cf-hub (ENT-4269) +- Prevented DB maintenance tasks on a passive High Availability hub (ENT-4706) +- Repair outcome for starting cf-monitord or cf-execd is no longer suppressed + (CFE-2964) +- Restrictive permissions on hub install log are now enforced (ENT-4506) +- Ensured that asynchronous query API semaphores are writable (ENT-4551) +- Fixed standalone_self_upgrade not triggering because of stale data + (ENT-4317) +- Fixed maintenance policy for promise log cleanup to respect history_length_days + (ENT-4588) +- Improved efficiency and error handling of user specified policy update bundle +- Log version of Enterprise agent outside of state (ENT-4352) +- Added package module for managing windows packages using msiexec (ENT-3719) +- Prevented inventorying un-expanded memory values from cf-monitord (ENT-4522) +- Prevented performance overhead on hubs that don't enable license utilization logging + (ENT-4333) +- Collection status records in the future are now purged (ENT-4362) +- Reduced cost of knowing when setopt is available in yum (CFE-2993) +- runalerts is now restarted if modified (ENT-4273) +- Separated kill signals from restart class to avoid warning (CFE-2974) +- Separated termination and observation promises for cf-monitord + (CFE-2963) +- Set default access promises for directories to only share if directory exists + (CFE-3060) +- Set default value for purge_scheduled_reports_older_than_days + (ENT-4404) +- Added more accurate and descriptive daemon classes +- collect_window in body server control can now be set from augments + (ENT-4283) +- Guarded vars promises in cfe_internal_enterprise_mission_portal_apache + Constrain vars promises in cfe_internal_enterprise_mission_portal_apache + to policy_server.enterprise_edition::, otherwise "cf-promises --show-vars" + includes a dump of the entire datastate from the "data" variable in + cfe_internal_enterprise_mission_portal_apache (line over 100K long). + (CFE-3011) +- redhat_pure is no longer defined on Fedora hosts (CFE-3022) + +## 3.13.0 + +- Added Debian 9 to the self upgrade package map (ENT-4255) +- Added `system-uuid` to default dmidecode inventory (CFE-2925) +- Added inventory of AWS EC2 linux instances (CFE-2924) +- Added ubuntu 18 to package map for self upgrade (ENT-4118) +- Allowed dmidefs inventory to be overridden via augments (CFE-2927) +- Analyze yum return code before parsing its output (CFE-2868) +- Fixed issue when promise to edit file that does not exist caused "promise + not kept" condition (ENT-3965) +- Avoid trying to read /proc/meminfo when it doesn't exist (CFE-2922) +- Avoid use of $(version) for package_version in legacy implementation + (ENT-3963) +- Cleanup old report data relative to the most recent changetimestamp + (ENT-4807) +- Clear `__lastseenhostslogs` every 5 minutes. (ENT-3550) +- Configure Enterprise hub pull collection schedule via augments + (ENT-3834) +- Configure agent_expireafter from augments (ENT-4308) +- Create desired version tracking data when necessary (ENT-3937) +- Cron based watchdog for cf-execd on AIX (ENT-3963) +- Detect systemd service enablement for non native services (CFE-2932) +- Documented how def.acl is used and how to configure it (CFE-2861) +- Fixed augments control state paths to work on windows (ENT-3839) +- Fixed package_latest detecting larger version in some cases (CFE-1743) +- Fixed standalone self upgrade when path contains spaces (ENT-4117) +- Fixed unattended self upgrade on AIX (ENT-3972) +- Fixed services starting on windows (ENT-3883) +- Improve performance of enterprise license utilization logging +- Inventory Memory on HPUX (ENT-4188) +- Inventory Physical Memory MB when dmidecode is found (CFE-2896) +- Inventory Setuid Files (ENT-4158) +- Inventory memory on Windows (ENT-4187) +- Made recommendations about postgresql.conf (ENT-3958) +- Only consider files that exist for rotation (ENT-3946) +- Prevent noise when a service that should be disabled is missing. + (CFE-2690) +- Prevent standalone self upgrade from triggering un-necessarily + (ENT-4092) +- Removed Design Center related policies + Design center never left beta and has been deprecated. Supporting policies have + been removed. If you wish to continue using design center sketches you must + incorporate them into inputs and the bundlesequence manually. + (ENT-4050) +- Removed unicode characters (ENT-3823) +- Removed templates for deprecated components (ENT-3781) +- Removed un-necessary agent run during self upgrade (ENT-4116) +- Slackware package module support (CFE-2827) +- Specify scope => "namespace" when using persistent classes (CFE-2860) +- Store the epoch of packages in cache db with zypper +- Sync cf-runalerts override unit template with package (ENT-3923) +- Update policy can now skip local copy optimization on policy servers + (CFE-2932) +- Updated yum package module to take arbitrary options (ENT-4177) +- Use default for package arch on aix (ENT-3963) +- Use rpmvercmp for version comparison on AIX (ENT-3963) +- Users allowed to request execution via cf-runagent can be configured + (ENT-4054) +- apt_get package module includes held packages when listing updates + (CFE-2855) + +## 3.12.0b1 + +- Avoid executing self upgrade policy unnecessarily (ENT-3592) +- Added amazon_linux class to yum package module +- Introduce ability to set policy update bundle via augments (CFE-2687) +- Localize delete tidy in ha update policy (ENT-3659) +- Improve context notifying user of missing policy update bundle + (ENT-3624) +- Configure ignore_missing_inputs and ignore_missing_bundles via augments + (CFE-2773) +- Changed class identifying runagent initiated executions from cfruncommand to cf_runagent_initiated +- Support enablerepo and disablerepo options in yum package_module + (CFE-2806) +- Fixed cf-runagent during 3.7.x -> 3.10.x migration + (CFE-2776, CFE-2781, CFE-2782) +- Made it possible to tune policy master_location via augments in update policy + (ENT-3692) +- Fixed inventory for total memory on AIX (CFE-2797) +- Do not manage redis since it's no longer used (ENT-2797) +- Server control maxconnections can be configured via augments + (CFE-2660) +- Allowed configuration of allowlegacyconnects from augments (ENT-3375) +- Fixed ability for zypper package_module to downgrade packages +- Splaytime in body executor control can now be configured via augments + (CFE-2699) +- Added maintenance policy to refresh events table on enterprise hubs + (ENT-3537) +- Added apache config for new LDAP API (ENT-3265) +- update.cf bundlesequence can be configured via augments (CFE-2521) +- Update policy inputs can be extended via augments (CFE-2702) +- Added oracle linux support to standalone self upgrade +- Added bundle to track component variables to restart when necessary + (CFE-2326) +- Retention of files found in log directories can now be configured via augments + (CFE-2539) +- Allowed multiple sections in insert_ini_section (CFE-2721) +- Added lines_present edit_lines bundle +- Schedule in body executor control can now be configured via augments + (CFE-2508) +- Included scheduled report assets in self maintenance (ENT-3558) +- Removed unused body action aggregator and body file_select folder +- Removed unused body process_count check_process +- Prevent yum from locking in package_methods when possible + (CFE-2759) +- Render variables tagged for inventory from agent host_info_report + (CFE-2750) +- Made apt_get package module work with repositories containing spaces in the label + (ENT-3438) +- Allowed hubs to collect from themselves over loopback (ENT-3329) +- Log file max size and rotation limits can now be configured via augments + (CFE-2538) +- Changed: Do not silence Enterprise hub maintenance +- Ensure HA standby hubs have am_policy_hub state marker (ENT-3328) +- Added support for 32bit rpms in standalone self upgrade (ENT-3377) +- Added enterprise maintenance bundles to host info report (ENT-3537) +- Removed unnecessary promises for OOTB package inventory +- Added external watchdog support for stuck cf-execd (ENT-3251) +- Be less noisy when a promised service is not found (CFE-2690) +- Ignore empty options in apt_get module (CFE-2685) +- Added postgres.log to enterprise log file rotation (ENT-3191) +- Removed unnecessary support for including 3.6 controls +- Fixed systemctl path detection +- Policy Release Id is now inventoried by default (CFE-2097) +- Fixed to frequent logging of enterprise license utilization (ENT-3390) +- Maintain access to exported CSV reports in older versions (ENT-3572) +- cf-execd service override template now only kills cf-execd on stop + (ENT-3395) +- Fixed self upgrade for hosts older than 3.7.4 (ENT-3368) +- Avoid self upgrade from triggering during bootstrap (ENT-3394) +- Added json templates for rendering serial and multiline data (CFE-2713) +- Removed unused libraries and controls +- Fixed an error in the `file_make_mustache_*`, incorrect variable name used + (CFE-2714) + +## 3.11.0 + +- Renamed enable_client_initiated_reporting to client_initiated_reporting_enabled +- Directories for ubuntu 16 and centos 7 should exist in master_software_updates + (ENT-3136) +- Fixed: Automatic client upgrades for deb hosts +- Added AIX OOTB oslevel inventory (ENT-3117) +- Disabled package inventory via modules on redhat like systems with unsupported python versions + (CFE-2602) +- Made stock policy update more resilient (CFE-2587) +- Configure networks allowed to initiate report collection (client initiated reporting) via augments (#910) + (CFE-2624) +- apt_get package module: Fix bug which prevented updates + from being picked up if there was more than one source listed in the + `apt upgrade` output, without a comma in between (CFE-2605) +- Enabled specification of monitoring_include via augments (CFE-2505) +- Configure call_collect_interval from augments (enable_client_initiated_reporting) (#905) + (CFE-2623) +- Added templates shortcut (CFE-2582) +- Behaviour changed: when used with CFEngine 3.10.0 or greater, + bundles set_config_values() and set_line_based() are appending a + trailing space when inserting a configuration option with empty value + (CFE-2466) +- Added default report collection exclusion based on promise handle + (ENT-3061) +- Fixed ability to select INI region with metachars (CFE-2519) +- Changed: Verify transferred files during policy update +- Changed select_region INI_section to match end of section or end of file + (CFE-2519) +- Added class to enable post transfer verification during policy updates +- Added: prunetree bundle to stdlib + The prunetree bundle allows you to delete files and directories up to a + specified depth older than a specified number of days +- Do not symlink agents to /usr/local/bin on CoreOS (ENT-3047) +- Added: Ability to set default_repository via augments +- Enabled settig def.max_client_history_size via augments (CFE-2560) +- Changed self upgrade now uses standalone policy (ENT-3155) +- Fixed apt_get package module incorrectly using interactive mode +- Added ability to append to bundlesequnece with def.json (CFE-2460) +- Enabled paths to POSIX tools by default instead of native tools +- Removed bundle agent cfe_internal_bins (CFE-2636) +- Included previous_state and untracked reports when client clear a buildup of unreported data + (ENT-3161) +- Fixed command to restart apache on config change (ENT-3134) +- cf-serverd listens on ipv4 and ipv6 by default (CFE-528) +- FixesMake apt_get module compatible with Ubuntu 16.04 (CFE-2445) +- Fixed rare bug that would sometimes prevent redis-server from launching +- Added oslevel to well known paths (ENT-3121) +- Added policy to track CFEngine Enterprise license utilization + (ENT-3186) +- Ensure MP SSL Cert is readable (ENT-3050) + +## 3.10.0 + +- Added: Classes body tailored for use with diff +- Changed: Session Cookies use HTTPOnly and secure attributes (ENT-2781) +- Changed: Verify transferred files during policy update +- Added: Inventory for system product name (model) (ENT-2780) +- Added: Ensure appropriate permissions for SSL files (ENT-760) +- Fixed rare bug that would sometimes prevent redis-server from launching. +- Changed: Enable strict transport security +- Added: Definition of from_cfexecd for cf-execd initiated runs + (CFE-2386) +- Added testing jUnit and TAP bundles and include them in stdlib.cf +- Changed: Rename duplicate bodies in ha_update.cf (ENT-2753) +- Changed: Disable RC4 Cipher for ssl in Mission Portal +- Pass package promise options to underlying apt-get call (#802) + (CFE-2468) +- Changed: Enable agent component management policy on systemd hosts + (CFE-2429) +- Added: Enterprise appliaction log dir to rotation +- Changed: re-enable hub process maintenance +- Added: edit_line contains_literal_string to stdlib +- Fixed: Services starting or stopping unnecessarily (CFE-2421) +- Allowed specifying agent maxconnections via def.json (CFE-2461) +- Changed: Disable http TRACE method +- Changed: Reduce Enteprise webserver info +- Changed: cronjob bundle tolerates different spacing +- Fixed: CFEngine choking on standard services (CFE-2806) +- Changed select_region INI_section to match end of section or end of file + (CFE-2519) +- Fixed ability to manage INI sections with metachars for + manage_variable_values_ini and set_variable_values_ini (CFE-2519) +- Fixed apt_get package module incorrectly using interactive mode. +- Added ability to append to bundlesequnece with def.json (CFE-2460) +- Behaviour changed: when used with CFEngine 3.10.0 or greater, + bundles set_config_values() and set_line_based() are appending a + trailing space when inserting a configuration option with empty value. + (CFE-2466) + +## 3.7.0 + +- Support for user specified overriding of framework defaults without modifying + policy supplied by the framework itself (see example_def.json) +- Support for def.json class augmentation in update policy +- Run vacuum operation on PostgreSQL every night as a part of maintenance. +- Added measure_promise_time action body to lib (3.5, 3.6, 3.7, 3.8) +- New negative class guard `cfengine_internal_disable_agent_email` so that + agent email can be easily disabled by augmenting def.json +- Relocated def.cf to controls/VER/ +- Relocated update_def to controls/VER +- Relocated all controls to controls/VER +- Only load cf_hub and reports.cf on CFEngine Enterprise installs +- Relocated acls related to report collection from bundle server access_rules + to controls/VER/reports.cf into bundle server report_access_rules +- Re-organized cfe_internal splitting core from enterprise specific policies + and loading the appropriate inputs only when necessary +- Moved update directory into cfe_internal as it is not generally intended to + be modified +- services/autorun.cf moved to lib/VER/ as it is not generally intended to be + modified +- To improve predictibility autorun bundles are activated in lexicographical + order +- Relocated services/file_change.cf to cfe_internal/enterprise. This policy is + most useful for a good OOTB experience with CFEngine Enterprise Mission + Portal. +- Relocated service_catalogue from promises.cf to services/main.cf. It is + intended to be a user entry. This name change correlates with the main + bundle being activated by default if there is no bundlesequence specified. +- Reduce benchmarks sample history to 1 day. +- Update policy no longer generates a keypair if one is not found. (Redmine: #7167) +- Relocated cfe_internal_postgresql_maintenance bundle to lib/VER/ +- Set postgresql_monitoring_maintenance only for versions 3.6.0 and 3.6.1 +- Move hub specific bundles from lib/VER/cfe_internal.cf into lib/VER/cfe_internal_hub.cf + and load them only if policy_server policy if set. +- Re-organized lib/VER/stdlib.cf from lists into classic array for use with getvalues +- `inform_mode` classes changed to `DEBUG|DEBUG_$(this.bundle)::` (Redmine: #7191) +- Enabled limit_robot_agents in order to work around multiple cf-execd + processes after upgrade. (Redmine #7185) +- Removed Diff reporting on /etc/shadow (Enterprise) +- Update policy from promise.cf inputs. There is no reason to include the + update policy into promises.cf, update.cf is the entry for the update policy +- `_not_repaired` outcome from classes_generic and scoped_classes generic (Redmine: #7022) +- standard_services now restarts the service if it was not already running + when using service_policy => restart with chkconfig (Redmine #7258) +- Fixed process_result logic to match the purpose of body process_select + days_older_than (Redmine #3009) diff --git a/MPF.md b/MPF.md index bc8ce157cc..945eca4ea9 100644 --- a/MPF.md +++ b/MPF.md @@ -147,7 +147,7 @@ For example: **Notes:** -* The order in which bundles are actuates is not guaranteed. +* The order in which bundles are actuated is not guaranteed. * The agent will error if a named bundle is not part of inputs. ### Specify the agent bundle used for policy update @@ -164,12 +164,14 @@ Override this bundle by setting `def.mpf_update_policy_bundle` via augments: { "variables": { "default:def.mpf_update_policy_bundle": { - "value": "MyCustomPolicyUpdateBundle" + "value": "default:MyCustomPolicyUpdateBundle" } } } ``` +**NOTE:** Be sure to specify the namespace the bundle is in, for example, `default`. + **History:** * Introduced in 3.12.0 @@ -1304,6 +1306,38 @@ Example definition in augments file: } ``` +### Specify the CFEngine protocol version to use + +By default CFEngine will negotiate the newest protocol version available. Configuring `protocol_version` will restrict the protocol to the specified version. + +```json +{ + "variables": { + "default:def.control_common_protocol_version": { + "value": "filestream" + } + } +} +``` + +**Notes:** + +- Valid values for `protocol_version` can be extracted from the syntax-description output of `cf-promises`. + + For example: + + ```command + cf-promises --syntax-description=json | jq -r '.bodyTypes.common.attributes.protocol_version.range' + ``` + + ```output + (1|classic|2|tls|3|cookie|4|filestream|latest) + ``` + +**History:** + +- Added in CFEngine 3.27.0, 3.24.3 + ### Configure the ciphers used by cf-serverd When `default:def.control_server_allowciphers` is defined `cf-serverd` will use the ciphers specified instead of the binary defaults. @@ -1406,6 +1440,26 @@ Example definition in augments file: * Added in 3.22.0, 3.21.2 +### Configure the minimum log level for system log + +When `default:def.control_common_system_log_level` is defined the value controls the minimum log level required for log messages to go to the system log (e.g. syslog, Windows Event Log). + +Example definition in augments file: + +```json +{ + "variables": { + "default:def.control_common_system_log_level": { + "value": "info", + "comment": "We want syslog to recieve messages tha are level info and above." + } + } +} +``` +**History:** + +* Added in 3.25.0 + ### Configure users allowed to initiate execution via cf-runagent cf-serverd only allows specified users to request unscheduled execution remotely via cf-runagent. @@ -1816,6 +1870,30 @@ This can be configured via [augments][Augments]: **History:** Added 3.11.0 +### Configure maxconnections for cf-agent + +`maxconnections` in `body agent control` configures the maximum number of +outbound connections allowed by `cf-agent`. By default the MPF configures this to `30` matching the binary default. + +**Notes:** + +- Generally this would need to be increased for hosts who are copying files from many other hosts (a-typical, especially in Enterprise environments). + +This can be configured via [augments][Augments]: + +```json +{ + "variables": { + "default:def.control_agent_maxconnections": { + "value": "1000", + "comment": "On the hub we collect a data file from each client recently seen, this requires cf-agent to be allowed to make many connections" + } + } +} +``` + +**History:** Added in CFEngine 3.10.0 + ### Configure networks allowed to make collect_calls (client initiated reporting) By default the hub allows collect calls (client initiated reporting) from the @@ -1887,6 +1965,10 @@ Primarily for developer convenience, this setting allows you to easily disable t } ``` +**History:** + +* Added in CFEngine 3.12.0 + ### Configure Enterprise Mission Portal Apache SSLProtocol This directive can be used to control which versions of the SSL/TLS protocol will be accepted in new connections. @@ -1995,7 +2077,7 @@ For example: **Notes:** -* The order in which bundles are actuates is not guaranteed. +* The order in which bundles are actuated is not guaranteed. * The agent will error if a named bundle is not part of inputs. **History:** Added in 3.10.0 @@ -2283,6 +2365,7 @@ can be customized via Augments. ```yum_rpm_enable_repo``` , ```yum_group```, ```rpm_filebased```, ```ips```, ```smartos```, ```opencsw```, ```emerge```, ```pacman```, ```zypper```, ```generic``` + * [package bundles][lib/packages.cf]: ```package_latest```, ```package_specific_present```, ```package_specific_absent```, ```package_specific_latest```, ```package_specific``` diff --git a/README.md b/README.md index a3c650c559..b59da541ff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Looking for help? -[![Gitter chat](https://badges.gitter.im/cfengine/core.png)](https://gitter.im/cfengine/core) | [![IRC channel](https://kiwiirc.com/buttons/irc.cfengine.com/cfengine.png)](https://web.libera.chat?channel=#cfengine) +* [Chat with us in #CFEngine:matrix.org](https://matrix.to/#/#CFEngine:matrix.org). +* Ask questions on [Github Discussions](https://github.com/cfengine/core/discussions/) or the mailing list [help-cfengine@googlegroups.com](https://groups.google.com/g/help-cfengine). # CFEngine 3 masterfiles diff --git a/cfe_internal/enterprise/CFE_hub_specific.cf b/cfe_internal/enterprise/CFE_hub_specific.cf index 22e0782a82..7817b76a6f 100644 --- a/cfe_internal/enterprise/CFE_hub_specific.cf +++ b/cfe_internal/enterprise/CFE_hub_specific.cf @@ -40,6 +40,14 @@ bundle common cfe_internal_hub_vars policy_server:: + "http_port" -> { "ENT-12151" } + string => ifelse( isvariable("cfe_internal_hub_vars.http_port"), "$(cfe_internal_hub_vars.http_port)", "80" ), + comment => "Mission portal's webserver HTTP port. Default 80"; + + "https_port" -> { "ENT-12151" } + string => ifelse( isvariable("cfe_internal_hub_vars.https_port"), "$(cfe_internal_hub_vars.https_port)", "443" ), + comment => "Mission portal's webserver HTTPS port. Default 443"; + "docroot" string => "$(sys.workdir)/httpd/htdocs", comment => "Root directory of Enterprise Web interface", handle => "cfe_internal_hub_vars_docroot"; @@ -91,6 +99,47 @@ bundle common cfe_internal_hub_vars } +################################################################## +# +# update_cli_rest_server_url_config +# - updates REST server URL port of Mission Portal WebGUI when +# cfe_internal_hub_vars.https_port is changed +# +################################################################## +bundle agent update_cli_rest_server_url_config +{ + vars: + # Both share and live versions must be changed at once since httpd will be restarted later in the same agent run. + "mp_config_file" string => "$(cfe_internal_hub_vars.docroot)/application/config/config.php"; + "mp_share_config_file" string => "$(sys.workdir)/share/GUI/application/config/config.php"; + "regex_test_pattern" string => ".*localhost:$(cfe_internal_hub_vars.https_port).*"; + + files: + !mpf_disable_mission_portal_docroot_sync_from_share_gui:: + "$(mp_share_config_file)" + edit_line => change_cli_rest_server_url_port, + if => and( + fileexists("$(mp_share_config_file)"), + islessthan(countlinesmatching("$(regex_test_pattern)", "$(mp_share_config_file)"), 1) + ); + + any:: + "$(mp_config_file)" + edit_line => change_cli_rest_server_url_port, + if => and( + fileexists("$(mp_config_file)"), + islessthan(countlinesmatching("$(regex_test_pattern)", "$(mp_config_file)"), 1) + ); +} + +bundle edit_line change_cli_rest_server_url_port +{ + replace_patterns: + "^\s*\$config\['cli_rest_server_url'\]\s*=\s*\"https://localhost(?::(?!$(cfe_internal_hub_vars.https_port))\d{1,5})?/api/\";\s*$" + replace_with => value(" $config['cli_rest_server_url'] = \"https://localhost:$(cfe_internal_hub_vars.https_port)/api/\";"), + comment => "Change port CLI REST server URL port"; +} + ################################################################## # # cfe_internal_update_folders diff --git a/cfe_internal/enterprise/federation/federation.cf b/cfe_internal/enterprise/federation/federation.cf index 8fc27de0f9..d812d93470 100644 --- a/cfe_internal/enterprise/federation/federation.cf +++ b/cfe_internal/enterprise/federation/federation.cf @@ -245,7 +245,7 @@ bundle agent semanage_installed warn or fix based."; debian_6|debian_7|debian_8|ubuntu_12|ubuntu_14|ubuntu_16|rhel_5:: "semanage_package" string => "policycoreutils"; - debian_9|debian_10|ubuntu_18|redhat_8|centos_8|redhat_9|rocky_9:: + debian_9|debian_10|ubuntu_18|redhat_8|centos_8|redhat_9|redhat_10|rocky_9:: "semanage_package" string => "policycoreutils-python-utils"; redhat_6|centos_6|redhat_7|centos_7:: "semanage_package" string => "policycoreutils-python"; @@ -591,10 +591,6 @@ bundle agent federation_manage_files copy_from => default:local_dcp( "$(this.promise_dirname)/../../../templates/federated_reporting/dump.sh" ), perms => default:mog( "700", "root", "root" ); - "$(cfengine_enterprise_federation:config.federation_dir)/fedhub/dump/filters/50-merge_inserts.awk" - copy_from => default:local_dcp( "$(this.promise_dirname)/../../../templates/federated_reporting/50-merge_inserts.awk" ), - perms => default:mog( "600", "root", "root" ); - am_transporter:: "$(cfengine_enterprise_federation:config.bin_dir)/transport.sh" -> { "CFE-951" } copy_from => default:local_dcp( "$(this.promise_dirname)/../../../templates/federated_reporting/transport.sh" ), @@ -924,6 +920,9 @@ bundle agent setup_status # parse sshd config to find the file and then readfile(): string => execresult("ssh-keyscan localhost 2>/dev/null | sed 's/localhost //g' | sort", useshell); classes: + "ssh_server_fingerprint_collected" + expression => not(strcmp("$(ssh_server_fingerprint)", "")); + "superhub_setup_status_complete" expression => "any", depends_on => { @@ -934,7 +933,12 @@ bundle agent setup_status }; files: - superhub_setup_status_complete:: + # An empty fingerprint (ssh-keyscan returned nothing, e.g. sshd not yet + # reachable on localhost) must not be advertised: a superhub would render + # an empty known_hosts entry for this host and its rsync pull would later + # fail with "Host key verification failed". Skip the status update until + # the fingerprint is collected; the next agent run will retry. + superhub_setup_status_complete.ssh_server_fingerprint_collected:: "$(cfengine_enterprise_federation:config.path_setup_status)" create => "true", perms => default:mog( "600", "cfapache", "root" ), @@ -947,7 +951,11 @@ bundle agent setup_status "transport_ssh_public_key": "$(ssh_pub_key)", "transport_ssh_server_fingerprint": "$(ssh_server_fingerprint)", }', - if => isvariable( ssh_pub_key ); + if => isvariable(ssh_pub_key); + + reports: + superhub_setup_status_complete.!ssh_server_fingerprint_collected:: + "warning: 'ssh-keyscan localhost' returned no SSH host key; federation setup status not written yet. Will retry next run."; } bundle agent distributed_cleanup_setup diff --git a/cfe_internal/enterprise/mission_portal.cf b/cfe_internal/enterprise/mission_portal.cf index fe69ef62f7..c82667db30 100644 --- a/cfe_internal/enterprise/mission_portal.cf +++ b/cfe_internal/enterprise/mission_portal.cf @@ -58,7 +58,8 @@ bundle agent apachectl_patched_for_upgrade edit_template => "$(this.promise_dirname)/templates/apachectl.mustache", handle => "apachectl_content_pre_create_default_templated_files", template_method => "mustache", - template_data => parsejson( '{ "cfengine_enterprise_mission_portal_httpd_dir": "$(sys.workdir)/httpd" }'); + template_data => parsejson( '{ "cfengine_enterprise_mission_portal_httpd_dir": "$(sys.workdir)/httpd" }'), + classes => results("bundle", "apachectl_file"); _running_cfengine_version_where_templated_files_NOT_automatically_created:: "$(sys.workdir)/httpd/bin/apachectl" @@ -66,12 +67,19 @@ bundle agent apachectl_patched_for_upgrade edit_template => "$(this.promise_dirname)/templates/apachectl.mustache", handle => "apachectl_content_post_create_default_templated_files", template_method => "mustache", - template_data => parsejson( '{ "cfengine_enterprise_mission_portal_httpd_dir": "$(sys.workdir)/httpd" }'); + template_data => parsejson( '{ "cfengine_enterprise_mission_portal_httpd_dir": "$(sys.workdir)/httpd" }'), + classes => results("bundle", "apachectl_file"); cfengine:: "$(sys.workdir)/httpd/bin/apachectl" handle => "apachectl_perms", perms => mog( "0755", "root", "root" ); + + commands: + # This only runs if apachectl touched (repaired) and restorecon path exists + apachectl_file_repaired.default:_stdlib_path_exists_restorecon:: + "$(default:paths.restorecon) $(sys.workdir)/httpd/bin/apachectl" + comment => "Ensure the templated apachectl has the correct SELinux context."; } bundle agent cfe_internal_enterprise_mission_portal_apache @@ -163,9 +171,10 @@ bundle agent mission_portal_apache_from_stage(config, staged_config) string => "Configure apache based on successfully staged config"; classes: - "systemd_supervised" - expression => returnszero("$(paths.systemctl) -q is-active cf-apache > /dev/null 2>&1", "useshell"), - if => fileexists( $(paths.systemctl) ); + "systemd_supervised" -> { "ENT-11189" } + expression => returnszero("$(paths.systemctl) cat cf-apache > /dev/null 2>&1", "useshell"), + if => fileexists( $(paths.systemctl) ), + comment => "Set when cf-apache.service is a unit known to systemd"; vars: @@ -234,6 +243,13 @@ bundle agent mission_portal_apache_from_stage(config, staged_config) contain => in_shell, comment => "We restart apache after the new valid config is in place"; + methods: + systemd_supervised:: + "Reset cf-apache failed state" -> { "ENT-11189" } + usebundle => cf_apache_reset_failed_state, + if => "mission_portal_apache_config_repaired", + comment => "Clear any latched failed state before restarting cf-apache"; + services: systemd_supervised:: "cf-apache" @@ -404,3 +420,15 @@ bundle agent cfe_enterprise_selfsigned_cert "DEBUG $(this.bundle): No Certificate Generation Requested" if => "!_cfe_enterprise_selfsigned_cert_regenerate_certificate"; } + +bundle agent cf_apache_reset_failed_state +# @brief Clear any latched 'failed' state on cf-apache.service so subsequent +# service operations are not refused by systemd's start rate limiter +# (StartLimitBurst). Safe no-op when the unit is not in a failed state. +{ + commands: + "$(paths.systemctl) reset-failed cf-apache" -> { "ENT-11189" } + contain => in_shell, + handle => "cf_apache_systemctl_reset_failed", + comment => "Reset latched failed state on cf-apache.service"; +} diff --git a/cfe_internal/enterprise/templates/httpd.conf.mustache b/cfe_internal/enterprise/templates/httpd.conf.mustache index f733fc1664..1d28af2e51 100644 --- a/cfe_internal/enterprise/templates/httpd.conf.mustache +++ b/cfe_internal/enterprise/templates/httpd.conf.mustache @@ -207,6 +207,23 @@ LogLevel warn Header always set X-Frame-Options DENY Header always set X-Content-Type-Options nosniff + Header always set Content-Security-Policy \ + "frame-ancestors 'self'; \ + default-src 'self'; \ + script-src 'self' 'unsafe-inline'; \ + style-src 'self' 'unsafe-inline' fonts.googleapis.com; \ + object-src 'none'; \ + frame-src 'self'; \ + child-src 'self'; \ + img-src 'self' data: blob: avatars.githubusercontent.com badges.gitter.im fonts.gstatic.com kiwiirc.com raw.githubusercontent.com raw.github.com; \ + font-src 'self' data: fonts.googleapis.com fonts.gstatic.com; \ + connect-src 'self' fonts.gstatic.com fonts.googleapis.com; \ + manifest-src 'self'; \ + base-uri 'self'; \ + form-action 'self'; \ + media-src 'self'; \ + worker-src 'self' blob:;" + SSLOptions +StdEnvVars @@ -232,6 +249,9 @@ AddHandler php{{{vars.cfe_internal_hub_vars.php_version}}}-script .php AddType application/x-httpd-php-source php{{{vars.cfe_internal_hub_vars.php_version}}} +# Timeout defaults to 60 but that is too short for some operations on slower hub hardware +Timeout 120 + Options -Indexes +FollowSymLinks +MultiViews diff --git a/cfe_internal/recommendations.cf b/cfe_internal/recommendations.cf index fad760201d..a33b2eb809 100644 --- a/cfe_internal/recommendations.cf +++ b/cfe_internal/recommendations.cf @@ -107,6 +107,46 @@ bundle agent ignore_interfaces_rx_reccomendations } @endif +bundle agent nfs_mount_recommendations +# @brief Recommendations about configured NFS servers +{ + meta: + + "tags" slist => { "cfengine_recommends" }; + + vars: + "nfs_server_list" + slist => getvalues( "default:inventory_linux.nfs_server"), + depends_on => { "cfe_internal_inventory_mounted_nfs_server" }; + + classes: + + # If we end up emitting the recommendation, then we define a class so that + # instructions about disabling these reports are also emitted. + + "cfengine_recommendation_instruct_disablement" + expression => "cfengine_recommendation_emitted_kept", + scope => "namespace"; + + reports: + + "$(with)" + with => concat( + "NOTICE: At least one of your NFS servers is specified", + " in-consistently. Consider aligning your definitions to", + " consistently use or avoid a trailing dot when specifying", + " the NFS server." + ), + if => and( + # Check if there exists inventory of mounted nfs servers + isvariable( "nfs_server_list" ), + # Check if any other NFS server looks identical when adding a trailing dot + some( concat( escape("$(nfs_server_list)"), "\.$" ), + "nfs_server_list" ) + ), + classes => results( "bundle", "cfengine_recommendation_emitted"); +} + bundle agent postgresql_conf_recommendations # @brief Recommendations about the configuration of postgresql.conf for CFEngine Enterprise Hubs { diff --git a/cfe_internal/update/systemd_units.cf b/cfe_internal/update/systemd_units.cf index a9468f405b..90a25dcec3 100644 --- a/cfe_internal/update/systemd_units.cf +++ b/cfe_internal/update/systemd_units.cf @@ -44,14 +44,14 @@ bundle agent cfe_internal_systemd_unit_files systemd:: "$(systemctl)" - args => "daemon-reload", + args => "daemon-reload --no-ask-password", handle => "cfe_internal_systemd_unit_files_reload_when_changed", if => classmatch("cfe_systemd_service_unit_.*_repaired"), comment => "We need to reload the systemd configuration after any unit is changed in order for systemd to recognize the change."; "$(systemctl)" - args => "restart $(service_units).service", + args => "restart $(service_units).service --no-ask-password", handle => "cfe_internal_systemd_unit_restart_when_changed", if => and(classify("cfe_systemd_service_unit_$(service_units)_repaired"), returnszero("$(systemctl) --quiet is-active $(service_units)", noshell)), diff --git a/cfe_internal/update/update_bins.cf b/cfe_internal/update/update_bins.cf index ca6650d36c..acf6b63459 100644 --- a/cfe_internal/update/update_bins.cf +++ b/cfe_internal/update/update_bins.cf @@ -262,7 +262,7 @@ bundle agent cfe_internal_update_bins comment => "Ensure the local software directory exists for new binaries to be downloaded to"; - "$(local_software_dir)" + "$(local_software_dir)/." comment => "Copy binary updates from master source on policy server", handle => "cfe_internal_update_bins_files_pkg_copy", copy_from => u_pcp("$(master_software_location)/$(package_dir)", @(update_def.policy_servers)), diff --git a/cfe_internal/update/update_policy.cf b/cfe_internal/update/update_policy.cf index 3c31c897c2..c7c4c06f78 100644 --- a/cfe_internal/update/update_policy.cf +++ b/cfe_internal/update/update_policy.cf @@ -42,7 +42,7 @@ bundle agent cfe_internal_update_policy # Look for a bundle that matches what the user wants "found_matching_user_specified_bundle" - slist => bundlesmatching( "$(def.mpf_update_policy_bundle)" ); + slist => bundlesmatching( "^$(def.mpf_update_policy_bundle)$" ); methods: @@ -71,18 +71,16 @@ bundle agent cfe_internal_update_policy inform_mode|verbose_mode|DEBUG|DEBUG_cfe_internal_update_policy:: # Report a human readable way to understand the policy behavior - "Found user specified update bundle." - if => "have_user_specified_update_bundle"; - "User specified update bundle: $(def.mpf_update_policy_bundle)" if => "have_user_specified_update_bundle"; "User specified update bundle MISSING! Falling back to $(default_policy_update_bundle)." if => and( "have_user_specified_update_bundle", - "missing_user_specified_update_bundle" - ); - - + "missing_user_specified_update_bundle" ); + any:: + "WARNING User specified update bundle '$(def.mpf_update_policy_bundle)' does not specify a namespace. Please specify a namespace, e.g. 'default:$(def.mpf_update_policy_bundle)'." + if => and( not(regcmp( ".*:.*", $(def.mpf_update_policy_bundle) ) ), + "have_user_specified_update_bundle" ); } bundle agent cfe_internal_setup_python_symlink(symlink_path) @@ -160,6 +158,10 @@ bundle agent cfe_internal_update_policy_cpv # scanned for update. { vars: + # TODO: Remove this once sys.keydir is always available (3.26+ only) + "keydir" -> { "CFE-2822" } + string => ifelse(isvariable("sys.keydir"), "$(sys.keydir)", "$(sys.workdir)/ppkeys"); + "inputs_dir" string => translatepath("$(sys.inputdir)"), comment => "Directory containing CFEngine policies", handle => "cfe_internal_update_policy_vars_inputs_dir"; @@ -187,7 +189,7 @@ bundle agent cfe_internal_update_policy_cpv comment => "Path to a policy file", handle => "cfe_internal_update_vars_file_check"; - "ppkeys_file" string => translatepath("$(sys.workdir)/ppkeys/localhost.pub"), + "ppkeys_file" string => translatepath("$(keydir)/localhost.pub"), comment => "Path to public key file", handle => "cfe_internal_update_policy_vars_ppkeys_file"; @@ -782,7 +784,7 @@ body delete u_tidy bundle agent modules_presence # @brief Render vendored and user provided modules from $(sys.inputdir) to $(sys.workdir) # -# @description This bundle manages the contents of $(sys.workdir)/modules by +# @description This bundle manages the contents of moduledir (/var/cfengine/modules) by # first dealing with package module scripts. # Preference is given to user provided package module scripts in # modules/packages directory. If a module there matches a mustache @@ -792,18 +794,28 @@ bundle agent modules_presence # e.g. modules/packages/apt_get takes precedence over modules/packages/apt_get.mustache # # Any other files in the modules directory will be promised to -# be updated in $(sys.workdir)/modules, including any sub-directories. +# be updated in moduledir (/var/cfengine/modules), including any sub-directories. { + vars: + # TODO: Remove this once sys.moduledir is always available (3.26+ only) + "moduledir" string => ifelse(isvariable("sys.moduledir"), "$(sys.moduledir)", "$(sys.workdir)/modules"); "_vendored_dir" string => "$(this.promise_dirname)$(const.dirsep)..$(const.dirsep)..$(const.dirsep)modules$(const.dirsep)packages$(const.dirsep)vendored$(const.dirsep)"; + "_vendored_dir_filter" string => "$(this.promise_dirname)$(const.dirsep)..$(const.dirsep)..$(const.dirsep)modules$(const.dirsep)packages$(const.dirsep)vendored"; "_override_dir" string => "$(this.promise_dirname)$(const.dirsep)..$(const.dirsep)..$(const.dirsep)modules$(const.dirsep)packages$(const.dirsep)"; "_custom_template_dir" string => "$(this.promise_dirname)$(const.dirsep)..$(const.dirsep)..$(const.dirsep)modules$(const.dirsep)mustache$(const.dirsep)"; "_vendored_paths" slist => findfiles("$(_vendored_dir)*.mustache"); "_custom_template_paths" slist => findfiles("$(_custom_template_dir)*.mustache"), if => isdir( "$(_custom_template_dir)" ); - "_package_paths" slist => filter("$(_override_dir)vendored", _package_paths_tmp, "false", "true", 999); + "_package_paths" + with => ifelse( or( cf_version_between( "3.24.0", "3.24.3"), + cf_version_at("3.26.0"), + cf_version_at("3.27.0")), "$(const.dirsep)", + ""), + slist => filter("$(_override_dir)vendored$(with)", _package_paths_tmp, "false", "true", 999); windows:: - "_package_paths_tmp" slist => findfiles("$(_override_dir)*"); + "_package_paths" slist => filter("\Q${_vendored_dir_filter}\E.*", _package_paths_tmp, "true", "true", 999), + comment => "The list will include the vendored sub-directory that we don't want so remove it."; "_vendored_modules" slist => maplist(regex_replace("$(this)", "\Q$(_vendored_dir)\E(.*).mustache", "$1", "g"), @(_vendored_paths)); "_override_modules" slist => maplist(regex_replace("$(this)", "\Q$(_override_dir)\E(.*)", "$1", "g"), @(_package_paths)); # replace single backslashes in a windows path with double-backslashes @@ -811,7 +823,8 @@ bundle agent modules_presence # causing PCRE to try and interpret special escape sequences. "_not_vendored_modules_pathname_regex" string => regex_replace("$(sys.inputdir)$(const.dirsep)modules$(const.dirsep)(?!packages$(const.dirsep)vendored).*","\\\\","\\\\\\\\","g"); !windows:: - "_package_paths_tmp" slist => findfiles("$(_override_dir)*"); + "_package_paths" slist => filter("${_vendored_dir_filter}.*", _package_paths_tmp, "true", "true", 999), + comment => "The list will include the vendored sub-directory that we don't want so remove it."; "_vendored_modules" slist => maplist(regex_replace("$(this)", "$(_vendored_dir)(.*).mustache", "$1", "g"), @(_vendored_paths)); "_override_modules" slist => maplist(regex_replace("$(this)", "$(_override_dir)(.*)", "$1", "g"), @(_package_paths)); "_custom_template_modules" slist => maplist(regex_replace("$(this)", "$(_custom_template_dir)(.*).mustache", "$1", "g"), @(_custom_template_paths)); @@ -826,21 +839,21 @@ bundle agent modules_presence # update (see controls/update_def.cf input_name_patterns var. files: - "$(sys.workdir)/modules/packages/$(_vendored_modules)" + "$(moduledir)/packages/$(_vendored_modules)" create => "true", perms => u_mo("755", "root"), unless => canonify("override_vendored_module_$(_vendored_modules)"), edit_template => "$(_vendored_dir)$(_vendored_modules).mustache", template_method => "mustache"; - "$(sys.workdir)/modules/packages/$(_override_modules)" + "$(moduledir)/packages/$(_override_modules)" copy_from => u_cp_missing_ok("$(_override_dir)$(_override_modules)"), perms => u_mo("755", "root"), if => or ( canonify("override_vendored_module_$(_override_modules)"), canonify("override_module_$(_override_modules)")); - "$(sys.workdir)/modules/$(_custom_template_modules)" -> { "ENT-10793" } + "$(moduledir)/$(_custom_template_modules)" -> { "ENT-10793" } comment => "We want to render mustache templated modules", handle => "cfe_internal_update_policy_files_custom_template_modules", template_method => "mustache", @@ -848,7 +861,7 @@ bundle agent modules_presence perms => u_mo("500", "root"), if => fileexists("$(_custom_template_dir)$(_custom_template_modules).mustache"); - "$(sys.workdir)/modules" + "$(moduledir)" comment => "Copy any non-packages modules", handle => "cfe_internal_update_policy_files_nonpackages_modules", copy_from => u_cp("$(sys.inputdir)$(const.dirsep)modules"), @@ -862,14 +875,13 @@ bundle agent modules_presence reports: DEBUG:: "_override_dir: $(_override_dir)"; - "_package_paths_tmp: $(with)" with => storejson(_package_paths_tmp); + "_package_paths: $(with)" with => storejson(_package_paths); "_not_vendored_modules_pathname_regex: $(_not_vendored_modules_pathname_regex)"; "_vendored_modules: $(_vendored_modules)"; "_override_modules: $(_override_modules)"; "_vendored_dir: $(_vendored_dir)"; "_vendored_paths: $(_vendored_paths)"; "_override_dir: $(_override_dir)"; - "_package_paths: $(_package_paths)"; "override_vendored_module_$(_vendored_modules)" if => "override_vendored_module_$(_vendored_modules)"; "override_module_$(_override_modules)" diff --git a/ci/bootstrap-policy-run.Dockerfile b/ci/bootstrap-policy-run.Dockerfile deleted file mode 100644 index fc91a79f52..0000000000 --- a/ci/bootstrap-policy-run.Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM alpine -RUN apk update && apk add cfengine make automake autoconf git diff --git a/ci/bootstrap-policy-run.cfremote.Dockerfile b/ci/bootstrap-policy-run.cfremote.Dockerfile new file mode 100644 index 0000000000..500318a04e --- /dev/null +++ b/ci/bootstrap-policy-run.cfremote.Dockerfile @@ -0,0 +1,5 @@ +ARG CFENGINE_VERSION="master" +FROM debian +RUN apt update && apt upgrade -y +RUN apt install -y pipx sudo make automake autoconf git procps python3 +RUN pipx install cf-remote diff --git a/ci/bootstrap-policy-run.sh b/ci/bootstrap-policy-run.sh index b2143e3242..ab10f38b1c 100755 --- a/ci/bootstrap-policy-run.sh +++ b/ci/bootstrap-policy-run.sh @@ -1,8 +1,16 @@ #!/usr/bin/env sh set -ex -./autogen.sh --prefix=/var/lib/cfengine +if [ -f ../core/ci/install.sh ]; then + ../core/ci/install.sh +else + # here we use community so that masterfiles has less errors when bootstrapping as it expects an enterprise hub with the -nova package + PATH=/root/.local/bin:$PATH cf-remote --version "$CFENGINE_VERSION" install --edition community --clients localhost +fi +./autogen.sh make install +export PATH=/var/cfengine/bin:$PATH which cf-agent +ps -efl | grep cf- # debug cf-serverd already running somehow? cf-agent -IB $(hostname -i) | tee bootstrap.log cf-agent -KIf update.cf | tee update.log cf-agent -KI | tee promise.log diff --git a/ci/bootstrap-policy-run.source.Dockerfile b/ci/bootstrap-policy-run.source.Dockerfile new file mode 100644 index 0000000000..1e51578ac2 --- /dev/null +++ b/ci/bootstrap-policy-run.source.Dockerfile @@ -0,0 +1,6 @@ +ARG CFENGINE_VERSION="master" +FROM debian +COPY core /core +RUN apt update && apt upgrade -y +# need python3 for apt_get package module to avoid errors +RUN apt install -y sudo make automake autoconf git python3 procps diff --git a/ci/docker-bootstrap-policy-run.sh b/ci/docker-bootstrap-policy-run.sh index 6db6215712..1ed8b5cd57 100755 --- a/ci/docker-bootstrap-policy-run.sh +++ b/ci/docker-bootstrap-policy-run.sh @@ -5,27 +5,41 @@ set -ex COMPUTED_ROOT="$(readlink -e "$(dirname "$0")/../../")" # NTECH_ROOT should be the same, but if available use it so user can do their own thing. NTECH_ROOT=${NTECH_ROOT:-$COMPUTED_ROOT} +CFENGINE_VERSION=${1:-master} +export CFENGINE_VERSION cd "${NTECH_ROOT}/masterfiles" # cleanup rm -f update.log bootstrap.log promise.log -if docker ps | grep mpf; then - docker stop mpf +image_name=bootstrap-${CFENGINE_VERSION} +if docker ps | grep "$image_name"; then + docker stop "$image_name" fi -if docker ps -a | grep mpf; then - docker ps -a | grep mpf | awk '{print $1}' | xargs docker rm +if docker ps -a | grep "$image_name"; then + docker ps -a | grep "$image_name" | awk '{print $1}' | xargs docker rm fi -if docker images | grep mpf; then - docker rmi mpf +if docker images | grep "$image_name"; then + docker rmi "$image_name" +fi + +if [ -d "${NTECH_ROOT}"/core ]; then + docker build -t "$image_name" --build-arg CFENGINE_VERSION="$CFENGINE_VERSION" -f "${NTECH_ROOT}"/masterfiles/ci/bootstrap-policy-run.source.Dockerfile "${NTECH_ROOT}" +else + docker build -t "$image_name" --build-arg CFENGINE_VERSION="$CFENGINE_VERSION" -f "${NTECH_ROOT}"/masterfiles/ci/bootstrap-policy-run.cfremote.Dockerfile "${NTECH_ROOT}" fi # run the test -docker build -t mpf -f "${NTECH_ROOT}"/masterfiles/ci/bootstrap-policy-run.Dockerfile "${NTECH_ROOT}"/masterfiles -docker run --workdir /mpf --volume "${NTECH_ROOT}"/masterfiles:/mpf --tty mpf sh /mpf/ci/bootstrap-policy-run.sh -if grep error *.log; then +docker run -e CFENGINE_VERSION --workdir /masterfiles --volume "${NTECH_ROOT}"/masterfiles:/masterfiles --tty "$image_name" sh /masterfiles/ci/bootstrap-policy-run.sh + +if grep error ./*.log; then echo "fail" exit 1 else echo "success" fi + +if [ ! -f bootstrap.log ] || [ ! -f promise.log ] || [ ! -f update.log ]; then + echo "No log files. Fail." + exit 23 +fi diff --git a/controls/cf_serverd.cf b/controls/cf_serverd.cf index e766bceed0..973633aa08 100644 --- a/controls/cf_serverd.cf +++ b/controls/cf_serverd.cf @@ -68,15 +68,18 @@ body server control allowusers => { @(def.control_server_allowusers) }; + # In 3.10 the quotation is properly closed when EOF is reached. It is left + # open so that arguments (like -K and --remote-bundles) can be appended. + # 3.10.x does not automatically append -I -Dcfruncommand + windows:: - cfruncommand => "$(sys.cf_agent) -I -D cf_runagent_initiated -f \"$(sys.update_policy_path)\" & - $(sys.cf_agent) -I -D cf_runagent_initiated"; - !windows:: + # /s removes the first and last quote characters and aids in specifying paths with surrounding quotes + cfruncommand => "$(def.cf_runagent_shell) /s /c \" + $(sys.cf_agent) -I -D cf_runagent_initiated -f $(sys.update_policy_path) & + $(sys.cf_agent) -I -D cf_runagent_initiated"; - # In 3.10 the quotation is properly closed when EOF is reached. It is left - # open so that arguments (like -K and --remote-bundles) can be appended. - # 3.10.x does not automatically append -I -Dcfruncommand + !windows:: cfruncommand => "$(def.cf_runagent_shell) -c \' $(sys.cf_agent) -I -D cf_runagent_initiated -f $(sys.update_policy_path) ; @@ -172,7 +175,7 @@ bundle server mpf_default_access_rules() shortcut => "hub_cmdb", admit_keys => { $(connection.key) }; - !windows:: + any:: "$(def.cf_runagent_shell)" -> { "ENT-6673" } handle => "server_access_grant_access_shell_cmd", comment => "Grant access to shell for cfruncommand", diff --git a/controls/def.cf b/controls/def.cf index dac644925b..22609da8c7 100644 --- a/controls/def.cf +++ b/controls/def.cf @@ -275,16 +275,36 @@ bundle common def int => "30", if => not( isvariable( "control_agent_maxconnections" ) ); - # Because in some versions of cfengine bundlesequence in body common - # control does not support does not support iteration over data containers - # we must first pick out the bundles into a shallow container that we can - # then get a regular list from using getvalues(). + # Common Controls - "tbse" data => mergedata( "def.control_common_bundlesequence_end" ); - "bundlesequence_end" slist => getvalues( tbse ); + # Because in some versions of cfengine bundlesequence in body common + # control does not support iteration over data containers we must first + # pick out the bundles into a shallow container that we can then get a + # regular list from using getvalues(). - "tbse" data => mergedata( "def.control_common_bundlesequence_classification" ); - "bundlesequence_classification" slist => getvalues( tbse ); + "bundlesequence_end" -> { "CFE-4855" } + slist => { }, + if => not( isvariable( "def.control_common_bundlesequence_end") ), + comment => concat( "We define an empty list so that the agent will not", + " error about undefined variable when ", + " def.bundlesequence_end is not defined." ); + "bundlesequence_end" -> { "CFE-4855" } + slist => getvalues( mergedata( "def.control_common_bundlesequence_end" ) ), + comment => concat( "We define bundlesequence_end from Augments if it's", + " available. This allows for customization without", + " modifying the vendored policy." ); + + "bundlesequence_classification" -> { "CFE-4855" } + slist => { }, + if => not( isvariable( "def.control_common_bundlesequence_classification") ), + comment => concat( "We define an empty list so that the agent will not", + " error about undefined variable when ", + " def.bundlesequence_classification is not defined." ); + "bundlesequence_classification" -> { "CFE-4855" } + slist => getvalues( mergedata( "def.control_common_bundlesequence_classification" ) ), + comment => concat( "We define bundlesequence_classification from Augments if it's", + " available. This allows for customization without", + " modifying the vendored policy." ); "control_common_ignore_missing_bundles" -> { "CFE-2773" } string => ifelse( strcmp( $(control_common_ignore_missing_bundles), "true" ), @@ -392,6 +412,18 @@ bundle common def " it's value will be used for allowtlsversion in body server", " control. Else the binary default will be used."); + "control_common_protocol_version_defined" -> { "CFE-4543" } + expression => isvariable( "default:def.control_common_protocol_version" ), + comment => concat( "Defines the protocol version to use for all outgoing", + " connections.", + # It's challenging to keep this aligned with the core agent code + # cf-promises --syntax-description=json | jq -r '.bodyTypes.common.attributes.protocol_version.range' + " (1|classic|2|tls|3|cookie|4|filestream|latest)" ); + "control_common_system_log_level_defined" -> { "CFE-4452" } + expression => isvariable( "default:def.control_common_system_log_level" ), + comment => concat( "The minimum log level required for log messages to go to the", + " system log (e.g. syslog or Windows Event Log).", + " (critical|error|warning|notice|info)" ); vars: debian:: @@ -498,6 +530,12 @@ bundle common def comment => "Define path to shell used by cf-runagent", handle => "common_def_vars_solaris_cf_runagent_shell"; + windows:: + "cf_runagent_shell" + string => "${sys.winsysdir}${const.dirsep}cmd.exe", + comment => "Define path to shell used by cf-runagent", + handle => "common_def_vars_windows_cf_runagent_shell"; + !(windows|solaris):: "cf_runagent_shell" string => "/bin/sh", @@ -558,7 +596,8 @@ bundle common def "log_dir[package_logs]" string => "$(const.dirsep)cfengine_package_logs"; enterprise.am_policy_hub:: - "log_dir[application]" string => "$(sys.workdir)/httpd/htdocs/application/logs"; + "log_dir[mission_portal]" string => "$(sys.workdir)/httpd/logs"; + "log_dir[application]" string => "$(sys.workdir)/httpd/logs/application"; any:: "cfe_log_dirs" slist => getvalues( log_dir ); diff --git a/controls/update_def.cf.in b/controls/update_def.cf.in index 371541b15a..104698bdf2 100644 --- a/controls/update_def.cf.in +++ b/controls/update_def.cf.in @@ -5,6 +5,19 @@ bundle common update_def any:: "sys_policy_hub_port_exists" expression => isvariable("sys.policy_hub_port"); + "control_common_protocol_version_defined" -> { "CFE-4543" } + expression => isvariable( "default:def.control_common_protocol_version" ), + comment => concat( "Defines the protocol version to use for all outgoing", + " connections.", + # It's challenging to keep this aligned with the core agent code + # cf-promises --syntax-description=json | jq -r '.bodyTypes.common.attributes.protocol_version.range' + " (1|classic|2|tls|3|cookie|4|filestream|latest)" ); + "control_common_system_log_level_defined" -> { "CFE-4452" } + expression => isvariable( "default:def.control_common_system_log_level" ), + comment => concat( "The minimum log level required for log messages to go to the", + " system log (e.g. syslog or Windows Event Log).", + " (critical|error|warning|notice|info)" ); + vars: "hub_binary_version" -> { "ENT-10664" } data => data_regextract( diff --git a/inventory/linux.cf b/inventory/linux.cf index cfacd3cebb..268f2bc28b 100644 --- a/inventory/linux.cf +++ b/inventory/linux.cf @@ -32,32 +32,29 @@ bundle common inventory_linux "proc_1_process" string => filestat($(proc_1_cmdline), "linktarget"); any:: - "proc_routes" data => data_readstringarrayidx("/proc/net/route", + "proc_routes" data => data_readstringarrayidx("/proc/$(this.promiser_pid)/net/route", "#[^\n]*","\s+",40,4k), - if => fileexists("/proc/net/route"); + if => fileexists("/proc/$(this.promiser_pid)/net/route"); "routeidx" slist => getindices("proc_routes"); "dgw_ipv4_iface" string => "$(proc_routes[$(routeidx)][0])", comment => "Name of the interface where default gateway is routed", if => strcmp("$(proc_routes[$(routeidx)][1])", "00000000"); linux:: - "nfs_servers" -> { "CFE-3259" } - comment => "NFS servers (to list hosts impacted by NFS outages)", - slist => maplist( regex_replace( $(this) , ":.*", "", "g"), - # NFS server is before the colon (:), that's all we want - # e.g., nfs.example.com:/vol/homedir/user1 /home/user1 ... - # ^^^^^^^^^^^^^^^ - grep( ".* nfs .*", - readstringlist("/proc/mounts", "", "\n", inf, inf) - ) - ), - if => fileexists( "/proc/mounts" ); + "mounts" string => "/proc/$(this.promiser_pid)/mounts"; + "nfs_mounts" + slist => grep( ".* nfs .*", + readstringlist("$(mounts)", "", "\n", inf, inf) ), + if => and( not( isvariable( "$(this.promiser)" ) ), + fileexists( "$(mounts)" ) ); - "nfs_server[$(nfs_servers)]" - string => "$(nfs_servers)", - meta => { "inventory", "attribute_name=NFS Server" }; - + "nfs_server[$(with)]" -> { "CFE-3259", "ENT-13210", "ENT-13223" } + with => regex_replace( "$(nfs_mounts)", ":.*", "", "g" ), + handle => "cfe_internal_inventory_mounted_nfs_server", + string => "$(with)", + meta => { "inventory", "attribute_name=NFS Server" }, + if => not( isvariable( "$(this.promiser)" ) ); classes: @@ -77,8 +74,8 @@ bundle common inventory_linux " acceptable ( 3.x or 2.4 or greater ) for package", " modules. We use this guard to prevent errors", " related to missing python modules."), - expression => returnszero("$(sys.bindir)/cfengine-selected-python -V 2>&1 | grep ^Python | cut -d' ' -f 2 | ( IFS=. read v1 v2 v3 ; [ $v1 -ge 3 ] || [ $v1 -eq 2 -a $v2 -ge 4 ] )", - useshell); + expression => returnszero("$(sys.bindir)/cfengine-selected-python -c 'import sys; exit(sys.version_info < (2, 4))'", + noshell); } bundle monitor measure_entropy_available diff --git a/lib/feature.cf b/lib/feature.cf index 4aa4744c63..048f548ac0 100644 --- a/lib/feature.cf +++ b/lib/feature.cf @@ -80,6 +80,7 @@ bundle agent feature_test body classes feature_cancel(x) # @brief Undefine class `x` when promise is kept or repaired +# # Used internally by bundle `feature` { cancel_kept => { "$(x)" }; diff --git a/lib/files.cf b/lib/files.cf index 5122e4e32d..732dd261fa 100644 --- a/lib/files.cf +++ b/lib/files.cf @@ -437,25 +437,33 @@ bundle edit_line set_variable_values_ini(tab, sectionName) # Be careful if the index string contains funny chars "cindex[$(index)]" string => canonify("$(index)"); + "_escaped_section" string => escape("$(sectionName)"); classes: "edit_$(cindex[$(index)])" not => strcmp("$($(tab)[$(sectionName)][$(index)])","dontchange"), comment => "Create conditions to make changes"; + "section_$(sectionName)_exists" + expression => regline("^\[$(_escaped_section)\]", "$(edit.filename)"), + if => fileexists("$(edit.filename)"), + comment => "Check if the section header already exists in the file"; + field_edits: # If the line is there, but commented out, first uncomment it "#+\s*$(index)\s*=.*" select_region => INI_section(escape("$(sectionName)")), edit_field => col("\s*=\s*","1","$(index)","set"), - if => "edit_$(cindex[$(index)])"; + if => and("edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")); # match a line starting like the key something "\s*$(index)\s*=.*" edit_field => col("\s*=\s*","2","$($(tab)[$(sectionName)][$(index)])","set"), select_region => INI_section(escape("$(sectionName)")), classes => results("bundle", "set_variable_values_ini_not_$(cindex[$(index)])"), - if => "edit_$(cindex[$(index)])"; + if => and("edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")); insert_lines: "[$(sectionName)]" @@ -464,7 +472,16 @@ bundle edit_line set_variable_values_ini(tab, sectionName) "$(index)=$($(tab)[$(sectionName)][$(index)])" select_region => INI_section(escape("$(sectionName)")), - if => "!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired).edit_$(cindex[$(index)])"; + if => and("!(set_variable_values_ini_not_$(cindex[$(index)])_kept|set_variable_values_ini_not_$(cindex[$(index)])_repaired)", + "edit_$(cindex[$(index)])", + canonify("section_$(sectionName)_exists")), + handle => "insert_key_in_existing_section_$(sectionName)_$(cindex[$(index)])"; + + "$(index)=$($(tab)[$(sectionName)][$(index)])" + location => after("^\[$(_escaped_section)\]"), + if => and("edit_$(cindex[$(index)])", + not(canonify("section_$(sectionName)_exists"))), + handle => "insert_key_in_new_section_$(sectionName)_$(cindex[$(index)])"; } @@ -1243,7 +1260,8 @@ body edit_field fstab_options(newval, method) body edit_field quoted_var(newval,method) # @brief Edit the quoted value of the matching line # @param newval The new value -# @param method The method by which to edit the field +# @param method The method by which to edit the field (append|prepend|alphanum|set|delete) +# Ref https://docs.cfengine.com/latest/reference-promise-types-files-edit_line-field_edits.html#field_operation { field_separator => "\""; select_field => "2"; diff --git a/lib/packages.cf b/lib/packages.cf index 666bc8d278..2122d4fa62 100644 --- a/lib/packages.cf +++ b/lib/packages.cf @@ -100,6 +100,25 @@ body package_module apt_get @endif } +body package_module dnf_group +# @brief manage dnf package groups +# +# **Example:** +# +# ```cf3 +# "development" +# policy => "present", +# package_module => dnf_group, +# options => { "group_package_types=optional", +# "install_weak_deps=false" }, +# version => "latest"; # Upgrade group packages +# ``` +{ + query_installed_ifelapsed => "$(package_module_knowledge.query_installed_ifelapsed)"; + query_updates_ifelapsed => "$(package_module_knowledge.query_updates_ifelapsed)"; + interpreter => "$(sys.bindir)/cfengine-selected-python"; +} + body package_module zypper { query_installed_ifelapsed => "$(package_module_knowledge.query_installed_ifelapsed)"; @@ -164,6 +183,17 @@ body package_module yum @endif } +body package_module dnf +# @brief Define details used when interfacing with dnf +{ + query_installed_ifelapsed => "$(package_module_knowledge.query_installed_ifelapsed)"; + query_updates_ifelapsed => "$(package_module_knowledge.query_updates_ifelapsed)"; + #default_options => {}; +@if minimum_version(3.12.2) + interpreter => "$(sys.bindir)/cfengine-selected-python"; +@endif +} + body package_module slackpkg # @brief Define details used when interfacing with slackpkg { @@ -414,9 +444,9 @@ bundle common pip_knowledge vars: "call_pip" string => "$(paths.path[pip])"; - "pip_list_name_regex" string => "^([[:alnum:]-_]+)\s\([\d.]+\)"; - "pip_list_version_regex" string => "^[[:alnum:]-_]+\s\(([\d.]+)\)"; - "pip_installed_regex" string => "^([[:alnum:]-_]+\s\([\d.]+\))"; + "pip_list_name_regex" string => "^([[:alnum:]\-_]+)\s\([\d.]+\)"; + "pip_list_version_regex" string => "^[[:alnum:]\-_]+\s\(([\d.]+)\)"; + "pip_installed_regex" string => "^([[:alnum:]\-_]+\s\([\d.]+\))"; } bundle common solaris_knowledge diff --git a/lib/paths.cf b/lib/paths.cf index 434a17c836..a9d849c035 100644 --- a/lib/paths.cf +++ b/lib/paths.cf @@ -168,6 +168,7 @@ bundle common paths "path[find]" string => "/usr/bin/find"; "path[grep]" string => "/usr/bin/grep"; "path[ls]" string => "/usr/bin/ls"; + "path[lssrc]" string => "/usr/bin/lssrc"; "path[netstat]" string => "/usr/bin/netstat"; "path[oslevel]" string => "/usr/bin/oslevel"; "path[ping]" string => "/usr/bin/ping"; @@ -175,10 +176,12 @@ bundle common paths "path[printf]" string => "/usr/bin/printf"; "path[sed]" string => "/usr/bin/sed"; "path[sort]" string => "/usr/bin/sort"; + "path[startsrc]" string => "/usr/bin/startsrc"; + "path[stopsrc]" string => "/usr/bin/stopsrc"; "path[tr]" string => "/usr/bin/tr"; "path[yum]" string => "/usr/bin/yum"; - archlinux:: + archlinux|manjaro:: "path[awk]" string => "/usr/bin/awk"; "path[bc]" string => "/usr/bin/bc"; @@ -215,9 +218,14 @@ bundle common paths "path[tr]" string => "/usr/bin/tr"; # "path[pacman]" string => "/usr/bin/pacman"; + "path[pamac]" string => "/usr/bin/pamac"; "path[yaourt]" string => "/usr/bin/yaourt"; "path[useradd]" string => "/usr/bin/useradd"; + "path[userdel]" string => "/usr/bin/userdel"; + "path[usermod]" string => "/usr/bin/usermod"; "path[groupadd]" string => "/usr/bin/groupadd"; + "path[groupdel]" string => "/usr/bin/groupdel"; + "path[groupmod]" string => "/usr/bin/groupmod"; "path[ip]" string => "/usr/bin/ip"; "path[ifconfig]" string => "/usr/bin/ifconfig"; "path[journalctl]" string => "/usr/bin/journalctl"; @@ -367,10 +375,13 @@ bundle common paths "path[df]" string => "/bin/df"; "path[diff]" string => "/usr/bin/diff"; "path[dig]" string => "/usr/bin/dig"; + "path[dmidecode]" string => "/usr/sbin/dmidecode"; + "path[dmsetup]" string => "/usr/sbin/dmsetup"; "path[domainname]" string => "/bin/domainname"; "path[echo]" string => "/bin/echo"; "path[egrep]" string => "/bin/egrep"; "path[ethtool]" string => "/usr/sbin/ethtool"; + "path[fdisk]" string => "/usr/sbin/fdisk"; "path[find]" string => "/usr/bin/find"; "path[free]" string => "/usr/bin/free"; "path[getenforce]" string => "/usr/sbin/getenforce"; @@ -380,7 +391,10 @@ bundle common paths "path[iptables]" string => "/sbin/iptables"; "path[iptables_save]" string => "/sbin/iptables-save"; "path[ls]" string => "/bin/ls"; - "path[lsof]" string => "/usr/sbin/lsof"; + "path[lshw]" string => "/usr/sbin/lshw"; + "path[lsof]" string => ifelse( "redhat_7|redhat_6", "/usr/sbin/lsof", + "/usr/bin/lsof" + ); "path[netstat]" string => "/bin/netstat"; "path[nologin]" string => "/sbin/nologin"; "path[ping]" string => "/usr/bin/ping"; @@ -462,10 +476,12 @@ bundle common paths "path[diff]" string => "/usr/bin/diff"; "path[dig]" string => "/usr/bin/dig"; "path[dmidecode]" string => "/usr/sbin/dmidecode"; + "path[dmsetup]" string => "/usr/sbin/dmsetup"; "path[domainname]" string => "/bin/domainname"; "path[echo]" string => "/bin/echo"; "path[egrep]" string => "/bin/egrep"; "path[ethtool]" string => "/sbin/ethtool"; + "path[fdisk]" string => "/usr/sbin/fdisk"; "path[find]" string => "/usr/bin/find"; "path[free]" string => "/usr/bin/free"; "path[getenforce]" string => "/usr/sbin/getenforce"; @@ -475,6 +491,7 @@ bundle common paths "path[iptables]" string => "/sbin/iptables"; "path[iptables_save]" string => "/sbin/iptables-save"; "path[ls]" string => "/bin/ls"; + "path[lshw]" string => "/usr/bin/lshw"; "path[lsof]" string => "/usr/bin/lsof"; "path[netstat]" string => "/bin/netstat"; "path[nologin]" string => "/usr/sbin/nologin"; @@ -524,8 +541,6 @@ bundle common paths "path[logger]" string => "/usr/bin/logger"; opensuse:: - "path[ls]" string => "/usr/bin/ls"; - "path[lsof]" string => "/usr/bin/lsof"; "path[awk]" string => "/usr/bin/awk"; "path[cat]" string => "/usr/bin/cat"; "path[cksum]" string => "/usr/bin/cksum"; diff --git a/lib/services.cf b/lib/services.cf index 482e54709f..d2876bfc1d 100644 --- a/lib/services.cf +++ b/lib/services.cf @@ -111,11 +111,13 @@ bundle agent standard_services(service,state) # # Else, if chkconfig is present, it will be used. # -# Else, if the service command is available, if will be used. +# Else, if the service command is available, it will be used. # -# Else, if the svcadm command is available, if will be used. Note you +# Else, if the svcadm command is available, it will be used. Note you # have to supply the full SMF service identifier. # +# Else, if lssrc command is available (AIX), it will be used. +# # Else, control is passed to `classic_services`. # # Note you do **not** have to call this bundle from `services` @@ -170,7 +172,9 @@ bundle agent standard_services(service,state) "chkconfig" expression => "!systemd._stdlib_path_exists_chkconfig"; "sysvservice" expression => "!systemd.!chkconfig._stdlib_path_exists_service"; "smf" expression => "!systemd.!chkconfig.!sysvservice._stdlib_path_exists_svcadm"; - "fallback" expression => "!systemd.!chkconfig.!sysvservice.!smf"; + # AIX System Resource Controller https://www.ibm.com/docs/en/aix/7.2?topic=concepts-system-resource-controller + "aix_src" expression => "_stdlib_path_exists_lssrc"; + "fallback" expression => "!systemd.!chkconfig.!sysvservice.!smf.!aix_src"; "have_init" expression => fileexists($(init)); @@ -268,6 +272,8 @@ bundle agent standard_services(service,state) classes => kept_successful_command; methods: + aix_src:: + "aix_service" usebundle => aix_services($(service), $(state)); fallback:: "classic" usebundle => classic_services($(service), $(state)); @@ -334,7 +340,7 @@ bundle agent systemd_services(service,state) # * restart - Service should be restarted, no promise about state on boot made. # * reload - Service should be reloaded, no promise about state on boot made. # * enabled - Service should be enabled, no promise about state on boot made. -# * disabled - Service should be reloaded, no promise about state on boot made. +# * disabled - Service should be disabled, no promise about state on boot made. # * start - Service should be running, service should be started on boot (active + enabled). # * stop - Service should not be running, service should not be started on boot (inactive + disabled). # @@ -348,8 +354,8 @@ bundle agent systemd_services(service,state) # # # Explicitly use `systemd_services` # "sshd" -# service_policy => "running", -# service_policy => "systemd_services"; +# service_policy => "enabled", +# service_method => systemd_services; # ``` # # Alternatively, since services promises are an abstraction around bundles, the service state can be promised via a methods type promise. @@ -363,7 +369,7 @@ bundle agent systemd_services(service,state) vars: systemd:: "call_systemctl" - string => "$(paths.systemctl) --no-ask-password --global --system"; + string => "$(paths.systemctl) --no-ask-password --system"; "systemd_properties" string => "-pLoadState,CanStop,UnitFileState,ActiveState,LoadState,CanStart,CanReload"; @@ -446,7 +452,7 @@ bundle agent systemd_services(service,state) if => "action_custom"; reports: - systemd.service_notfound.(start|restart|reload).(inform_mode|verbose_mode):: + systemd.service_notfound.(action_start|action_restart|action_reload).(inform_mode|verbose_mode):: "$(this.bundle): Could not find service: $(service)"; } @@ -1098,3 +1104,74 @@ bundle agent classic_services(service,state) "DEBUG $(this.bundle): The baseinit is NOT provided, using default" if => not(isvariable("baseinit[$(service)]")); } + +body service_method aix_service_method +{ + service_bundle => aix_services("$(this.promiser)","$(this.service_policy)"); +} + +# example of querying state of a service on AIX +# +# bash-5.1# /usr/bin/lssrc -s sendmail +# Subsystem Group PID Status +# sendmail mail 5308762 active +# +# according to https://docs.cfengine.com/docs/3.24/reference-promise-types-services.html#service_policy +# state can be one of start, stop, enable, disable, restart and reload. +# disable/enable might be available for services in /etc/inetd.conf +# e.g. https://www.ibm.com/support/pages/ibm-aix-how-disable-rsh-and-rlogin-services +# /usr/bin/lssrc -t login, comment out lines in /etc/inetd.conf +# +# Note: This service method bundle does NOT handle inetd services like rsh/rlogin +# only subsystems aka those services listed with /usr/bin/lssrc -a +# https://www.ibm.com/docs/en/aix/7.3?topic=daemons-subsystems-subservers +# +# Also note this from the lssrc man page: +# The lssrc command output can sometimes show two entries for a particular daemon. One instance will be active and another instance will be +# inoperative. This can happen if the subsystem is modified (using the mkssys command or chssys command) without stopping the subsystem. The +# original subsystem will remain active and the modified instance will be inoperative until the subsystem is stopped and started again. +# +# Additional output may appear prefixed with Q: for example if it takes some time to change the service state: +# +# notice: Q: "...in/stopsrc -s s": 0513-056 Timeout waiting for command response. If you specified a foreign host, +# Q: "...in/stopsrc -s s": see the /etc/inittab file on the foreign host to verify that the SRC daemon +# Q: "...in/stopsrc -s s": (srcmstr) was started with the -r flag to accept remote requests. +# Q: "...in/stopsrc -s s": 0513-059 The sendmail Subsystem has been started. Subsystem PID is 13042068. +# +# Another failure case. Likely on next agent run (default of 5 minutes) the service will have stopped or we will try again. +# error: Finished command related to promiser '/usr/bin/stopsrc -s sendmail' -- an error occurred, returned 1 +# notice: Q: "...in/stopsrc -s s": 0513-056 Timeout waiting for command response. If you specified a foreign host, +# Q: "...in/stopsrc -s s": see the /etc/inittab file on the foreign host to verify that the SRC daemon +# Q: "...in/stopsrc -s s": (srcmstr) was started with the -r flag to accept remote requests. +bundle agent aix_services(service, desired_state) +{ + vars: + # current state can be: active, inoperative, stopping + "current_state" string => execresult("$(paths.lssrc) -s $(service) | tail -1 | awk '{print $NF}'", useshell); + + classes: + "needs_start" expression => and( + strcmp("$(current_state)", "inoperative"), + strcmp("$(desired_state)", "start") + ); + "needs_restart" expression => and( + strcmp("$(desired_state)", "restart") + ); + "needs_stop" expression => and( + strcmp("$(current_state)", "active"), + strcmp("$(desired_state)", "stop") + ); + + commands: + needs_start:: + "$(paths.startsrc) -s $(service)"; + needs_restart:: + "$(paths.stopsrc) -s $(service); $(paths.startsrc) -s $(service)" + contain => in_shell; + needs_stop:: + "$(paths.stopsrc) -s $(service)"; + + reports: + DEBUG:: + "Current state of service $(service) is $(current_state). Desired state is $(desired_state)."; +} diff --git a/modules/packages/vendored/dnf.mustache b/modules/packages/vendored/dnf.mustache new file mode 100644 index 0000000000..5b496e340f --- /dev/null +++ b/modules/packages/vendored/dnf.mustache @@ -0,0 +1,533 @@ +#!/usr/bin/env python3 +# Note: See lib/packages.cf `package_module dnf` use of the +# `interpreter` attribute to use cfengine-selected-python. + +"""DNF Package Module for CFEngine. + +This module provides a Python-based interface between CFEngine and the DNF package +manager, supporting package installation, removal, updates, and queries on RPM-based +Linux distributions. + +The module implements the CFEngine package module protocol v1, communicating via +stdin/stdout using a key=value format. + +Supported Operations: + - supports-api-version: Report API version compatibility + - get-package-data: Extract metadata from packages or RPM files + - list-installed: List all installed packages (uses RPM library for speed) + - list-updates: Check for available package updates (online/offline) + - list-updates-local: Check for updates using local cache only + - repo-install: Install packages from configured repositories + - file-install: Install packages from local RPM files + - remove: Uninstall packages from the system + +Configuration: + The module accepts options via stdin in the format: + - options=enablerepo= + - options=disablerepo= + - options== + +Security Notes: + - File paths are validated for existence before processing + - DNF operations run with assumeyes=True to prevent interactive prompts + - All operations return proper exit codes (0=success, 1=error, 2=unsupported) + +Performance Optimizations: + - Uses RPM library directly for listing installed packages (faster than DNF) + - Supports offline mode using cached repository data + - Early returns when no packages are provided to avoid expensive initialization + +Error Handling: + - Exceptions are caught and reported via ErrorMessage= format + - Resource cleanup is performed using try/finally blocks where appropriate + +Dependencies: + - python3 + - python3-dnf + - python3-rpm + +Author: CFEngine AS +License: MIT +""" + +from typing import Dict, List, Tuple, Optional, Any, Union +import sys +import os +import logging +import dnf +import rpm + +# Exit codes +EXIT_SUCCESS = 0 +EXIT_ERROR = 1 +EXIT_UNSUPPORTED = 2 + +# Protocol constants +PROTOCOL_VERSION = "1" +DEFAULT_EPOCH = "0" + +# Configuration constants +MAX_INPUT_LINES = 10000 # Prevent DoS from excessive input +DEFAULT_ASSUME_YES = True # Non-interactive mode + + +def _s(val: Union[bytes, str, Any]) -> str: + """Convert bytes to string, pass through other types as str(). + + Args: + val: Value to convert (bytes, str, or other) + + Returns: + String representation of the value + """ + return val.decode("utf-8") if isinstance(val, bytes) else str(val) + + +# Protocol keys (input) +KEY_OPTIONS = "options" +KEY_NAME = "Name" +KEY_FILE = "File" +KEY_VERSION = "Version" +KEY_ARCHITECTURE = "Architecture" + +# Protocol keys (output) +KEY_ERROR_MESSAGE = "ErrorMessage" +KEY_PACKAGE_TYPE = "PackageType" + +# Package type values +PACKAGE_TYPE_FILE = "file" +PACKAGE_TYPE_REPO = "repo" + +# Repository option keys +OPT_ENABLE_REPO = "enablerepo" +OPT_DISABLE_REPO = "disablerepo" +OPT_ALLOW_DOWNGRADE = "allow_downgrade" + +# Boolean string values +BOOL_TRUE = "true" +BOOL_FALSE = "false" + +# Command line option prefix +CLI_OPTION_PREFIX = "--" + + +def _get_package_info_from_file(file_path: str) -> Dict[str, str]: + """Extract package information from an RPM file using the python-rpm library. + + Args: + file_path: Path to the RPM file + + Returns: + Dictionary containing package metadata (name, version, release, arch, epoch, full_version) + + Raises: + Exception: If RPM header cannot be read + """ + ts = rpm.TransactionSet() + try: + with open(file_path, "rb") as f: + hdr = ts.hdrFromFdno(f.fileno()) + except Exception as e: + raise Exception(f"Failed to read RPM header from {file_path}: {e}") + + name = _s(hdr[rpm.RPMTAG_NAME]) # type: ignore[attr-defined] + version = _s(hdr[rpm.RPMTAG_VERSION]) # type: ignore[attr-defined] + release = _s(hdr[rpm.RPMTAG_RELEASE]) # type: ignore[attr-defined] + arch = _s(hdr[rpm.RPMTAG_ARCH]) # type: ignore[attr-defined] + epoch = hdr[rpm.RPMTAG_EPOCH] # type: ignore[attr-defined] + epoch_str = DEFAULT_EPOCH if epoch is None else _s(epoch) + + return { + "name": name, + "version": version, + "release": release, + "arch": arch, + "epoch": epoch_str, + "full_version": f"{version}-{release}" if release else version, + } + + +def _get_base(with_repos: bool = True) -> dnf.Base: + """Create and configure a DNF base object. + + Args: + with_repos: Whether to load repository information + + Returns: + Configured DNF Base instance + """ + base = dnf.Base() + base.conf.assumeyes = DEFAULT_ASSUME_YES + if with_repos: + base.read_all_repos() + base.fill_sack(load_system_repo=True) + else: + base.fill_sack(load_system_repo=True, load_available_repos=False) + return base + + +def _parse_stdin() -> Tuple[List[Dict[str, str]], List[str]]: + """Parses stdin protocol input into (packages, options). + + Returns: + Tuple of (packages list, options list) where: + - packages: List of dicts with keys like 'name', 'file', 'version', 'arch' + - options: List of option strings + + Raises: + Exception: If input exceeds MAX_INPUT_LINES + """ + packages: List[Dict[str, str]] = [] + options: List[str] = [] + curr: Dict[str, str] = {} + for line_num, line in enumerate(sys.stdin): + if line_num >= MAX_INPUT_LINES: + raise Exception(f"Input exceeds maximum allowed lines ({MAX_INPUT_LINES})") + k, _, v = line.strip().partition("=") + if k == KEY_OPTIONS: + options.append(v) + elif k in (KEY_NAME, KEY_FILE): + if curr: + packages.append(curr) + curr = {k.lower(): v} + elif k == KEY_VERSION: + curr["version"] = v + elif k == KEY_ARCHITECTURE: + curr["arch"] = v + if curr: + packages.append(curr) + return packages, options + + +def _is_downgrade_allowed(options: List[str]) -> bool: + """Check if package downgrade is explicitly allowed via options. + + Args: + options: List of option strings + + Returns: + True if 'allow_downgrade=true' is found, False otherwise. + """ + for option in options: + option = option.strip() + if "=" in option: + key, value = [x.strip() for x in option.split("=", 1)] + if key == OPT_ALLOW_DOWNGRADE and value.lower() == BOOL_TRUE: + return True + return False + + +def _apply_options(base: dnf.Base, options: List[str]) -> None: + """Apply repository options and generic DNF configuration from the policy. + + Args: + base: DNF Base instance to configure + options: List of option strings in format "key=value" or "--flag" + """ + for option in options: + option = option.strip() + if "=" in option: + key, value = [x.strip() for x in option.split("=", 1)] + if key == OPT_ENABLE_REPO: + if base.repos is not None and value in base.repos: + base.repos[value].enable() + elif key == OPT_DISABLE_REPO: + if base.repos is not None and value in base.repos: + base.repos[value].disable() + elif key == OPT_ALLOW_DOWNGRADE: + pass # Handled separately + elif hasattr(base.conf, key): + attr = getattr(base.conf, key) + if not callable(attr): + conf_value: Union[bool, int, str] = value + if value.lower() == BOOL_TRUE: + conf_value = True + elif value.lower() == BOOL_FALSE: + conf_value = False + elif value.isdigit(): + conf_value = int(value) + try: + setattr(base.conf, key, conf_value) + except Exception as e: + logging.warning( + f"Failed to set config '{key}' to '{conf_value}': {e}" + ) + elif option.startswith(CLI_OPTION_PREFIX): + conf_key = option[len(CLI_OPTION_PREFIX) :].replace("-", "_") + if hasattr(base.conf, conf_key): + attr = getattr(base.conf, conf_key) + if not callable(attr): + try: + setattr(base.conf, conf_key, True) + except Exception as e: + logging.warning(f"Failed to set flag '{conf_key}': {e}") + + +def _do_transaction(base: dnf.Base) -> int: + """Resolves dependencies and executes the DNF transaction. + + Args: + base: DNF Base instance with pending transaction + + Returns: + 0 on success, non-zero on failure + """ + if not base.resolve(): + if not base.transaction: + return 0 + if not base.transaction: + return 0 + base.download_packages(list(base.transaction.install_set)) + base.do_transaction() + return 0 + + +def _resolve_spec(pkg: Dict[str, str]) -> Optional[str]: + """Resolve a package specification string from a package or file path. + + Args: + pkg: Package dictionary with keys like 'name', 'file', 'version', 'arch' + + Returns: + Package specification string or None if unable to resolve + + Raises: + Exception: If specified file does not exist + """ + name = pkg.get("name") + file_path = pkg.get("file") + + path = file_path or (name if name and name.startswith("/") else None) + if path: + if not os.path.exists(path): + raise Exception(f"Package file not found: {path}") + info = _get_package_info_from_file(path) + name = info["name"] + + if not name: + return None + spec = name + version = pkg.get("version") + if version: + spec += "-" + version + arch = pkg.get("arch") + if arch: + spec += "." + arch + return spec + + +def get_package_data() -> int: + """Get package metadata from stdin and output it. + + Returns: + 0 on success, 1 on failure + """ + packages, _ = _parse_stdin() + if not packages: + # Optimization: Avoid further processing if no package metadata is provided + return 1 + pkg = packages[0] + pkg_string = pkg.get("file") or pkg.get("name") + if not pkg_string: + return 1 + + if pkg_string.startswith("/"): + info = _get_package_info_from_file(pkg_string) + sys.stdout.write( + f"{KEY_PACKAGE_TYPE}={PACKAGE_TYPE_FILE}\n{KEY_NAME}={info['name']}\n{KEY_VERSION}={info['full_version']}\n{KEY_ARCHITECTURE}={info['arch']}\n" + ) + else: + sys.stdout.write( + f"{KEY_PACKAGE_TYPE}={PACKAGE_TYPE_REPO}\n{KEY_NAME}={pkg_string}\n" + ) + sys.stdout.flush() + return 0 + + +def list_installed() -> int: + """List all installed packages. + + Returns: + 0 on success, non-zero on failure + """ + _parse_stdin() # Protocol requires reading stdin even if unused + mi = rpm.TransactionSet().dbMatch() + for h in mi: + name = _s(h["name"]) + ver = _s(h["version"]) + rel = _s(h["release"]) + arch = _s(h["arch"]) + sys.stdout.write( + f"{KEY_NAME}={name}\n{KEY_VERSION}={ver}-{rel}\n{KEY_ARCHITECTURE}={arch}\n" + ) + sys.stdout.flush() + return 0 + + +def list_updates(online: bool) -> int: + """List available package updates. + + Args: + online: Whether to check online repositories or use cache only + + Returns: + 0 on success, non-zero on failure + """ + packages, options = _parse_stdin() + base = _get_base(with_repos=True) + base.conf.cacheonly = not online + _apply_options(base, options) + try: + base.upgrade_all() + if base.resolve() and base.transaction: + for tsi in base.transaction: + if tsi.action == dnf.transaction.PKG_UPGRADE: # type: ignore[attr-defined] + v_str = f"{tsi.pkg.version}-{tsi.pkg.release}" + sys.stdout.write( + f"{KEY_NAME}={tsi.pkg.name}\n{KEY_VERSION}={v_str}\n{KEY_ARCHITECTURE}={tsi.pkg.arch}\n" + ) + sys.stdout.flush() + finally: + base.close() + return EXIT_SUCCESS + + +def repo_install() -> int: + """Install packages from repositories. + + Returns: + 0 on success, non-zero on failure + """ + packages, options = _parse_stdin() + if not packages: + # Optimization: Avoid expensive DNF base initialization if no packages are provided + return 0 + base = _get_base(with_repos=True) + try: + _apply_options(base, options) + allow_downgrade = _is_downgrade_allowed(options) + for pkg in packages: + spec = _resolve_spec(pkg) + if spec: + try: + base.install(spec) + except Exception as install_err: + if allow_downgrade: + try: + base.downgrade(spec) + except Exception as downgrade_err: + logging.warning( + f"Failed to install or downgrade '{spec}': " + f"install error: {install_err}, downgrade error: {downgrade_err}" + ) + else: + logging.warning(f"Failed to install '{spec}': {install_err}") + return _do_transaction(base) + finally: + base.close() + + +def remove() -> int: + """Remove installed packages. + + Returns: + 0 on success, non-zero on failure + """ + packages, options = _parse_stdin() + if not packages: + # Optimization: Avoid DNF base initialization if no packages are provided + return 0 + base = _get_base(with_repos=False) + try: + _apply_options(base, options) + for pkg in packages: + spec = _resolve_spec(pkg) + if spec: + base.remove(spec) + return _do_transaction(base) + finally: + base.close() + + +def file_install() -> int: + """Install packages from local RPM files. + + Returns: + 0 on success, non-zero on failure + + Raises: + Exception: If package files are not found + """ + packages, options = _parse_stdin() + if not packages: + # Optimization: Avoid DNF base initialization if no packages are provided + return 0 + rpm_files: List[str] = [p["file"] for p in packages if p.get("file")] + if not rpm_files: + # Optimization: Avoid further processing if no file paths were successfully parsed + return 0 + for f in rpm_files: + if not os.path.exists(f): + raise Exception(f"Package file not found: {f}") + base = _get_base(with_repos=True) + try: + _apply_options(base, options) + for pkg in base.add_remote_rpms(rpm_files): + base.package_install(pkg) + return _do_transaction(base) + finally: + base.close() + + +def supports_api_version() -> int: + """Report the supported package module API version. + + Returns: + Always returns 0 + """ + sys.stdout.write(f"{PROTOCOL_VERSION}\n") + return 0 + + +def main() -> int: + """Main entry point for the DNF module. + + Returns: + Exit code: 0 for success, 1 for error, 2 for unsupported command + """ + if len(sys.argv) < 2: + return EXIT_UNSUPPORTED + + op: str = sys.argv[1] + + # Dispatch table for protocol commands + commands: Dict[str, Any] = { + "supports-api-version": supports_api_version, + "get-package-data": get_package_data, + "list-installed": list_installed, + "list-updates": lambda: list_updates(online=True), + "list-updates-local": lambda: list_updates(online=False), + "repo-install": repo_install, + "remove": remove, + "file-install": file_install, + } + + if op not in commands: + return EXIT_UNSUPPORTED + + try: + return commands[op]() + except Exception as e: + # Proper error output for CFEngine protocol + sys.stdout.write(f"{KEY_ERROR_MESSAGE}={str(e)}\n") + sys.stdout.flush() + return EXIT_ERROR + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.WARNING, + format="%(message)s", + handlers=[logging.StreamHandler(sys.stderr)], + ) + sys.exit(main()) diff --git a/modules/packages/vendored/dnf_group.mustache b/modules/packages/vendored/dnf_group.mustache new file mode 100644 index 0000000000..09698226b1 --- /dev/null +++ b/modules/packages/vendored/dnf_group.mustache @@ -0,0 +1,504 @@ +#!/usr/bin/python3 + +"""DNF Group Package Module for CFEngine. + +Supported Operations: + - supports-api-version, get-package-data, list-installed + - list-updates, list-updates-local (checks for package updates in groups) + - repo-install, remove, file-install + +Configuration (--setopt style): + Group options: + - options=group_package_types=mandatory|default|optional + + DNF/repo options: + - options=.enabled=1|0 + - options== (any base.conf attribute) + +Version Handling: + - version=latest: Upgrade group packages + +Dependencies: python3, python3-dnf +""" + +from typing import Dict, List, Tuple, Union +import sys +import logging +import os +import dnf +import dnf.exceptions + +# Exit codes +EXIT_SUCCESS, EXIT_ERROR, EXIT_UNSUPPORTED = 0, 1, 2 + +# Protocol +PROTOCOL_VERSION = "1" +MAX_INPUT_LINES = 10000 +KEY_OPTIONS, KEY_NAME, KEY_FILE, KEY_VERSION, KEY_ARCHITECTURE = ( + "options", + "Name", + "File", + "Version", + "Architecture", +) +KEY_ERROR_MESSAGE, KEY_PACKAGE_TYPE = "ErrorMessage", "PackageType" +PACKAGE_TYPE_FILE, PACKAGE_TYPE_REPO = "file", "repo" + +# Options +OPT_GROUP_PACKAGE_TYPES = "group_package_types" +VERSION_LATEST = "latest" + + +def _convert_value(value: str) -> Union[bool, int, str]: + """Convert string value to appropriate Python type.""" + if value.lower() in ("true", "1", "yes"): + return True + if value.lower() in ("false", "0", "no"): + return False + return int(value) if value.isdigit() else value + + +def _parse_stdin() -> Tuple[List[Dict[str, str]], List[str]]: + """Parse stdin protocol input into (packages, options).""" + packages, options, curr = [], [], {} + for line_num, line in enumerate(sys.stdin): + if line_num >= MAX_INPUT_LINES: + raise Exception(f"Input exceeds {MAX_INPUT_LINES} lines") + k, _, v = line.strip().partition("=") + if k == KEY_OPTIONS: + options.append(v) + elif k in (KEY_NAME, KEY_FILE): + if curr: + packages.append(curr) + curr = {k.lower(): v} + elif k == KEY_VERSION: + curr["version"] = v + elif k == KEY_ARCHITECTURE: + curr["arch"] = v + if curr: + packages.append(curr) + return packages, options + + +def _get_dnf_base(with_repos: bool = True, cache_only: bool = True) -> dnf.Base: + """Create configured DNF base object.""" + base = dnf.Base() + base.conf.assumeyes = True + base.conf.cacheonly = cache_only + base.conf.comment = "CFEngine dnf_group package module" + + if with_repos: + base.read_all_repos() + # Force metadata expiry to avoid stale cache FileNotFoundError + if not cache_only and base.repos: + for repo in base.repos.iter_enabled(): + repo.metadata_expire = 0 + base.fill_sack(load_system_repo=True) + else: + base.fill_sack(load_system_repo=True, load_available_repos=False) + return base + + +def _apply_setopt_options(base: dnf.Base, options: List[str]) -> None: + """Apply DNF config options (--setopt style).""" + for option in options: + # Skip group-specific options + if option.startswith(f"{OPT_GROUP_PACKAGE_TYPES}="): + continue + + if "=" not in option: + continue + + key, value = [x.strip() for x in option.split("=", 1)] + conv_value = _convert_value(value) + + # Repository option (e.g., epel.enabled=1) + if "." in key: + repo_id, repo_attr = key.split(".", 1) + if ( + base.repos + and repo_id in base.repos + and hasattr(base.repos[repo_id], repo_attr) + ): + try: + setattr(base.repos[repo_id], repo_attr, conv_value) + logging.debug(f"Set repo: {key} = {conv_value}") + except (AttributeError, ValueError, TypeError) as e: + logging.warning(f"Failed to set '{key}': {e}") + + # Base config option (e.g., install_weak_deps=false) + elif hasattr(base.conf, key) and not callable(getattr(base.conf, key)): + try: + setattr(base.conf, key, conv_value) + logging.debug(f"Set config: {key} = {conv_value}") + except (AttributeError, ValueError, TypeError) as e: + logging.warning(f"Failed to set '{key}': {e}") + + +def _parse_group_package_types(options: List[str]) -> List[str]: + """Determine package types to install from options.""" + for option in options: + if "=" in option: + key, value = [x.strip() for x in option.split("=", 1)] + if key == OPT_GROUP_PACKAGE_TYPES: + if value.lower() == "mandatory": + return ["mandatory"] + if value.lower() == "optional": + return ["mandatory", "default", "optional"] + return ["mandatory", "default"] + + return ["mandatory", "default"] # default + + +def _read_comps(base: dnf.Base) -> bool: + """Read comps safely. Returns True if successful, False otherwise.""" + try: + base.read_comps() + return base.comps is not None + except dnf.exceptions.CompsError as e: + logging.debug(f"Could not read comps: {e}") + return False + + +def _find_group(base: dnf.Base, group_id: str): + """Find group by ID in comps. Returns group object or None.""" + if not base.comps: + return None + for group in base.comps.groups_iter(): + if group.id == group_id: + return group + return None + + +def _is_group_installed(base: dnf.Base, group_id: str) -> bool: + """Check if group is installed.""" + return ( + hasattr(base, "history") + and hasattr(base.history, "group") + and bool(base.history.group.get(group_id)) + ) + + +def _execute_transaction(base: dnf.Base, operation: str) -> int: + """Resolve and execute DNF transaction.""" + try: + logging.debug(f"Resolving {operation} transaction...") + + if not base.resolve() or not base.transaction: + if not base.transaction: + logging.debug("No transaction needed") + return EXIT_SUCCESS + logging.error(f"Transaction resolution failed for {operation}") + return EXIT_ERROR + + # Download packages to avoid stale path errors + install_set = list(base.transaction.install_set) + if install_set: + logging.debug(f"Downloading {len(install_set)} packages...") + base.download_packages(install_set) + + logging.debug(f"Executing {operation}...") + base.do_transaction() + logging.debug("Transaction complete") + return EXIT_SUCCESS + + except ( + dnf.exceptions.DepsolveError, + dnf.exceptions.DownloadError, + dnf.exceptions.TransactionCheckError, + ) as e: + logging.error(f"Transaction error: {e}", exc_info=True) + return EXIT_ERROR + + +def supports_api_version() -> int: + sys.stdout.write(f"{PROTOCOL_VERSION}\n") + sys.stdout.flush() + return EXIT_SUCCESS + + +def get_package_data() -> int: + packages, _ = _parse_stdin() + if not packages: + return EXIT_ERROR + + pkg = packages[0] + pkg_string = pkg.get("file") or pkg.get("name") + if not pkg_string: + return EXIT_ERROR + + # Groups are repo type, files are file type + output = [] + if "/" in pkg_string or pkg_string.endswith(".rpm"): + output.append( + f"{KEY_PACKAGE_TYPE}={PACKAGE_TYPE_FILE}\n{KEY_NAME}={pkg_string}\n" + ) + if pkg.get("version"): + output.append(f"{KEY_VERSION}={pkg['version']}\n") + if pkg.get("arch"): + output.append(f"{KEY_ARCHITECTURE}={pkg['arch']}\n") + else: + output.append( + f"{KEY_PACKAGE_TYPE}={PACKAGE_TYPE_REPO}\n{KEY_NAME}={pkg_string}\n" + ) + + sys.stdout.write("".join(output)) + sys.stdout.flush() + return EXIT_SUCCESS + + +def list_installed() -> int: + _parse_stdin() # Consume stdin even though we don't need the data + base = _get_dnf_base(with_repos=True, cache_only=True) + try: + if not _read_comps(base) or not base.comps: + return EXIT_SUCCESS + + output = [] + for group in base.comps.groups_iter(): + if _is_group_installed(base, group.id): + output.append( + f"{KEY_NAME}={group.id}\n{KEY_VERSION}={group.id}\n{KEY_ARCHITECTURE}=all\n" + ) + + if output: + sys.stdout.write("".join(output)) + sys.stdout.flush() + return EXIT_SUCCESS + except dnf.exceptions.Error as e: + logging.debug(f"Error listing groups: {e}") + return EXIT_SUCCESS + finally: + base.close() + + +def _check_group_updates(cache_only: bool) -> int: + """Check for group updates. Helper for list_updates and list_updates_local.""" + base = _get_dnf_base(with_repos=True, cache_only=cache_only) + try: + if not _read_comps(base) or not base.comps: + return EXIT_SUCCESS + + # Reuse single test base for efficiency + test_base = _get_dnf_base(with_repos=True, cache_only=cache_only) + test_base.read_comps() + test_base.init_plugins() + test_base.pre_configure_plugins() + + try: + # Check each installed group for available updates + output = [] + for group in base.comps.groups_iter(): + if not _is_group_installed(base, group.id): + continue + + # Simulate upgrade to see if there are updates + try: + # Mark group for upgrade + test_base.group_upgrade(group.id) + + # Resolve to see if there are any packages to upgrade + if test_base.resolve() and test_base.transaction: + # There are updates available for this group + output.append( + f"{KEY_NAME}={group.id}\n{KEY_VERSION}=latest\n{KEY_ARCHITECTURE}=all\n" + ) + + # Reset for next group + test_base.reset(goal=True, repos=False, sack=False) + except (dnf.exceptions.MarkingError, dnf.exceptions.CompsError): + # Group can't be marked for upgrade or comps error + test_base.reset(goal=True, repos=False, sack=False) + continue + + if output: + sys.stdout.write("".join(output)) + sys.stdout.flush() + return EXIT_SUCCESS + finally: + test_base.close() + except dnf.exceptions.Error as e: + logging.debug(f"Error checking group updates: {e}") + return EXIT_SUCCESS + finally: + base.close() + + +def list_updates() -> int: + """List groups that have package updates available. + + Note: Groups themselves don't have versions, but the packages within + installed groups may have updates. This reports which groups contain + packages with available updates. + """ + _parse_stdin() + return _check_group_updates(cache_only=False) + + +def list_updates_local() -> int: + """List groups with updates using local cache only. + + Same as list_updates but uses cached metadata. + """ + _parse_stdin() + return _check_group_updates(cache_only=True) + + +def repo_install() -> int: + packages, options = _parse_stdin() + if not packages: + return EXIT_SUCCESS + + base = _get_dnf_base(with_repos=True, cache_only=False) + try: + _apply_setopt_options(base, options) + package_types = _parse_group_package_types(options) + + # Initialize plugins for DNF history + base.init_plugins() + base.pre_configure_plugins() + + _read_comps(base) # Best effort, continue even if fails + + # Process each group + for group_info in packages: + group_name = group_info.get("name", "").strip() + if not group_name: + continue + + # Validate and check version parameter + version_str = group_info.get("version", "").strip().lower() + is_upgrade = version_str == VERSION_LATEST + + if version_str and not is_upgrade: + logging.warning( + f"Group '{group_name}': version='{version_str}' ignored. " + f"DNF groups don't have versions. Use version='latest' to upgrade, or omit version." + ) + + # Find group + group = _find_group(base, group_name) + if not group: + sys.stdout.write( + f"{KEY_ERROR_MESSAGE}=dnf package group {group_name} not found\n" + ) + sys.stdout.flush() + return EXIT_SUCCESS + + logging.debug(f"Found group '{group.id}'") + + # Install, upgrade, or skip + if _is_group_installed(base, group.id): + if is_upgrade: + logging.debug(f"Upgrading '{group.id}'") + base.group_upgrade(group.id) + else: + logging.debug(f"Already installed, skipping '{group.id}'") + continue + else: + logging.debug(f"Installing '{group.id}' with types {package_types}") + base.group_install(group.id, package_types) + + return _execute_transaction(base, "install") + + except (dnf.exceptions.Error, dnf.exceptions.MarkingError) as e: + logging.error(f"Error during install: {e}", exc_info=True) + return EXIT_ERROR + finally: + base.close() + + +def remove() -> int: + packages, options = _parse_stdin() + if not packages: + return EXIT_SUCCESS + + base = _get_dnf_base(with_repos=True, cache_only=True) + try: + _apply_setopt_options(base, options) + + # Initialize plugins + base.init_plugins() + base.pre_configure_plugins() + + _read_comps(base) # Best effort, continue even if fails + + groups_removed = False + for pkg in packages: + group_name = pkg.get("name", "").strip() + if not group_name: + continue + + # Find group + group = _find_group(base, group_name) + if not group or not _is_group_installed(base, group.id): + logging.debug(f"Group '{group_name}' not installed, skipping") + continue + + logging.debug(f"Removing '{group.id}'") + try: + if hasattr(base, "env_group_remove"): + base.env_group_remove([group.id]) + else: + base.group_remove(group.id) + groups_removed = True + except dnf.exceptions.MarkingError as e: + logging.error(f"Failed to mark '{group.id}' for removal: {e}") + return EXIT_ERROR + + if not groups_removed: + logging.debug("No groups to remove") + return EXIT_SUCCESS + + return _execute_transaction(base, "remove") + + except dnf.exceptions.Error as e: + logging.error(f"Error during removal: {e}") + return EXIT_ERROR + finally: + base.close() + + +def file_install() -> int: + logging.error("File installation not supported for package groups") + return EXIT_ERROR + + +def main() -> int: + if len(sys.argv) < 2: + return EXIT_UNSUPPORTED + + commands = { + "supports-api-version": supports_api_version, + "get-package-data": get_package_data, + "list-installed": list_installed, + "list-updates": list_updates, + "list-updates-local": list_updates_local, + "repo-install": repo_install, + "remove": remove, + "file-install": file_install, + } + + op = sys.argv[1] + if op not in commands: + return EXIT_UNSUPPORTED + + try: + return commands[op]() + except Exception as e: + sys.stdout.write(f"{KEY_ERROR_MESSAGE}={e}\n") + sys.stdout.flush() + return EXIT_ERROR + + +if __name__ == "__main__": + logging.basicConfig( + level=logging.WARNING, + format="%(levelname)s: %(message)s", + handlers=[logging.StreamHandler(sys.stderr)], + ) + if os.environ.get("CFENGINE_DEBUG") or os.environ.get("DEBUG"): + logging.getLogger().setLevel(logging.DEBUG) + logging.debug(f"--- {' '.join(sys.argv)} ---") + + sys.exit(main()) diff --git a/modules/packages/vendored/yum.mustache b/modules/packages/vendored/yum.mustache index c42ebb17e8..2696cbe3aa 100755 --- a/modules/packages/vendored/yum.mustache +++ b/modules/packages/vendored/yum.mustache @@ -9,18 +9,21 @@ import subprocess import re -rpm_cmd = os.environ.get('CFENGINE_TEST_RPM_CMD', "/bin/rpm") +rpm_cmd = os.environ.get("CFENGINE_TEST_RPM_CMD", "/bin/rpm") rpm_quiet_option = ["--quiet"] -rpm_output_format = "Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n" +rpm_output_format = ( + "Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n" +) -yum_cmd = os.environ.get('CFENGINE_TEST_YUM_CMD', "/usr/bin/yum") +yum_cmd = os.environ.get("CFENGINE_TEST_YUM_CMD", "/usr/bin/yum") yum_options = ["--quiet", "-y"] -NULLFILE = open(os.devnull, 'w') +NULLFILE = open(os.devnull, "w") redirection_is_broken_cached = -1 + def redirection_is_broken(): # Older versions of Python have a bug where it is impossible to redirect # stderr using subprocess, and any attempt at redirecting *anything*, not @@ -41,7 +44,12 @@ def redirection_is_broken(): def subprocess_Popen(cmd, stdout=None, stderr=None): - if not redirection_is_broken() or (stdout is None and stderr is None) or stdout == subprocess.PIPE or stderr == subprocess.PIPE: + if ( + not redirection_is_broken() + or (stdout is None and stderr is None) + or stdout == subprocess.PIPE + or stderr == subprocess.PIPE + ): return subprocess.Popen(cmd, stdout=stdout, stderr=stderr) old_stdout_fd = -1 @@ -87,7 +95,19 @@ def get_package_data(): # Absolute file. sys.stdout.write("PackageType=file\n") sys.stdout.flush() - return subprocess_call([rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string]) + process = subprocess_Popen( + [rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string], + stdout=subprocess.PIPE, + ) + (stdoutdata, _) = process.communicate() + + if process.returncode != 0: + return process.returncode + + for line in stdoutdata.decode("utf-8").splitlines(): + sys.stdout.write(line.replace("(none):", "") + "\n") + + return 0 elif re.search("[:,]", pkg_string): # Contains an illegal symbol. sys.stdout.write(line + "ErrorMessage: Package string with illegal format\n") @@ -102,7 +122,18 @@ def list_installed(): # Ignore everything. sys.stdin.readlines() - return subprocess_call([rpm_cmd, "-qa", "--qf", rpm_output_format]) + process = subprocess_Popen( + [rpm_cmd, "-qa", "--qf", rpm_output_format], stdout=subprocess.PIPE + ) + (stdoutdata, _) = process.communicate() + + if process.returncode != 0: + return process.returncode + + for line in stdoutdata.decode("utf-8").splitlines(): + sys.stdout.write(line.replace("(none):", "") + "\n") + + return 0 def list_updates(online): @@ -110,7 +141,7 @@ def list_updates(online): for line in sys.stdin: line = line.strip() if line.startswith("options="): - option = line[len("options="):] + option = line[len("options=") :] if option.startswith("-"): yum_options.append(option) elif option.startswith("enablerepo=") or option.startswith("disablerepo="): @@ -120,7 +151,9 @@ def list_updates(online): if not online: online_flag = ["-C"] - process = subprocess_Popen([yum_cmd] + yum_options + online_flag + ["check-update"], stdout=subprocess.PIPE) + process = subprocess_Popen( + [yum_cmd] + yum_options + online_flag + ["check-update"], stdout=subprocess.PIPE + ) (stdoutdata, _) = process.communicate() # analyze return code from `yum check-update`: # 0 means no updates @@ -129,7 +162,9 @@ def list_updates(online): if process.returncode == 1 and not online: # If we get an error when listing local updates, try again using the # online method, so that the cache is generated - process = subprocess_Popen([yum_cmd] + yum_options + ["check-update"], stdout=subprocess.PIPE) + process = subprocess_Popen( + [yum_cmd] + yum_options + ["check-update"], stdout=subprocess.PIPE + ) (stdoutdata, _) = process.communicate() if process.returncode != 100: # either there were no updates or error happened @@ -152,7 +187,9 @@ def list_updates(online): continue lastline = "" - match = re.match(r"^(?P\S+)\.(?P[^.\s]+)\s+(?P\S+)\s+\S+\s*$", line) + match = re.match( + r"^(?P\S+)\.(?P[^.\s]+)\s+(?P\S+)\s+\S+\s*$", line + ) if match is not None: sys.stdout.write("Name=" + match.group("name") + "\n") sys.stdout.write("Version=" + match.group("version") + "\n") @@ -174,8 +211,9 @@ def one_package_argument(name, arch, version, is_yum_install): archs.append(arch) if is_yum_install: - process = subprocess_Popen([rpm_cmd, "--qf", "%{arch}\n", - "-q", name], stdout=subprocess.PIPE) + process = subprocess_Popen( + [rpm_cmd, "--qf", "%{arch}\n", "-q", name], stdout=subprocess.PIPE + ) existing_archs = [line.decode("utf-8").rstrip() for line in process.stdout] process.wait() if process.returncode == 0 and existing_archs: @@ -218,13 +256,13 @@ def package_arguments_builder(is_yum_install): name = "" version = "" arch = "" - single_cmd_args = [] # List of arguments - multi_cmd_args = [] # List of lists of arguments + single_cmd_args = [] # List of arguments + multi_cmd_args = [] # List of lists of arguments old_name = "" for line in sys.stdin: line = line.strip() if line.startswith("options="): - option = line[len("options="):] + option = line[len("options=") :] if option.startswith("-"): yum_options.append(option) elif option.startswith("enablerepo=") or option.startswith("disablerepo="): @@ -232,7 +270,9 @@ def package_arguments_builder(is_yum_install): if line.startswith("Name="): if name: # Each new "Name=" triggers a new entry. - single_list, multi_list = one_package_argument(name, arch, version, is_yum_install) + single_list, multi_list = one_package_argument( + name, arch, version, is_yum_install + ) single_cmd_args += single_list if name == old_name: # Packages that differ only by architecture should be @@ -255,7 +295,9 @@ def package_arguments_builder(is_yum_install): arch = line.split("=", 1)[1].rstrip() if name: - single_list, multi_list = one_package_argument(name, arch, version, is_yum_install) + single_list, multi_list = one_package_argument( + name, arch, version, is_yum_install + ) single_cmd_args += single_list if name == old_name: # Packages that differ only by architecture should be @@ -436,4 +478,5 @@ def main(): sys.stderr.write("Invalid operation\n") return 2 + sys.exit(main()) diff --git a/promises.cf.in b/promises.cf.in index 6c093b0f72..181e7306f1 100644 --- a/promises.cf.in +++ b/promises.cf.in @@ -139,6 +139,10 @@ body common control control_common_tls_ciphers_defined:: tls_ciphers => "$(default:def.control_common_tls_ciphers)"; # See also: allowciphers in body server control + control_common_protocol_version_defined:: + protocol_version => "$(default:def.control_common_protocol_version)"; + control_common_system_log_level_defined:: + system_log_level => "$(default:def.control_common_system_log_level)"; } bundle common inventory diff --git a/standalone_self_upgrade.cf.in b/standalone_self_upgrade.cf.in index 3850b7fab2..d23e034283 100644 --- a/standalone_self_upgrade.cf.in +++ b/standalone_self_upgrade.cf.in @@ -42,6 +42,20 @@ bundle common def_standalone_self_upgrade comment => concat( "If default:def.control_common_tls_ciphers is defined then", " its value will be used for the set of tls ciphers allowed", " for outbound connections. Else the binary default will be used."); + + "control_common_protocol_version_defined" -> { "CFE-4543" } + expression => isvariable( "default:def.control_common_protocol_version" ), + comment => concat( "Defines the protocol version to use for all outgoing", + " connections.", + # It's challenging to keep this aligned with the core agent code + # cf-promises --syntax-description=json | jq -r '.bodyTypes.common.attributes.protocol_version.range' + " (1|classic|2|tls|3|cookie|4|filestream|latest)" ); + "control_common_system_log_level_defined" -> { "CFE-4452" } + expression => isvariable( "default:def.control_common_system_log_level" ), + comment => concat( "The minimum log level required for log messages to go to the", + " system log (e.g. syslog or Windows Event Log).", + " (critical|error|warning|notice|info)" ); + } body agent control # @brief Agent controls for standalone self upgrade @@ -263,7 +277,7 @@ bundle agent cfengine_software_cached_locally # NOTE This is pegged to the single upstream policy hub, it won't fail # over to a secondary for copying the binarys to update. - "$(local_software_dir)" + "$(local_software_dir)/." comment => "Copy binary updates from master source on policy server", handle => "cfe_internal_update_bins_files_pkg_copy", copy_from => u_dsync( "$(master_software_location)/$(package_dir)", $(sys.policy_hub) ), @@ -545,12 +559,18 @@ bundle common cfengine_package_names "pkg[oracle_8_x86_64]" string => "$(pkg[redhat_8_x86_64])"; "pkg[rocky_8_x86_64]" string => "$(pkg[redhat_8_x86_64])"; - # Redhat/Centos/Oracle/Rocky 8 use the same package + # Redhat/Centos/Oracle/Rocky 9 use the same package "pkg[redhat_9_x86_64]" string => "$(pkg_name)-$(pkg_version)-$(pkg_release).el9.x86_64.rpm"; "pkg[centos_9_x86_64]" string => "$(pkg[redhat_9_x86_64])"; "pkg[oracle_9_x86_64]" string => "$(pkg[redhat_9_x86_64])"; "pkg[rocky_9_x86_64]" string => "$(pkg[redhat_9_x86_64])"; + # Redhat/Centos/Oracle/Rocky 10 use the same package + "pkg[redhat_10_x86_64]" string => "$(pkg_name)-$(pkg_version)-$(pkg_release).el10.x86_64.rpm"; + "pkg[centos_10_x86_64]" string => "$(pkg[redhat_10_x86_64])"; + "pkg[oracle_10_x86_64]" string => "$(pkg[redhat_10_x86_64])"; + "pkg[rocky_10_x86_64]" string => "$(pkg[redhat_10_x86_64])"; + # 64bit Debian @@ -559,6 +579,8 @@ bundle common cfengine_package_names "pkg[debian_9_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian9_amd64.deb"; "pkg[debian_10_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian10_amd64.deb"; "pkg[debian_11_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian11_amd64.deb"; + "pkg[debian_12_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian12_amd64.deb"; + "pkg[debian_13_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian13_amd64.deb"; # 64bit Ubuntu "pkg[ubuntu_14_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu14_amd64.deb"; @@ -566,12 +588,16 @@ bundle common cfengine_package_names "pkg[ubuntu_18_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu18_amd64.deb"; "pkg[ubuntu_20_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu20_amd64.deb"; "pkg[ubuntu_22_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu22_amd64.deb"; + "pkg[ubuntu_24_x86_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu24_amd64.deb"; # aarch64 Ubuntu "pkg[ubuntu_22_arm_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu22_arm64.deb"; + "pkg[ubuntu_24_arm_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).ubuntu24_arm64.deb"; # aarch64 Debian "pkg[debian_11_arm_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian11_arm64.deb"; + "pkg[debian_12_arm_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian12_arm64.deb"; + "pkg[debian_13_arm_64]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian13_arm64.deb"; # 32bit DEBs "pkg[$(cfengine_master_software_content._deb_dists)_$(cfengine_master_software_content._32bit_arches)]" string => "$(pkg_name)_$(pkg_version)-$(pkg_release).debian7_i386.deb"; @@ -650,6 +676,12 @@ bundle agent cfengine_master_software_content "dir[oracle_9_x86_64]" string => "$(dir[redhat_9_x86_64])"; "dir[rocky_9_x86_64]" string => "$(dir[redhat_9_x86_64])"; + # Redhat/Centos/Oracle/Rocky 10 use the same package + "dir[redhat_10_x86_64]" string => "agent_rhel10_x86_64"; + "dir[centos_10_x86_64]" string => "$(dir[redhat_10_x86_64])"; + "dir[oracle_10_x86_64]" string => "$(dir[redhat_10_x86_64])"; + "dir[rocky_10_x86_64]" string => "$(dir[redhat_10_x86_64])"; + # Debian "dir[debian_7_x86_64]" string => "agent_deb_x86_64"; "dir[debian_8_x86_64]" string => "agent_debian8_x86_64"; @@ -657,6 +689,10 @@ bundle agent cfengine_master_software_content "dir[debian_10_x86_64]" string => "agent_debian10_x86_64"; "dir[debian_11_x86_64]" string => "agent_debian11_x86_64"; "dir[debian_11_arm_64]" string => "agent_debian11_arm_64"; + "dir[debian_12_x86_64]" string => "agent_debian12_x86_64"; + "dir[debian_13_x86_64]" string => "agent_debian13_x86_64"; + "dir[debian_12_arm_64]" string => "agent_debian12_arm_64"; + "dir[debian_13_arm_64]" string => "agent_debian13_arm_64"; # Ubuntu "dir[ubuntu_14_x86_64]" string => "agent_ubuntu14_x86_64"; @@ -665,6 +701,8 @@ bundle agent cfengine_master_software_content "dir[ubuntu_20_x86_64]" string => "agent_ubuntu20_x86_64"; "dir[ubuntu_22_x86_64]" string => "agent_ubuntu22_x86_64"; "dir[ubuntu_22_arm_64]" string => "agent_ubuntu22_arm_64"; + "dir[ubuntu_24_x86_64]" string => "agent_ubuntu24_x86_64"; + "dir[ubuntu_24_arm_64]" string => "agent_ubuntu24_arm_64"; # All 32bit debs use the same package "_deb_dists" slist => { "debian_4", "debian_5", "debian_6", @@ -874,6 +912,11 @@ body common control (debian|redhat):: package_module => $(package_module_knowledge.platform_default); + + control_common_protocol_version_defined:: + protocol_version => "$(default:def.control_common_protocol_version)"; + control_common_system_log_level_defined:: + system_log_level => "$(default:def.control_common_system_log_level)"; } body depth_search u_recurse_basedir(d) diff --git a/templates/cf-apache.service.mustache b/templates/cf-apache.service.mustache index 9ebeb7e3da..d96574e6fd 100644 --- a/templates/cf-apache.service.mustache +++ b/templates/cf-apache.service.mustache @@ -12,6 +12,11 @@ ExecStart={{{vars.sys.workdir}}}/httpd/bin/apachectl start ExecStop={{{vars.sys.workdir}}}/httpd/bin/apachectl stop ExecReload={{{vars.sys.workdir}}}/httpd/bin/apachectl graceful PIDFile={{{vars.sys.workdir}}}/httpd/httpd.pid +# ENT-11189: apachectl writes the PID file shortly after fork. On a busy host +# (e.g. mid-upgrade with SELinux relabel, cf-postgres and cf-php-fpm churning) +# the default 90s start timeout has been observed to fire while apache is still +# coming up, leaving worker children bound to :80 and the unit in a restart loop. +TimeoutStartSec=300 Restart=always RestartSec=10 UMask=0177 diff --git a/templates/federated_reporting/50-merge_inserts.awk b/templates/federated_reporting/50-merge_inserts.awk deleted file mode 100644 index e31536d792..0000000000 --- a/templates/federated_reporting/50-merge_inserts.awk +++ /dev/null @@ -1,118 +0,0 @@ -# -# An AWK script to merge consecutive INSERT INTO SQL statements that insert data -# into the same table into fewer statements each inserting multiple VALUES -# tuples (rows). This can significantly speed up processing/execution of the SQL -# statements (if the DB supports multiple VALUES per one INSERT INTO). -# - -BEGIN { - # split lines on SQL keywords - # lines are like "INSERT INTO table_name (col1, col2) VALUES (val1, val2);" - FS = "(INSERT INTO|VALUES)" - - # Output Record Separator -- "\n" by default, we need greater control - ORS = "" - - # helper variables - table_name = "" - counter = 0 - - # maximum rows per one INSERT INTO statement (we need to limit this because - # otherwise PostgreSQL can easily run out of memory when buffering things) - max_per_statement = 10000 -} - -/^INSERT INTO/ { - # "INSERT INTO table_name (col1, col2) VALUES (val1, val2);" - # $1 == "" - # $2 == " table_name (col1, col2) " - # $3 == " (val1, val2);" - - if (NF != 3) { - # Less or more than 3 fields which this means that 'INSERT INTO' or - # 'VALUES' didn't appear in the row or appeared in some unexpected - # places. Just preserve such line. - - if (table_name != "") { - # the previous line(s) was (were) INSERT INTO statements into some - # table, let's terminate the statement, remember we are not in the - # process of adding rows to any INSERT INTO statement and reset the - # counter - print ";\n" - table_name = "" - counter = 0 - } - - # in any case just print/preserve the line - print $0"\n" - next - } - - # split the "table_name (col1, col2)" field on spaces - split($2, fields, " ") - - # trim ";" and any trailing whitespace from the "VALUES (val1, val2);" part - values = $3; - gsub(";\\s*$", "", values); - - if (table_name == "") { - # starting with a new table, store its name and write out the beginning - # of the INSERT INTO statement - table_name = fields[1] - print "INSERT INTO"$2"VALUES \n"values - counter = 1 - } - else { - if (table_name == fields[1]) { - # another line inserting into the same table - if (counter == max_per_statement) { - # reached the limit of maximum rows per one INSERT INTO statement - # terminate it and start a new one for the same table - print ";\n" - print "INSERT INTO"$2"VALUES \n"values - counter = 1 - } - else { - # more rows for the same table - # write ",\n" after the previous row first, write the row and - # increment the counter - print ",\n"values - counter++ - } - } - else { - # a different table, terminate the INSERT INTO statement for the - # previous table, start a new one for the new table and reset the - # counter of rows per one statement - print ";\n" - print "\n" - print "INSERT INTO"$2"VALUES \n"values - counter = 1 - } - } -} - -!/^INSERT INTO/ { - # all the other lines (empty, different SQL statements, comments,...) - - if (table_name != "") { - # the previous line(s) was (were) INSERT INTO statements into some - # table, let's terminate the statement, remember we are not in the - # process of adding rows to any INSERT INTO statement and reset the - # counter - print ";\n" - table_name = "" - counter = 0 - } - - # in any case just print/preserve the line - print $0"\n" -} - -END { - if (table_name != "") { - # the previous line(s) was (were) INSERT INTO statements into some - # table, let's terminate the statement, we are at the end - print ";\n" - } -} diff --git a/templates/federated_reporting/distributed_cleanup.py b/templates/federated_reporting/distributed_cleanup.py index 6e983c2686..7dcc3ecdbd 100755 --- a/templates/federated_reporting/distributed_cleanup.py +++ b/templates/federated_reporting/distributed_cleanup.py @@ -31,7 +31,7 @@ import subprocess import sys from getpass import getpass -from nova_api import NovaApi +from nova_api import NovaApi, Unauthenticated, Unauthenticated2FA from cfsecret import read_secret, write_secret WORKDIR = None @@ -65,26 +65,37 @@ def interactive_setup_feeder(hub, email, fr_distributed_cleanup_password, force_interactive=False): + feeder_hostname = hub["ui_name"] + feeder_admin_user = input("Enter admin username for {} [admin]: ".format(feeder_hostname)) or "admin" if force_interactive: feeder_credentials = input( - "admin credentials for {}: ".format( - hub["ui_name"] - ) + "admin credentials for {}: ".format(feeder_hostname) ) print() # output newline for easier reading else: feeder_credentials = getpass( - prompt="Enter admin credentials for {}: ".format( - hub["ui_name"] - ) + prompt="Enter admin password for {}: ".format(feeder_hostname) ) - feeder_hostname = hub["ui_name"] feeder_api = NovaApi( - api_user="admin", + api_user=feeder_admin_user, api_password=feeder_credentials, cert_path=CERT_PATH, hostname=feeder_hostname, ) + try: + feeder_api.status() + except Unauthenticated2FA: + token = getpass(prompt="Enter 2FA code for {}: ".format(feeder_hostname)) + feeder_api = NovaApi( + api_user=feeder_admin_user, + api_password=feeder_credentials, + cert_path=CERT_PATH, + hostname=feeder_hostname, + two_factor_token=token, + ) + except Unauthenticated: + print("admin credentials for {} are incorrect, try again".format(feeder_hostname)) + sys.exit(1) logger.info("Creating fr_distributed_cleanup role on %s", feeder_hostname) response = feeder_api.put( @@ -103,7 +114,7 @@ def interactive_setup_feeder(hub, email, fr_distributed_cleanup_password, force_ ) sys.exit(1) response = feeder_api.put_role_permissions( - "fr_distributed_cleanup", ["host.delete"] + "fr_distributed_cleanup", ["host.delete", "hosts-delete-permanently.delete"] ) if response["status"] != 201: print("Unable to set RBAC permissions on role fr_distributed_cleanup") @@ -130,6 +141,7 @@ def interactive_setup_feeder(hub, email, fr_distributed_cleanup_password, force_ def interactive_setup(force_interactive=False): fr_distributed_cleanup_password = "".join(random.choices(string.digits + string.ascii_letters, k=20)) + admin_user = input("Enter admin username for superhub {} [admin]: ".format(socket.getfqdn())) or "admin" if force_interactive: admin_pass = input("admin password for superhub {}: ".format(socket.getfqdn())) print() # newline for easier reading @@ -138,27 +150,26 @@ def interactive_setup(force_interactive=False): prompt="Enter admin password for superhub {}: ".format(socket.getfqdn()) ) - api = NovaApi(api_user="admin", api_password=admin_pass) + api = NovaApi(api_user=admin_user, api_password=admin_pass) # first confirm that this host is a superhub - status = api.fr_hub_status() - if ( - status["status"] == 200 - and status["role"] == "superhub" - and status["configured"] - ): - logger.debug("This host is a superhub configured for Federated Reporting.") - else: - if status["status"] == 401: - print("admin credentials are incorrect, try again") - sys.exit(1) - else: - print( - "Check the status to ensure role is superhub and configured is True. {}".format( - status - ) + try: + status = api.fr_hub_status() + except Unauthenticated2FA: + token = getpass(prompt="Enter 2FA code for superhub {}: ".format(socket.getfqdn())) + api = NovaApi(api_user=admin_user, api_password=admin_pass, two_factor_token=token) + status = api.fr_hub_status() + except Unauthenticated: + print("admin credentials are incorrect, try again") + sys.exit(1) + if not (status["status"] == 200 and status["role"] == "superhub" and status["configured"]): + print( + "Check the status to ensure role is superhub and configured is True. {}".format( + status ) - sys.exit(1) + ) + sys.exit(1) + logger.debug("This host is a superhub configured for Federated Reporting.") feederResponse = api.fr_remote_hubs() if not feederResponse["hubs"]: @@ -295,19 +306,26 @@ def main(): ) try: response = feeder_api.status() - except Exception as e: - print("Could not connect to {}, error: {}".format(feeder_hostname, e)); - sys.exit(1); - if response["status"] == 401 and sys.stdout.isatty(): - # auth error when running interactively - # assume it's a new feeder and offer to set it up interactively - hub_user = api.get( "user", "fr_distributed_cleanup") - if hub_user is None or 'email' not in hub_user: - email = 'fr_distributed_cleanup@{}'.format(hub['ui_name']) + except Unauthenticated2FA: + if sys.stdout.isatty(): + hub_user = api.get("user", "fr_distributed_cleanup") + email = hub_user['email'] if hub_user and 'email' in hub_user else 'fr_distributed_cleanup@{}'.format(hub['ui_name']) + interactive_setup_feeder(hub, email, fr_distributed_cleanup_password) + else: + print("2FA required for feeder {}. Skipping".format(feeder_hostname)) + continue + except Unauthenticated: + if sys.stdout.isatty(): + hub_user = api.get("user", "fr_distributed_cleanup") + email = hub_user['email'] if hub_user and 'email' in hub_user else 'fr_distributed_cleanup@{}'.format(hub['ui_name']) + interactive_setup_feeder(hub, email, fr_distributed_cleanup_password) else: - email = hub_user['email'] - interactive_setup_feeder(hub, email, fr_distributed_cleanup_password) - elif response["status"] != 200: + print("Unable to authenticate to feeder {}. Skipping".format(feeder_hostname)) + continue + except Exception as e: + print("Could not connect to {}, error: {}".format(feeder_hostname, e)) + sys.exit(1) + if response["status"] != 200: print( "Unable to get status for feeder {}. Skipping".format(feeder_hostname) ) @@ -372,9 +390,11 @@ def main(): # We only selected hostkey so will take the first value. host_to_delete = row[0] - response = feeder_api.delete("host", host_to_delete) - # both 202 Accepted and 404 Not Found are acceptable responses - if response["status"] not in [202, 404]: + + responseDelete = feeder_api.delete("host", host_to_delete) + responsePermanentlyDelete = feeder_api.delete("hosts/delete-permanently", host_to_delete) + # both 202 Accepted/204 No Content and 200 Ok/404 Not Found are acceptable responses + if responseDelete["status"] not in [202, 204] or responsePermanentlyDelete["status"] not in [200, 404]: logger.warning( "Delete %s on feeder %s got %s status code", host_to_delete, @@ -393,17 +413,11 @@ def main(): ) continue - # simulate the host api delete process by setting current_timestamp in deleted column - # and delete from all federated tables similar to the clear_hosts_references() pgplsql function. - post_sql += "INSERT INTO __hosts (hostkey,deleted) VALUES" - deletes = [] + # delete from __hosts and all federated tables similar to the clear_hosts_references() pgplsql function. + hostkeys_to_delete = [] for hostkey in post_hostkeys: - deletes.append("('{}', CURRENT_TIMESTAMP)".format(hostkey)) - - delete_sql = ", ".join(deletes) - delete_sql += ( - " ON CONFLICT (hostkey,hub_id) DO UPDATE SET deleted = excluded.deleted;\n" - ) + hostkeys_to_delete.append("'{}'".format(hostkey)) + delete_sql = "DELETE FROM __hosts WHERE hostkey IN ({});\n".format(",".join(hostkeys_to_delete)) clear_sql = "set schema 'public';\n" for table in CFE_FR_TABLES: # special case of partitioning, operating on parent table will work diff --git a/templates/federated_reporting/dump.sh b/templates/federated_reporting/dump.sh index 7105939e2f..cbbd1596b9 100644 --- a/templates/federated_reporting/dump.sh +++ b/templates/federated_reporting/dump.sh @@ -55,15 +55,7 @@ in_progress_file="$CFE_FR_DUMP_DIR/$CFE_FR_FEEDER_$ts.sql.$CFE_FR_COMPRESSOR_EXT log "Dumping tables: $CFE_FR_TABLES" { - "$CFE_BIN_DIR"/pg_dump --serializable-deferrable --column-inserts --data-only $(printf ' -t %s' $CFE_FR_TABLES) cfdb - - # in case of 3.12 must copy m_inventory as if it was __inventory - if [[ "$CFE_VERSION" =~ "3.12." ]]; then - # pg_dump will not dump the contents of views so we must run the following SQL: - "$CFE_BIN_DIR"/psql cfdb --quiet -c "COPY (SELECT * FROM m_inventory WHERE values IS NOT NULL) TO STDOUT CSV QUOTE '''' FORCE QUOTE *" | - sed -e 's.^.INSERT INTO __inventory (hostkey, values) VALUES (.' \ - -e 's.$.);.' - fi + "$CFE_BIN_DIR"/pg_dump --serializable-deferrable --column-inserts --rows-per-insert=10000 --data-only $(printf ' -t %s' $CFE_FR_TABLES) cfdb } | sed_filters | awk_filters | "$CFE_FR_COMPRESSOR" $CFE_FR_COMPRESSOR_ARGS > "$in_progress_file" || failed=1 diff --git a/templates/federated_reporting/nova_api.py b/templates/federated_reporting/nova_api.py index cec6349324..687bcdffbd 100755 --- a/templates/federated_reporting/nova_api.py +++ b/templates/federated_reporting/nova_api.py @@ -34,6 +34,14 @@ _DEFAULT_SECRETS_PATH = "{}/httpd/secrets.ini".format(_WORKDIR) +class Unauthenticated(Exception): + pass + + +class Unauthenticated2FA(Unauthenticated): + pass + + class NovaApi: def __init__( self, @@ -42,6 +50,7 @@ def __init__( api_password=None, cert_path=None, ca_cert_dir=None, + two_factor_token=None, ): self._hostname = hostname or str(socket.getfqdn()) self._api_user = api_user @@ -69,6 +78,8 @@ def __init__( basic_auth="{}:{}".format(self._api_user, self._api_password) ) self._headers["Content-Type"] = "application/json" + if two_factor_token: + self._headers["Cf-2fa-Token"] = two_factor_token # urllib3 v2.0 removed SubjectAltNameWarning and instead throws an error if no SubjectAltName is present in a certificate if hasattr(urllib3.exceptions, "SubjectAltNameWarning"): # if urllib3 is < v2.0 then SubjectAltNameWarning will exist and should be silenced @@ -111,10 +122,17 @@ def _build_response(self, response): if not message: if response.status == 201: message = "Created" + if response.status == 401: + if "Invalid two-factor" in message: + raise Unauthenticated2FA(message) + raise Unauthenticated(message) value["message"] = message value["status"] = response.status else: - data = json.loads(response.data.decode("utf-8")) + body = response.data.decode("utf-8").strip() + if not body: + return {"status": response.status} + data = json.loads(body) # some APIs like query API return a top-level data key which we want to skip for ease of use if "data" in data: # data response e.g. query API returns top-level key 'data' diff --git a/templates/federated_reporting/psql_wrapper.sh.mustache b/templates/federated_reporting/psql_wrapper.sh.mustache index b29bfcf232..d54bea87dd 100644 --- a/templates/federated_reporting/psql_wrapper.sh.mustache +++ b/templates/federated_reporting/psql_wrapper.sh.mustache @@ -14,8 +14,22 @@ fi TMP=$(mktemp) cd /tmp -OUT=$(su - cfpostgres --command "{{{vars.sys.bindir}}}/psql --quiet --tuples-only --no-align --no-psqlrc \"$1\" --command=\"$2\"" 2> $TMP) -RETURN_CODE=$? + +# psql returns 2 when the connection to the server went bad, which can happen +# transiently while postgres is being restarted. Retry a few times so that the +# wrapper doesn't fail the promise just because postgres is briefly unavailable. +MAX_ATTEMPTS=10 +ATTEMPT=1 +while : ; do + OUT=$(su - cfpostgres --command "{{{vars.sys.bindir}}}/psql --quiet --tuples-only --no-align --no-psqlrc \"$1\" --command=\"$2\"" 2> $TMP) + RETURN_CODE=$? + if [ $RETURN_CODE -ne 2 ] || [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then + break + fi + ATTEMPT=$((ATTEMPT + 1)) + sleep 3 +done + ERR=$(<$TMP) EXIT_CODE=$(echo $OUT | awk -F= '{ if ( /exit_code/ ) print $2}') diff --git a/tests/acceptance/17_packages/01_init/unsafe/timed/001-prepare-repositories.cf b/tests/acceptance/17_packages/01_init/unsafe/timed/001-prepare-repositories.cf index cc14666266..66154edb6c 100644 --- a/tests/acceptance/17_packages/01_init/unsafe/timed/001-prepare-repositories.cf +++ b/tests/acceptance/17_packages/01_init/unsafe/timed/001-prepare-repositories.cf @@ -13,18 +13,13 @@ body common control "../../../../../../$(sys.local_libdir)/files.cf", "../../../../../../$(sys.local_libdir)/commands.cf", "../../../packages-info.cf.sub", + "../../../meta_skip.cf.sub", }; bundlesequence => { default("$(this.promise_filename)") }; } bundle agent test { - meta: - "test_skip_needs_work" string => "!redhat.!debian", - meta => { "redmine5866" }; - # RedHat 4 RPM has a bug which corrupts the RPM DB during our tests, so it is untestable. - "test_skip_unsupported" string => "redhat_4|centos_4"; - vars: "bundles" slist => { "repositories", "signing_keys", @@ -134,8 +129,9 @@ bundle agent signing_keys rm /test-repos/deb_repo1/dists/package1/Release.gpg /test-repos/deb_repo2/dists/package2/Release.gpg && \ $(gpg) --detach-sign --armor --output /test-repos/deb_repo1/dists/package1/Release.gpg /test-repos/deb_repo1/dists/package1/Release && \ $(gpg) --detach-sign --armor --output /test-repos/deb_repo2/dists/package2/Release.gpg /test-repos/deb_repo2/dists/package2/Release && \ - rm -rf .gnupg-temp && \ - apt-key add $(p.resources)/gpg/pubring.gpg" + $(gpg) --export --output /etc/apt/trusted.gpg.d/cfengine-test-repo.gpg && \ + chmod 0644 /etc/apt/trusted.gpg.d/cfengine-test-repo.gpg && \ + rm -rf .gnupg-temp" contain => useshell, classes => if_successful("signing_keys_ok"); } @@ -143,28 +139,29 @@ bundle agent signing_keys bundle agent apt_config { classes: - !(ubuntu_10|debian_6):: - "apt_config_ok" expression => "any", + !(ubuntu_10|debian_6|ubuntu_24|ubuntu_26):: + "apt_config_ok" + expression => "any", scope => "namespace"; files: + ubuntu_24|ubuntu_26:: + "/etc/apt/apt.conf.d/accept-older-pubkeys" + comment => "key in 17_packages/resources/gpg use rsa1024 which is not supported on Ubuntu-24 and later.", + create => "true", + content => 'APT::Key::Assert-Pubkey-Algo ">=rsa1024";', + classes => if_successful("apt_config_ok"); + ubuntu_10|debian_6:: # Work around bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=715494 # Apt cache does not behave correctly if installing more than one package # per second. "/etc/apt/apt.conf.d/nocache" create => "true", - edit_line => no_apt_cache, - edit_defaults => empty, + content => 'Dir::Cache::pkgcache "";', classes => if_successful("apt_config_ok"); } -bundle edit_line no_apt_cache -{ - insert_lines: - 'Dir::Cache::pkgcache "";'; -} - bundle agent dpkg_multiarch { vars: diff --git a/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test.cf b/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test.cf index 59f05adb4e..d89b35bfe2 100644 --- a/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test.cf +++ b/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test.cf @@ -35,8 +35,9 @@ bundle agent init # packages where earlier releases did not, so fails many tests. # RHEL 8 has broken DNF (upgrading a 32bit package also installs a 64bit # package) + "test_soft_fail" string => "rhel_8|rhel_9", - meta => {"CFE-rhbz", "CFE-4096"}; + meta => {"CFE-rhbz", "CFE-4096", "ENT-13499" }; # For setting up the cfengine-selected-python symlink we want to # target $(sys.bindir) as that will be in the test WORKDIR. diff --git a/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test_generator.py b/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test_generator.py index 69441d1f4a..cc144d8a49 100755 --- a/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test_generator.py +++ b/tests/acceptance/17_packages/10_new/unsafe/the_great_package_test_generator.py @@ -121,8 +121,9 @@ def header(test_count): # packages where earlier releases did not, so fails many tests. # RHEL 8 has broken DNF (upgrading a 32bit package also installs a 64bit # package) + "test_soft_fail" string => "rhel_8|rhel_9", - meta => {"CFE-rhbz", "CFE-4096"}; + meta => {"CFE-rhbz", "CFE-4096", "ENT-13499" }; # For setting up the cfengine-selected-python symlink we want to # target $(sys.bindir) as that will be in the test WORKDIR. diff --git a/tests/acceptance/17_packages/11_old/unsafe/package-inventory.cf b/tests/acceptance/17_packages/11_old/unsafe/package-inventory.cf index aad106a898..08655fb47a 100644 --- a/tests/acceptance/17_packages/11_old/unsafe/package-inventory.cf +++ b/tests/acceptance/17_packages/11_old/unsafe/package-inventory.cf @@ -13,6 +13,7 @@ body common control "../../../../../$(sys.local_libdir)/packages.cf", "../../../../../inventory/any.cf", "../../packages-info.cf.sub", + "../../meta_skip.cf.sub", }; bundlesequence => { default($(this.promise_files)) }; } @@ -20,13 +21,8 @@ body common control bundle agent init { meta: - # need packages for platforms other than redhat and debian on x86_64 architecture - # see tests/acceptance/17_packages/meta_skip.cf.sub - "test_skip_needs_work" string => "(!redhat.!debian)|(!x86_64)", - meta => { "CFE-3992" }; - # RedHat 4 RPM has a bug which corrupts the RPM DB during our tests, so it is untestable. - # And available patches is an Enterprise feature. - "test_skip_unsupported" string => "redhat_4|centos_4|!enterprise"; + # Available patches is an Enterprise feature. + "test_skip_unsupported" string => "!enterprise"; methods: "any" usebundle => clear_packages("dummy"); diff --git a/tests/acceptance/17_packages/meta_skip.cf.sub b/tests/acceptance/17_packages/meta_skip.cf.sub index b71260282f..8d1d4f1b56 100644 --- a/tests/acceptance/17_packages/meta_skip.cf.sub +++ b/tests/acceptance/17_packages/meta_skip.cf.sub @@ -1,9 +1,9 @@ bundle common 17_packages_meta { meta: - "test_skip_needs_work" string => "(!redhat.!debian)|(!x86_64)", - comment => "Need to create test packages for platforms other than x86 redhat and debian based distributions.", - meta => { "CFE-3993", "CFE-3992"}; + "test_skip_needs_work" string => "(!redhat.!debian)|(!x86_64)|(debian_13|redhat_10)", + comment => "Need to create test packages for platforms other than x86 redhat and debian based distributions. Also, debian-13 deprecates apt-key and requires a newer pubkey algorithm.", + meta => { "CFE-3993", "CFE-3992", "ENT-13499" }; "test_skip_unsupported" string => "redhat_4|centos_4|debian_4|debian_etch", comment => "RedHat 4 RPM has a bug which corrupts the RPM DB during our tests, so it is untestable.", diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf new file mode 100644 index 0000000000..6671d8af72 --- /dev/null +++ b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf @@ -0,0 +1,67 @@ +####################################################### +# +# Test that set_variable_values_ini does not error when section doesn't exist +# +####################################################### + +body common control +{ + inputs => { "../../default.cf.sub" }; + bundlesequence => { default("$(this.promise_filename)") }; + version => "1.0"; +} + +####################################################### + +bundle agent init +{ + files: + # The tested file "actual" is copied from our seeded starting position. + "$(G.testfile).actual" + copy_from => local_cp("$(this.promise_filename).actual"); + + # Next we place the file which we will compare the final result with. + "$(G.testfile).expected" + copy_from => local_cp("$(this.promise_filename).expected"); +} + +####################################################### + +bundle agent test +{ + meta: + "description" -> { "CFE-3866" } + string => "Test that set_variable_values_ini does not error when section doesn't exist"; + + vars: + "config[section1][key1]" string => "value1"; + "config[section1][key2]" string => "value2"; + "config[section2][key3]" string => "value3"; + "config[section2][key4]" string => "value4"; + + files: + "$(G.testfile).actual" + create => "true", + edit_line => set_variable_values_ini("test.config", "section1"); + + "$(G.testfile).actual" + edit_line => set_variable_values_ini("test.config", "section2"); +} + +####################################################### + +bundle agent check +{ + methods: + "check" + usebundle => dcs_if_diff("$(G.testfile).actual", "$(G.testfile).expected", + "pass", "_fail"); + + "fail" + usebundle => dcs_fail($(this.promise_filename)), + if => "_fail"; + + pass:: + "pass" + usebundle => dcs_pass($(this.promise_filename)); +} diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.actual b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.actual new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected new file mode 100644 index 0000000000..4adafa063c --- /dev/null +++ b/tests/acceptance/lib/files/set_variable_values_ini_missing_section.cf.expected @@ -0,0 +1,6 @@ +[section2] +key3=value3 +key4=value4 +[section1] +key2=value2 +key1=value1 diff --git a/tests/unit/test_package_module_yum b/tests/unit/test_package_module_yum index a7864c4742..56902f99b4 100755 --- a/tests/unit/test_package_module_yum +++ b/tests/unit/test_package_module_yum @@ -151,11 +151,11 @@ assert check("list-updates-local", [], 18, assert check("list-installed", [], 6, ["Name=firefox\nVersion=24.5.0-1.el5.centos\nArchitecture=i386", "Name=yum\nVersion=3.2.29-43.el6_5\nArchitecture=noarch"], - 4, ["rpm -qa --qf Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n"]) + 4, ["rpm -qa --qf Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n"]) assert check("get-package-data", ["File=/path/to/pkg"], 4, ["PackageType=file\nName=file_pkg\nVersion=10.0\nArchitecture=x86_64"], - 4, ["rpm --qf Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n -qp /path/to/pkg"]) + 4, ["rpm --qf Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n -qp /path/to/pkg"]) assert check("get-package-data", ["File=repo_pkg"], 2, ["PackageType=repo\nName=repo_pkg"], 0, []) diff --git a/update.cf.in b/update.cf.in index 471091e5af..a69e28379e 100644 --- a/update.cf.in +++ b/update.cf.in @@ -40,6 +40,11 @@ body common control control_common_tls_ciphers_defined:: tls_ciphers => "$(default:def.control_common_tls_ciphers)"; # See also: allowciphers in body server control + + control_common_protocol_version_defined:: + protocol_version => "$(default:def.control_common_protocol_version)"; + control_common_system_log_level_defined:: + system_log_level => "$(default:def.control_common_system_log_level)"; } #############################################################################