From f960daa8f5742e48a51d0e2b289e8a2431f5b592 Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Wed, 19 Aug 2026 17:07:43 -0500 Subject: [PATCH 1/6] Added Makefile to replace much of ci.yml workflow for local ease of use Ticket: none Changelog: none --- .github/workflows/ci.yml | 22 ++++++---------------- Makefile | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 Makefile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7572f7cb..23d75c23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,19 +18,9 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.14" - - name: Install python tools - run: pipx install flake8 pyright black pyflakes pytest cfbs cfengine - - name: Check the status with cfbs - run: cfbs status - - name: Validate with cfbs - run: cfbs validate - - name: Check the formatting - run: cfbs --check pretty ./cfbs.json - - name: Linting python code - run: ./ci/linting.sh - - name: Run promise type tests - run: pytest promise-types/ -v - - name: Lint policy with CFEngine CLI - run: cfengine lint --strict no ./ - - name: Check formatting with CFEngine CLI - run: cfengine format --check + - name: Install CFEngine community for tests + run: | + pipx install cf-remote + cf-remote install --clients localhost --edition community + - name: Run make check for linting, formatting and tests + run: make check diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2eabceed --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: check lint format all clean tools + +all: tools clean lint format check + +tools: + sudo pipx install --global flake8 pyright black pyflakes pytest cfbs cfengine + echo "deploy test requires cf-agent installed..." + command -v cf-agent + +clean: + rm -rf tests/deploy/out + +lint: clean tools + cfbs status + cfbs validate + cfbs --check pretty ./cfbs.json + ./ci/linting.sh + cfengine lint --strict no ./ + +format: lint + cfengine format --check + +check: format + pytest promise-types/ -v From e0504ff3f7971e8a18463d8ee20531c53438f0e8 Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 20 Aug 2026 09:50:08 -0500 Subject: [PATCH 2/6] ENT-14328: Added simple test to add all modules and ensure the build works with provides from cfbs.json --- .gitignore | 2 ++ Makefile | 1 + tests/deploy/00-promise-run-no-errors.sh | 9 ++++++ tests/deploy/deploy.sh | 39 ++++++++++++++++++++++++ tests/deploy/test.sh | 7 +++++ 5 files changed, 58 insertions(+) create mode 100755 tests/deploy/00-promise-run-no-errors.sh create mode 100755 tests/deploy/deploy.sh create mode 100755 tests/deploy/test.sh diff --git a/.gitignore b/.gitignore index e5e89d59..8bfd5e5e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ node_modules/ build/ dist/ .cache +tests/deploy/cfbs.json +tests/deploy/out diff --git a/Makefile b/Makefile index 2eabceed..69f1f719 100644 --- a/Makefile +++ b/Makefile @@ -22,3 +22,4 @@ format: lint check: format pytest promise-types/ -v + bash tests/deploy/test.sh diff --git a/tests/deploy/00-promise-run-no-errors.sh b/tests/deploy/00-promise-run-no-errors.sh new file mode 100755 index 00000000..53291da5 --- /dev/null +++ b/tests/deploy/00-promise-run-no-errors.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# assumes deploy.sh has already run adjacent to this file + +set -ex +sudo cf-agent -KI > log +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi diff --git a/tests/deploy/deploy.sh b/tests/deploy/deploy.sh new file mode 100755 index 00000000..9744b2b3 --- /dev/null +++ b/tests/deploy/deploy.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -ex + +echo "WARNING/TODO: This test, $0, requires all changes to be pushed up to a branch in order to test the latest. This could be improved if cfbs add could work with the modules repo and a cfbs.json file. See ENT-14421" +if [ -n "$GITHUB_HEAD_REF" ]; then + # github case + BRANCH="$GITHUB_HEAD_REF" +else + # local case + BRANCH=$(git rev-parse --abbrev-ref HEAD) +fi + +# workaround, if git@ url then we get Error: Cannot specify more than one version of the same module +# so transform the remote url +REPO=$(git remote get-url origin | \ + sed -e 's,git@,https://,' \ + -e 's,com:,com/,' \ +) + +if [ -n "$GITHUB_HEAD_REF" ]; then + REPO="$(echo "$REPO" | sed -e "s,cfengine,$GITHUB_TRIGGERING_ACTOR,")" +fi + +thisdir="$(dirname "$0")" +cd "$thisdir" +[ -d .git ] && rm -rf .git +[ -f cfbs.json ] && rm cfbs.json +cfbs --version +cfbs init --non-interactive +cfbs --non-interactive add "$REPO@$BRANCH" +cfbs build +sudo cfbs install +sudo cf-agent -IB 127.0.0.1 > log + +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi + diff --git a/tests/deploy/test.sh b/tests/deploy/test.sh new file mode 100755 index 00000000..9d37d240 --- /dev/null +++ b/tests/deploy/test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -ex +thisdir="$(dirname "$0")" +bash "$thisdir"/deploy.sh +if ls "$thisdir"/0*.sh >/dev/null; then + bash "$thisdir"/0*.sh +fi From d251828b5c8ade5f5bad0af07f04a45ab0602122 Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 20 Aug 2026 09:52:07 -0500 Subject: [PATCH 3/6] Fixed typo in delete-home-dotshosts cfbs.json meta data --- cfbs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfbs.json b/cfbs.json index 9864d8b5..28a13649 100644 --- a/cfbs.json +++ b/cfbs.json @@ -144,7 +144,7 @@ }, "delete-home-dotshosts": { "description": "Ensure that ~/.shosts files are not present, as they present a security risk.", - "subdirectory": "security/delete-home-dotshots", + "subdirectory": "security/delete-home-dotshosts", "steps": [ "copy policy/main.cf services/cfbs/delete-home-dotshots/", "policy_files services/cfbs/delete-home-dotshots/", From 9b91840aff8666cdd932196e9c19f5de481a87be Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 20 Aug 2026 09:53:45 -0500 Subject: [PATCH 4/6] Fixed typo in uninstall-packages module meta data in cfbs.json --- cfbs.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cfbs.json b/cfbs.json index 28a13649..1a581dc3 100644 --- a/cfbs.json +++ b/cfbs.json @@ -497,10 +497,10 @@ "description": "Allows you to specify a list of packages you want uninstalled on your hosts.", "subdirectory": "security/uninstall-packages", "steps": [ - "copy uninstall-packages.cf services/cfbs/modules/uninstall-packages/uninstall-packages.cf", + "copy main.cf services/cfbs/modules/uninstall-packages/main.cf", "input uninstall-packages/input.json def.json", "bundles uninstall_packages:uninstall_packages", - "policy_files services/cfbs/modules/uninstall-packages/uninstall-packages.cf" + "policy_files services/cfbs/modules/uninstall-packages/main.cf" ], "input": [ { From 4828d095fb476e9e1d034d2a522afca2bf5ad12e Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 20 Aug 2026 10:19:28 -0500 Subject: [PATCH 5/6] Fixed inventory-smartctl policy to properly guard against smartctl not being installed --- inventory/inventory-smartctl/policy.cf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/inventory/inventory-smartctl/policy.cf b/inventory/inventory-smartctl/policy.cf index 7aae3302..2358b111 100644 --- a/inventory/inventory-smartctl/policy.cf +++ b/inventory/inventory-smartctl/policy.cf @@ -33,9 +33,12 @@ bundle agent main ); "_sdir" string => "$(sys.statedir)"; - "_cache_ttl" string => "3600"; - # 1 hour + "_cache_ttl" + string => "3600", + comment => "3600 seconds is 1 hour"; + + linux._have_smartctl:: # Enumerate drives - extract first field from each line of smartctl --scan "_scan_lines" slist => splitstring( @@ -52,7 +55,6 @@ bundle agent main "_cache[${_drives}]" string => "$(_sdir)/inventory_smartctl_${_id[${_drives}]}.json"; - linux._have_smartctl:: # Rolled-up status: OK or DEGRADED (SMARTCTL_MISSING when smartctl absent) "smartctl_status" string => "DEGRADED", From c402ded750b631e2ff3e0be6ab9046e382c7d3bb Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 20 Aug 2026 10:21:29 -0500 Subject: [PATCH 6/6] Added install-ansible module Added shell deploy test to ensure pipx and ansible are installed according to specific classes for minimal vs full install and specific version of ansible. Ticket: ENT-14328 --- cfbs.json | 9 +++ software/install-ansible.cf | 58 +++++++++++++++++++ tests/deploy/01-install-ansible-full-test.sh | 20 +++++++ .../deploy/02-install-ansible-minimal-test.sh | 16 +++++ .../03-install-ansible-versions-test.sh | 55 ++++++++++++++++++ .../deploy/04-install-ansible-default-test.sh | 20 +++++++ tests/deploy/test.sh | 4 +- 7 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 software/install-ansible.cf create mode 100755 tests/deploy/01-install-ansible-full-test.sh create mode 100644 tests/deploy/02-install-ansible-minimal-test.sh create mode 100644 tests/deploy/03-install-ansible-versions-test.sh create mode 100755 tests/deploy/04-install-ansible-default-test.sh diff --git a/cfbs.json b/cfbs.json index 1a581dc3..5f263a43 100644 --- a/cfbs.json +++ b/cfbs.json @@ -546,6 +546,15 @@ "bundles windows_capability" ] }, + "install-ansible": { + "description": "Optionally install ansible.", + "subdirectory": "software", + "steps": [ + "copy install-ansible.cf services/cfbs/software/install-ansible.cf", + "policy_files services/cfbs/software/install-ansible.cf", + "bundles install_ansible" + ] + }, "windows-openssh-server": { "description": "Optionally install Windows OpenSSH Server.", "subdirectory": "software/windows", diff --git a/software/install-ansible.cf b/software/install-ansible.cf new file mode 100644 index 00000000..f270da3b --- /dev/null +++ b/software/install-ansible.cf @@ -0,0 +1,58 @@ +# Steps here based on this guide: https://docs.ansible.com/projects/ansible/latest/installation_guide/intro_installation.html +# +# host specific data supported, in the data bundle context +# +# data:install_ansible: class, if defined, install ansible +# data:ansible_minimal_install: class, if defined, minimal install aka ansible-core +# data:ansible_full_install: class, if defined, full install. This is the default if neither minimal or full classes are defined. +bundle agent install_ansible +{ + methods: + linux.data:install_ansible:: + "install_ansible_main"; + + reports: + windows:: + "Use WSL to install Ansible on Windows. See https://blog.rolpdog.com/2020/03/why-no-ansible-controller-for-windows.html"; + + !linux.!windows:: + "Installing Ansible on a non-Linux/non-Windows host is not supported"; +} + +bundle agent install_ansible_main +{ + classes: + !windows:: + "ansible_installed" + expression => returnszero("command -v ansible >/dev/null", "useshell"); + + vars: + "install_ansible_command" + string => "${base_command}==${data:install_ansible.version}", + if => isvariable("data:install_ansible.version"); + + "install_ansible_command" + string => "${base_command}", + if => not(isvariable("data:install_ansible.version")); + + data:ansible_minimal_install:: + "base_command" string => "pipx install --global ansible-core"; + + data:ansible_full_install|(!data:ansible_full_install.!data:ansible_minimal_install):: + "base_command" string => "pipx install --global --include-deps ansible"; + + packages: + "pipx" classes => if_ok("pipx_installed"); + + commands: + pipx_installed.!ansible_installed:: + "${install_ansible_command}" + contain => in_shell_umask(022), + comment => "The default umask of 077 would create /opt/pipx/venvs/ansible which is inaccessible to everyone but root, so use 022 instead."; +} + +body contain in_shell_umask(umask) +{ + useshell => "true"; + umask => "${umask}"; +} diff --git a/tests/deploy/01-install-ansible-full-test.sh b/tests/deploy/01-install-ansible-full-test.sh new file mode 100755 index 00000000..29acb7b5 --- /dev/null +++ b/tests/deploy/01-install-ansible-full-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# assumes deploy.sh has already run adjacent to this file + +set -ex + +sudo pipx uninstall --global ansible || true +sudo pipx uninstall --global ansible-core || true + +sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_full_install --bundle install_ansible > log +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi + +ansible --version +echo "expect that ansible-core is not installed via pipx list" +if ( sudo pipx list --global --short | grep ansible-core ); then + echo "expected only ansible to be installed, but found ansible-core" + exit 1 +fi diff --git a/tests/deploy/02-install-ansible-minimal-test.sh b/tests/deploy/02-install-ansible-minimal-test.sh new file mode 100644 index 00000000..1386973d --- /dev/null +++ b/tests/deploy/02-install-ansible-minimal-test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -ex + +sudo pipx uninstall --global ansible || true +sudo pipx uninstall --global ansible-core || true + +sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_minimal_install --bundle install_ansible > log +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi + +ansible --version +if ! ( sudo pipx list --global --short | grep ansible-core ); then + echo "expected ansible-core to be installed but did not find that in pipx list output" +fi diff --git a/tests/deploy/03-install-ansible-versions-test.sh b/tests/deploy/03-install-ansible-versions-test.sh new file mode 100644 index 00000000..c777563b --- /dev/null +++ b/tests/deploy/03-install-ansible-versions-test.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -ex + +sudo pipx uninstall --global ansible || true +sudo pipx uninstall --global ansible-core || true + +function cleanup +{ + sudo rm -f /var/cfengine/data/host_specific.json || true # to make sure any version data is removed for other tests other runs +} + +trap cleanup EXIT + +good_version="2.21.3" + +sudo mkdir -p /var/cfengine/data +cat < log + +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi + +ansible --version | grep "${good_version}" + +sudo pipx uninstall --global ansible || true +sudo pipx uninstall --global ansible-core || true + +bad_version="x.y.z" +cat < log + +if grep 'error:' log; then + echo "Expected error found due to bad version value. Test passes." + grep 'error:' log + exit 0 +fi + +echo "Expected errors when installing ansible with bad version" +exit 1 diff --git a/tests/deploy/04-install-ansible-default-test.sh b/tests/deploy/04-install-ansible-default-test.sh new file mode 100755 index 00000000..9ecd442e --- /dev/null +++ b/tests/deploy/04-install-ansible-default-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# assumes deploy.sh has already run adjacent to this file + +set -ex + +sudo pipx uninstall --global ansible || true +sudo pipx uninstall --global ansible-core || true + +sudo cf-agent -Kd -Ddata:install_ansible --bundle install_ansible > log +if grep 'error:' log; then + grep 'error:' log + exit 1 +fi + +ansible --version +echo "expect that ansible(full) is installed and not ansible-core" +if ( sudo pipx list --global --short | grep ansible-core ); then + echo "expected ansible(full) to be installed, but found ansible-core" + exit 1 +fi diff --git a/tests/deploy/test.sh b/tests/deploy/test.sh index 9d37d240..3c8d9c4e 100755 --- a/tests/deploy/test.sh +++ b/tests/deploy/test.sh @@ -3,5 +3,7 @@ set -ex thisdir="$(dirname "$0")" bash "$thisdir"/deploy.sh if ls "$thisdir"/0*.sh >/dev/null; then - bash "$thisdir"/0*.sh + for test in "$thisdir"/0*.sh; do + bash -ex "$test" + done fi