cfengine 0.23.0__tar.gz → 0.23.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cfengine-0.23.0 → cfengine-0.23.2}/.coveragerc +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/lint-policy-in-other-repos.yml +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/make-check.yml +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/pypi-publish.yml +3 -3
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/renovate.yml +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/update-syntax-description.yml +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/Makefile +3 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/PKG-INFO +6 -6
- {cfengine-0.23.0 → cfengine-0.23.2}/pyproject.toml +9 -9
- cfengine-0.23.2/renovate.json5 +91 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/PKG-INFO +6 -6
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/SOURCES.txt +6 -1
- cfengine-0.23.2/src/cfengine.egg-info/requires.txt +7 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/scm_file_list.json +6 -1
- cfengine-0.23.2/src/cfengine.egg-info/scm_version.json +8 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/arg_parse.py +13 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_commands.py +28 -11
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_objects.py +4 -4
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_utils.py +6 -5
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/commands.py +12 -0
- cfengine-0.23.2/src/cfengine_cli/container.py +52 -0
- cfengine-0.23.2/src/cfengine_cli/docker/test-agent/Dockerfile +13 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/main.py +45 -6
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/syntax-description.json +23 -11
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/004_block_type.expected.txt +1 -1
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/run-shell-tests.sh +6 -0
- cfengine-0.23.2/tests/shell/006-test-fail.sh +26 -0
- cfengine-0.23.2/tests/shell/007-test-container.sh +14 -0
- cfengine-0.23.2/tests/shell/008-cfbs-index.sh +77 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/uv.lock +175 -170
- cfengine-0.23.0/renovate.json +0 -5
- cfengine-0.23.0/src/cfengine.egg-info/requires.txt +0 -7
- cfengine-0.23.0/src/cfengine.egg-info/scm_version.json +0 -8
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/renovate-config.js +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/coverage.yml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/.github/workflows/stale.yml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/.gitignore +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/.python-version +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/CHEATSHEET.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/CLAUDE.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/HACKING.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/LICENSE +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/README.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/ci/01-install.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/setup.cfg +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/__init__.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/changelog.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/docs.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/format.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/initialize_project.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/lint.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/lint_csv.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/lint_yml.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/syntax_tree.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/up.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/validate.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/README.md +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/004_comments.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/005_bundle_comments.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/005_bundle_comments.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/006_remove_empty_comments.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/006_remove_empty_comments.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/007_class_guarded_empty_lines.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/008_long_string.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/008_long_string.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/009_single_line.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/009_single_line.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/010_stakeholder.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/010_stakeholder.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/011_macros.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/011_macros.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/011_promises.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/011_promises.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/012_sameline_comments.expected.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/format/012_sameline_comments.input.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/001_hello_world.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/002_deprecations.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/002_deprecations.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/003_name_lowercase.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/003_name_lowercase.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/003_name_lowercase.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/004_block_type.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/004_block_type.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/005_syntax_error.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/005_syntax_error.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/005_syntax_error.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/006_empty_file.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/006_empty_file.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/007_namespace.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/007_namespace.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/007_namespace.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/011_invalid_attributes.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/011_invalid_attributes.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/013_num_args_body.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/013_num_args_body.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/013_num_args_bundle.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/013_num_args_bundle.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/013_num_args_bundle_body.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/016_half_promises.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/016_half_promises.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/016_half_promises.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/017_implies_body.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/017_implies_body.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/017_implies_body.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/018_nested_calls.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/018_nested_calls.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/018_nested_calls.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/019_bundle_name_expansion.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/020_missing_braces.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/020_missing_braces.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/020_missing_semicolon.expected.txt +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/020_missing_semicolon.x.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/lint/021_reactor_strtotime_silence.cf +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/run-format-tests.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/run-lint-tests.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/run-up-validate-tests.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/shell/001-help.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/shell/002-version.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/shell/003-format.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/shell/004-format-check.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/shell/005-lint.sh +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/__init__.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_changelog.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_deps.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_format.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_lint_csv.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_lint_yml.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_paths.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_utils.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/unit/test_version.py +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/001_complex_config.yaml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/002_version.x.yaml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/003_box.x.yaml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/004_count.x.yaml +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/mocks/cloud_config.json +0 -0
- {cfengine-0.23.0 → cfengine-0.23.2}/tests/up-validate/mocks/vagrant +0 -0
|
@@ -5,7 +5,7 @@ on:
|
|
|
5
5
|
types: [published]
|
|
6
6
|
jobs:
|
|
7
7
|
release-build:
|
|
8
|
-
runs-on: ubuntu-
|
|
8
|
+
runs-on: ubuntu-26.04
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
steps:
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
name: release-dists
|
|
27
27
|
path: dist/
|
|
28
28
|
pre-release-tests:
|
|
29
|
-
runs-on: ubuntu-
|
|
29
|
+
runs-on: ubuntu-26.04
|
|
30
30
|
permissions:
|
|
31
31
|
contents: read
|
|
32
32
|
steps:
|
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
uv build
|
|
39
39
|
uv run pytest
|
|
40
40
|
pypi-publish:
|
|
41
|
-
runs-on: ubuntu-
|
|
41
|
+
runs-on: ubuntu-26.04
|
|
42
42
|
needs:
|
|
43
43
|
- release-build
|
|
44
44
|
- pre-release-tests
|
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
- name: Checkout
|
|
13
13
|
uses: actions/checkout@v7.0.1
|
|
14
14
|
- name: Self-hosted Renovate
|
|
15
|
-
uses: renovatebot/github-action@v46.
|
|
15
|
+
uses: renovatebot/github-action@v46.3.6
|
|
16
16
|
with:
|
|
17
17
|
configurationFile: .github/renovate-config.js
|
|
18
18
|
token: ${{ secrets.RENOVATE_TOKEN }}
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
update_syntax_desc:
|
|
16
16
|
if: contains(fromJSON('["cfengine","mendersoftware","NorthernTechHQ"]'), github.repository_owner)
|
|
17
17
|
name: Update syntax-description
|
|
18
|
-
runs-on: ubuntu-
|
|
18
|
+
runs-on: ubuntu-26.04
|
|
19
19
|
permissions:
|
|
20
20
|
contents: write
|
|
21
21
|
pull-requests: write
|
|
@@ -23,7 +23,9 @@ install:
|
|
|
23
23
|
pipx install --force --editable .
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
export COVERAGE_PROCESS_START = $(PWD)/.coveragerc
|
|
26
|
+
coverage: export COVERAGE_PROCESS_START = $(PWD)/.coveragerc
|
|
27
|
+
coverage: export COVERAGE_FILE = $(PWD)/.coverage
|
|
28
|
+
coverage: export PROJECT_ROOT = $(PWD)
|
|
27
29
|
coverage:
|
|
28
30
|
uv run coverage erase
|
|
29
31
|
uv run coverage run --parallel-mode -m pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine policy language, projects, and other CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -694,13 +694,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
694
694
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
695
695
|
Requires-Python: >=3.10
|
|
696
696
|
Description-Content-Type: text/markdown
|
|
697
|
-
Requires-Dist: cf-remote>=0.9.
|
|
698
|
-
Requires-Dist: cfbs>=5.
|
|
697
|
+
Requires-Dist: cf-remote>=0.9.6
|
|
698
|
+
Requires-Dist: cfbs>=5.8.1
|
|
699
699
|
Requires-Dist: tree-sitter-cfengine>=1.1.12
|
|
700
|
-
Requires-Dist: tree-sitter>=0.
|
|
701
|
-
Requires-Dist: markdown-it-py>=
|
|
700
|
+
Requires-Dist: tree-sitter>=0.26.0
|
|
701
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
702
702
|
Requires-Dist: pyyaml>=6.0.3
|
|
703
|
-
Requires-Dist: pydantic>=2.
|
|
703
|
+
Requires-Dist: pydantic>=2.13.5
|
|
704
704
|
|
|
705
705
|
# CFEngine command line interface (CLI)
|
|
706
706
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=
|
|
2
|
+
requires = ["setuptools>=84.0.0", "setuptools-scm>=10.3.4"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
@@ -10,13 +10,13 @@ readme = "README.md"
|
|
|
10
10
|
license = {file = "LICENSE"}
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
dependencies = [
|
|
13
|
-
"cf-remote>=0.9.
|
|
14
|
-
"cfbs>=5.
|
|
13
|
+
"cf-remote>=0.9.6",
|
|
14
|
+
"cfbs>=5.8.1",
|
|
15
15
|
"tree-sitter-cfengine>=1.1.12",
|
|
16
|
-
"tree-sitter>=0.
|
|
17
|
-
"markdown-it-py>=
|
|
16
|
+
"tree-sitter>=0.26.0",
|
|
17
|
+
"markdown-it-py>=4.2.0",
|
|
18
18
|
"pyyaml>=6.0.3",
|
|
19
|
-
"pydantic>=2.
|
|
19
|
+
"pydantic>=2.13.5",
|
|
20
20
|
]
|
|
21
21
|
classifiers = [
|
|
22
22
|
"Development Status :: 3 - Alpha",
|
|
@@ -43,7 +43,7 @@ cfengine = "cfengine_cli.main:main"
|
|
|
43
43
|
license-files = [] # Workaround bug in setuptools https://github.com/astral-sh/uv/issues/9513
|
|
44
44
|
|
|
45
45
|
[tool.setuptools.package-data]
|
|
46
|
-
cfengine_cli = ["*.json"] # syntax-description.json
|
|
46
|
+
cfengine_cli = ["*.json", "docker/test-agent/Dockerfile"] # syntax-description.json, cfengine test's container
|
|
47
47
|
|
|
48
48
|
[tool.pyright]
|
|
49
49
|
include = ["src"]
|
|
@@ -54,7 +54,7 @@ venv = ".venv"
|
|
|
54
54
|
|
|
55
55
|
[dependency-groups]
|
|
56
56
|
dev = [
|
|
57
|
-
"flake8>=7.1
|
|
58
|
-
"pytest>=
|
|
57
|
+
"flake8>=7.4.1",
|
|
58
|
+
"pytest>=9.1.1",
|
|
59
59
|
"coverage; python_version >= '3.10'",
|
|
60
60
|
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Global (self-hosted) settings are in .github/renovate-config.js,
|
|
2
|
+
// the runner workflow is .github/workflows/renovate.yml.
|
|
3
|
+
{
|
|
4
|
+
$schema: "https://docs.renovatebot.com/renovate-schema.json",
|
|
5
|
+
extends: ["config:recommended"],
|
|
6
|
+
reviewers: ["larsewi", "olehermanse"],
|
|
7
|
+
|
|
8
|
+
// Renovate does not infer maintenance branches from git, they have to be
|
|
9
|
+
// named here.
|
|
10
|
+
baseBranchPatterns: ["main"],
|
|
11
|
+
|
|
12
|
+
// Rebasing on every push to main would restart a pipeline per open PR.
|
|
13
|
+
rebaseWhen: "conflicted",
|
|
14
|
+
|
|
15
|
+
// The workflow runs once a day, so an hourly limit would act as a daily
|
|
16
|
+
// limit. Let the concurrent limit do the throttling.
|
|
17
|
+
prHourlyLimit: 0,
|
|
18
|
+
prConcurrentLimit: 5,
|
|
19
|
+
|
|
20
|
+
// Transitive deps only exist in uv.lock, so nothing in pyproject.toml
|
|
21
|
+
// reaches them. Replaces dependabot's "uv" ecosystem.
|
|
22
|
+
lockFileMaintenance: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
schedule: ["before 5am on monday"],
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// osvVulnerabilityAlerts does not depend on the PAT being able to read
|
|
28
|
+
// GitHub's own alerts API.
|
|
29
|
+
vulnerabilityAlerts: {
|
|
30
|
+
enabled: true,
|
|
31
|
+
schedule: ["at any time"],
|
|
32
|
+
labels: ["security"],
|
|
33
|
+
},
|
|
34
|
+
osvVulnerabilityAlerts: true,
|
|
35
|
+
|
|
36
|
+
packageRules: [
|
|
37
|
+
// pyproject.toml uses ">=" floors, which newer releases already satisfy,
|
|
38
|
+
// so the default rangeStrategy proposes nothing. "bump" raises the floor.
|
|
39
|
+
{
|
|
40
|
+
matchManagers: ["pep621"],
|
|
41
|
+
rangeStrategy: "bump",
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
matchManagers: ["pep621"],
|
|
46
|
+
matchDepTypes: ["project.dependencies", "build-system.requires"],
|
|
47
|
+
groupName: "python-dependencies",
|
|
48
|
+
groupSlug: "python-deps",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
matchManagers: ["pep621"],
|
|
52
|
+
matchDepTypes: ["dependency-groups"],
|
|
53
|
+
groupName: "python-dev-dependencies",
|
|
54
|
+
groupSlug: "python-dev-deps",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Bumping CFEngine's own packages is a product decision. Must stay after
|
|
58
|
+
// the python-dependencies rule above: packageRules are last-match-wins.
|
|
59
|
+
{
|
|
60
|
+
matchManagers: ["pep621"],
|
|
61
|
+
matchDepTypes: ["project.dependencies"],
|
|
62
|
+
matchPackageNames: ["cf-remote", "cfbs", "tree-sitter-cfengine"],
|
|
63
|
+
groupName: "cfengine-dependencies",
|
|
64
|
+
groupSlug: "cfengine-deps",
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Majors stay separate so they get a real review.
|
|
68
|
+
{
|
|
69
|
+
matchManagers: ["github-actions"],
|
|
70
|
+
matchUpdateTypes: ["minor", "patch", "digest"],
|
|
71
|
+
groupName: "github-actions",
|
|
72
|
+
groupSlug: "github-actions",
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// The python version is also pinned in the make-check matrix and in the
|
|
76
|
+
// classifiers, which Renovate cannot reach. One PR, not three.
|
|
77
|
+
{
|
|
78
|
+
matchDepNames: ["python"],
|
|
79
|
+
groupName: "python-version",
|
|
80
|
+
groupSlug: "python-version",
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Support floor, not a dependency. "bump" would raise it to ">=3.14.7"
|
|
84
|
+
// and drop 3.10 - 3.13, which make-check.yml still tests.
|
|
85
|
+
{
|
|
86
|
+
matchManagers: ["pep621"],
|
|
87
|
+
matchDepTypes: ["requires-python"],
|
|
88
|
+
enabled: false,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine policy language, projects, and other CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -694,13 +694,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
694
694
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
695
695
|
Requires-Python: >=3.10
|
|
696
696
|
Description-Content-Type: text/markdown
|
|
697
|
-
Requires-Dist: cf-remote>=0.9.
|
|
698
|
-
Requires-Dist: cfbs>=5.
|
|
697
|
+
Requires-Dist: cf-remote>=0.9.6
|
|
698
|
+
Requires-Dist: cfbs>=5.8.1
|
|
699
699
|
Requires-Dist: tree-sitter-cfengine>=1.1.12
|
|
700
|
-
Requires-Dist: tree-sitter>=0.
|
|
701
|
-
Requires-Dist: markdown-it-py>=
|
|
700
|
+
Requires-Dist: tree-sitter>=0.26.0
|
|
701
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
702
702
|
Requires-Dist: pyyaml>=6.0.3
|
|
703
|
-
Requires-Dist: pydantic>=2.
|
|
703
|
+
Requires-Dist: pydantic>=2.13.5
|
|
704
704
|
|
|
705
705
|
# CFEngine command line interface (CLI)
|
|
706
706
|
|
|
@@ -8,7 +8,7 @@ LICENSE
|
|
|
8
8
|
Makefile
|
|
9
9
|
README.md
|
|
10
10
|
pyproject.toml
|
|
11
|
-
renovate.
|
|
11
|
+
renovate.json5
|
|
12
12
|
uv.lock
|
|
13
13
|
.github/renovate-config.js
|
|
14
14
|
.github/workflows/coverage.yml
|
|
@@ -33,6 +33,7 @@ src/cfengine_cli/__init__.py
|
|
|
33
33
|
src/cfengine_cli/__main__.py
|
|
34
34
|
src/cfengine_cli/changelog.py
|
|
35
35
|
src/cfengine_cli/commands.py
|
|
36
|
+
src/cfengine_cli/container.py
|
|
36
37
|
src/cfengine_cli/deptool-README.md
|
|
37
38
|
src/cfengine_cli/deptool.py
|
|
38
39
|
src/cfengine_cli/dev.py
|
|
@@ -57,6 +58,7 @@ src/cfengine_cli/cfengine_wrapper/arg_parse.py
|
|
|
57
58
|
src/cfengine_cli/cfengine_wrapper/cfengine_commands.py
|
|
58
59
|
src/cfengine_cli/cfengine_wrapper/cfengine_objects.py
|
|
59
60
|
src/cfengine_cli/cfengine_wrapper/cfengine_utils.py
|
|
61
|
+
src/cfengine_cli/docker/test-agent/Dockerfile
|
|
60
62
|
src/cfengine_cli/masterfiles/__init__.py
|
|
61
63
|
src/cfengine_cli/masterfiles/analyze.py
|
|
62
64
|
src/cfengine_cli/masterfiles/check_download_matches_git.py
|
|
@@ -158,6 +160,9 @@ tests/shell/002-version.sh
|
|
|
158
160
|
tests/shell/003-format.sh
|
|
159
161
|
tests/shell/004-format-check.sh
|
|
160
162
|
tests/shell/005-lint.sh
|
|
163
|
+
tests/shell/006-test-fail.sh
|
|
164
|
+
tests/shell/007-test-container.sh
|
|
165
|
+
tests/shell/008-cfbs-index.sh
|
|
161
166
|
tests/unit/__init__.py
|
|
162
167
|
tests/unit/test_changelog.py
|
|
163
168
|
tests/unit/test_deps.py
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"ci/02-safe-tests.sh",
|
|
22
22
|
"ci/03-unsafe-tests.sh",
|
|
23
23
|
"pyproject.toml",
|
|
24
|
-
"renovate.
|
|
24
|
+
"renovate.json5",
|
|
25
25
|
"src/cfengine_cli/__init__.py",
|
|
26
26
|
"src/cfengine_cli/__main__.py",
|
|
27
27
|
"src/cfengine_cli/cfengine_wrapper/__init__.py",
|
|
@@ -31,9 +31,11 @@
|
|
|
31
31
|
"src/cfengine_cli/cfengine_wrapper/cfengine_utils.py",
|
|
32
32
|
"src/cfengine_cli/changelog.py",
|
|
33
33
|
"src/cfengine_cli/commands.py",
|
|
34
|
+
"src/cfengine_cli/container.py",
|
|
34
35
|
"src/cfengine_cli/deptool-README.md",
|
|
35
36
|
"src/cfengine_cli/deptool.py",
|
|
36
37
|
"src/cfengine_cli/dev.py",
|
|
38
|
+
"src/cfengine_cli/docker/test-agent/Dockerfile",
|
|
37
39
|
"src/cfengine_cli/docs.py",
|
|
38
40
|
"src/cfengine_cli/format.py",
|
|
39
41
|
"src/cfengine_cli/initialize_project.py",
|
|
@@ -151,6 +153,9 @@
|
|
|
151
153
|
"tests/shell/003-format.sh",
|
|
152
154
|
"tests/shell/004-format-check.sh",
|
|
153
155
|
"tests/shell/005-lint.sh",
|
|
156
|
+
"tests/shell/006-test-fail.sh",
|
|
157
|
+
"tests/shell/007-test-container.sh",
|
|
158
|
+
"tests/shell/008-cfbs-index.sh",
|
|
154
159
|
"tests/unit/__init__.py",
|
|
155
160
|
"tests/unit/test_changelog.py",
|
|
156
161
|
"tests/unit/test_deps.py",
|
|
@@ -11,6 +11,15 @@ from cf_remote.args import (
|
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def _add_index_arg(parser: argparse.ArgumentParser):
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"--index",
|
|
17
|
+
help="Specify alternate index (HTTPS URL or relative path to JSON file)",
|
|
18
|
+
type=str,
|
|
19
|
+
default=None,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
14
23
|
def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
15
24
|
update_parser = subp.add_parser(
|
|
16
25
|
"update",
|
|
@@ -20,7 +29,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
20
29
|
update_parser.add_argument(
|
|
21
30
|
"to_update",
|
|
22
31
|
nargs="*",
|
|
23
|
-
help="
|
|
32
|
+
help="Module(s) to update (all modules if omitted)",
|
|
24
33
|
)
|
|
25
34
|
remove_parser = subp.add_parser(
|
|
26
35
|
"remove",
|
|
@@ -43,6 +52,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
43
52
|
nargs="+",
|
|
44
53
|
help="Module(s) for which to add",
|
|
45
54
|
)
|
|
55
|
+
_add_index_arg(add_parser)
|
|
46
56
|
search_parser = subp.add_parser(
|
|
47
57
|
"search",
|
|
48
58
|
help="Searches the build-index for specified module(s)",
|
|
@@ -53,6 +63,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
53
63
|
nargs="+",
|
|
54
64
|
help="Module(s) for which to lookup",
|
|
55
65
|
)
|
|
66
|
+
_add_index_arg(search_parser)
|
|
56
67
|
|
|
57
68
|
input_parser = subp.add_parser(
|
|
58
69
|
"input",
|
|
@@ -84,6 +95,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
84
95
|
nargs="*",
|
|
85
96
|
help="Module(s) for which you would like more info, utilizes cfbs `info` function",
|
|
86
97
|
)
|
|
98
|
+
_add_index_arg(moduleinfo_parser)
|
|
87
99
|
|
|
88
100
|
show_parser = subp.add_parser(
|
|
89
101
|
"show", help="Shows your saved host-groups or info about a specified host"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
+
from cfbs.cfbs_config import CFBSConfig
|
|
3
4
|
from cfbs.utils import is_cfbs_repo
|
|
5
|
+
from cfbs.validate import validate_index_string
|
|
4
6
|
from cfbs.commands import (
|
|
5
7
|
build_command,
|
|
6
8
|
info_command,
|
|
@@ -22,6 +24,7 @@ from cfbs.commands import (
|
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
from cfengine_cli.utils import UserError
|
|
27
|
+
from cfengine_cli.container import run_in_container
|
|
25
28
|
from cfengine_cli.cfengine_wrapper.cfengine_objects import (
|
|
26
29
|
Executable,
|
|
27
30
|
ensure_default_agent_flags,
|
|
@@ -271,10 +274,7 @@ def deploy(
|
|
|
271
274
|
|
|
272
275
|
# TODO/WOULD be nice: Deploy without run (CFE-4704: https://northerntech.atlassian.net/browse/CFE-4704)
|
|
273
276
|
if hubs:
|
|
274
|
-
|
|
275
|
-
deploy_targets = [
|
|
276
|
-
"localhost" if location == "local" else location for location in hubs
|
|
277
|
-
]
|
|
277
|
+
deploy_targets = [location for location in hubs]
|
|
278
278
|
error = deploy_command(deploy_targets, masterfiles)
|
|
279
279
|
else:
|
|
280
280
|
return deploy_command(hubs, masterfiles)
|
|
@@ -287,6 +287,14 @@ def deploy(
|
|
|
287
287
|
return error
|
|
288
288
|
|
|
289
289
|
|
|
290
|
+
def test() -> int:
|
|
291
|
+
rc = build_command()
|
|
292
|
+
if rc != 0:
|
|
293
|
+
return rc
|
|
294
|
+
|
|
295
|
+
return run_in_container("out/masterfiles")
|
|
296
|
+
|
|
297
|
+
|
|
290
298
|
def show(target: list[str] | None = None) -> int:
|
|
291
299
|
if target == [] or target is None:
|
|
292
300
|
return show_command(False)
|
|
@@ -295,7 +303,14 @@ def show(target: list[str] | None = None) -> int:
|
|
|
295
303
|
return info(target)
|
|
296
304
|
|
|
297
305
|
|
|
298
|
-
def
|
|
306
|
+
def _init_cfbs_config(index: str | None = None) -> None:
|
|
307
|
+
if index is not None:
|
|
308
|
+
validate_index_string(index)
|
|
309
|
+
CFBSConfig.get_instance(index=index)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def moduleinfo(modules: list[str], index: str | None = None) -> int:
|
|
313
|
+
_init_cfbs_config(index)
|
|
299
314
|
if modules != []:
|
|
300
315
|
return info_command(modules)
|
|
301
316
|
if not is_cfbs_repo():
|
|
@@ -312,17 +327,19 @@ def cfbs_input(modules: list[str]) -> int:
|
|
|
312
327
|
return input_command(modules, "cfengine input")
|
|
313
328
|
|
|
314
329
|
|
|
315
|
-
def cfbs_add(modules: list[str]) -> int:
|
|
316
|
-
|
|
330
|
+
def cfbs_add(modules: list[str], index: str | None = None) -> int:
|
|
331
|
+
_init_cfbs_config(index)
|
|
332
|
+
return add_command(modules, "cfengine add")
|
|
317
333
|
|
|
318
334
|
|
|
319
|
-
def cfbs_remove(modules: list[str]
|
|
320
|
-
return remove_command(modules
|
|
335
|
+
def cfbs_remove(modules: list[str]) -> int:
|
|
336
|
+
return remove_command(modules)
|
|
321
337
|
|
|
322
338
|
|
|
323
|
-
def cfbs_update(to_update) -> int:
|
|
339
|
+
def cfbs_update(to_update: list[str]) -> int:
|
|
324
340
|
return update_command(to_update)
|
|
325
341
|
|
|
326
342
|
|
|
327
|
-
def cfbs_search(modules: list[str]) -> int:
|
|
343
|
+
def cfbs_search(modules: list[str], index: str | None = None) -> int:
|
|
344
|
+
_init_cfbs_config(index)
|
|
328
345
|
return search_command(modules)
|
|
@@ -27,14 +27,14 @@ def ensure_default_agent_flags(command: str) -> str:
|
|
|
27
27
|
class Executable:
|
|
28
28
|
"""
|
|
29
29
|
A single binary (cf-agent or cf-hub) at a known location -- either
|
|
30
|
-
|
|
30
|
+
localhost or a remote host identifier ("user@ip"). Knows its own path
|
|
31
31
|
and how to run a command against itself, whether that means a local
|
|
32
32
|
subprocess or an SSH call via cf-remote.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
35
|
def __init__(self, name: str, location: str, path: str, aliases=None) -> None:
|
|
36
36
|
self.name = name # "cf-agent" / "cf-hub"
|
|
37
|
-
self.location = location # "
|
|
37
|
+
self.location = location # "localhost" or "user@ip"
|
|
38
38
|
self.path = path # absolute path to the binary at that location
|
|
39
39
|
self.aliases = (
|
|
40
40
|
aliases or []
|
|
@@ -42,7 +42,7 @@ class Executable:
|
|
|
42
42
|
|
|
43
43
|
@property
|
|
44
44
|
def is_local(self) -> bool:
|
|
45
|
-
return self.location == "
|
|
45
|
+
return self.location == "localhost"
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def label(self) -> str:
|
|
@@ -102,7 +102,7 @@ class Installation:
|
|
|
102
102
|
|
|
103
103
|
@property
|
|
104
104
|
def is_local(self) -> bool:
|
|
105
|
-
return self.location == "
|
|
105
|
+
return self.location == "localhost"
|
|
106
106
|
|
|
107
107
|
@property
|
|
108
108
|
def aliases(self) -> list:
|
|
@@ -111,21 +111,22 @@ _Id = namedtuple("_Id", "location aliases")
|
|
|
111
111
|
|
|
112
112
|
def _identities(binary_name: str) -> Iterator[_Id]:
|
|
113
113
|
"""local + every known host as (location, aliases), without connecting."""
|
|
114
|
-
yield _Id("
|
|
114
|
+
yield _Id("localhost", ["localhost", "local"])
|
|
115
115
|
for host, aliases in _known_hosts(None if binary_name == "cf-agent" else "hub"):
|
|
116
116
|
yield _Id(host, aliases)
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
def _resolve(binary_name: str, ident: _Id) -> Executable | None:
|
|
120
120
|
"""Connect (if remote) and build an Executable, or None if unavailable."""
|
|
121
|
-
if ident.location == "
|
|
121
|
+
if ident.location == "localhost":
|
|
122
122
|
path = _find_local_path(binary_name)
|
|
123
|
-
return Executable(binary_name, "
|
|
123
|
+
return Executable(binary_name, "localhost", path) if path else None
|
|
124
124
|
data = _host_info(ident.location)
|
|
125
125
|
if not data:
|
|
126
126
|
return None
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
path = data.get("agent") if binary_name == "cf-agent" else data.get("hub")
|
|
128
|
+
if not path:
|
|
129
|
+
return None
|
|
129
130
|
return (
|
|
130
131
|
Executable(binary_name, ident.location, path, ident.aliases) if path else None
|
|
131
132
|
)
|
|
@@ -12,6 +12,7 @@ from cfengine_cli.up import validate_config, up_do, resolve_templates
|
|
|
12
12
|
from cfengine_cli.initialize_project import init_policy_module, init_promise_type
|
|
13
13
|
from cf_remote.paths import cf_remote_dir
|
|
14
14
|
from cfbs.commands import init_command
|
|
15
|
+
from cfengine_cli.cfengine_wrapper.cfengine_commands import test as _cfengine_test
|
|
15
16
|
from pydantic import ValidationError
|
|
16
17
|
|
|
17
18
|
|
|
@@ -47,6 +48,17 @@ def lint(files, strict, syntax_path) -> int:
|
|
|
47
48
|
return errors
|
|
48
49
|
|
|
49
50
|
|
|
51
|
+
def test(files, strict) -> int:
|
|
52
|
+
errors = _lint(files, strict, None)
|
|
53
|
+
if errors != 0:
|
|
54
|
+
plural = "error" if errors == 1 else "errors"
|
|
55
|
+
print(f"Lint failed, {errors} {plural} in total. Skipping build/deploy/run.")
|
|
56
|
+
return errors
|
|
57
|
+
|
|
58
|
+
print("Lint passed, no errors found.")
|
|
59
|
+
return _cfengine_test()
|
|
60
|
+
|
|
61
|
+
|
|
50
62
|
def dev(subcommand, args) -> int:
|
|
51
63
|
return dispatch_dev_subcommand(subcommand, args)
|
|
52
64
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from cfengine_cli.utils import UserError
|
|
6
|
+
|
|
7
|
+
_DOCKERFILE_DIR = os.path.join(os.path.dirname(__file__), "docker", "test-agent")
|
|
8
|
+
_IMAGE_TAG = "cfengine-cli-test-agent:latest"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def require_docker() -> None:
|
|
12
|
+
if shutil.which("docker") is None:
|
|
13
|
+
raise UserError(
|
|
14
|
+
"`cfengine test` runs the built policy set inside a Docker container -- install Docker to use it."
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ensure_image_built() -> None:
|
|
19
|
+
result = subprocess.run(
|
|
20
|
+
["docker", "build", "-q", "-t", _IMAGE_TAG, _DOCKERFILE_DIR]
|
|
21
|
+
)
|
|
22
|
+
if result.returncode != 0:
|
|
23
|
+
raise UserError("Failed to build the cfengine-test Docker image.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def run_in_container(masterfiles_dir: str) -> int:
|
|
27
|
+
"""
|
|
28
|
+
Runs cf-agent against the given built masterfiles directory inside a container
|
|
29
|
+
"""
|
|
30
|
+
require_docker()
|
|
31
|
+
_ensure_image_built()
|
|
32
|
+
|
|
33
|
+
abs_masterfiles = os.path.abspath(masterfiles_dir)
|
|
34
|
+
result = subprocess.run(
|
|
35
|
+
[
|
|
36
|
+
"docker",
|
|
37
|
+
"run",
|
|
38
|
+
"--rm",
|
|
39
|
+
"-v",
|
|
40
|
+
f"{abs_masterfiles}:/mnt/masterfiles:ro",
|
|
41
|
+
_IMAGE_TAG,
|
|
42
|
+
"sh",
|
|
43
|
+
"-c",
|
|
44
|
+
"rm -rf /var/cfengine/inputs "
|
|
45
|
+
"&& rm -rf /var/cfengine/masterfiles "
|
|
46
|
+
"&& cp -r /mnt/masterfiles /var/cfengine/masterfiles "
|
|
47
|
+
"&& /var/cfengine/bin/cf-agent --bootstrap 127.0.0.1 "
|
|
48
|
+
"&& /var/cfengine/bin/cf-agent -KIf update.cf "
|
|
49
|
+
"&& /var/cfengine/bin/cf-agent -KI",
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
return result.returncode
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
FROM debian:13-slim
|
|
2
|
+
ENV PATH="/root/.local/bin:${PATH}"
|
|
3
|
+
|
|
4
|
+
RUN apt-get update \
|
|
5
|
+
&& apt-get install -y --no-install-recommends \
|
|
6
|
+
python3 pipx sudo procps
|
|
7
|
+
|
|
8
|
+
RUN pipx install cfengine
|
|
9
|
+
|
|
10
|
+
RUN cfengine install --clients localhost --edition community
|
|
11
|
+
|
|
12
|
+
RUN mkdir -p /var/cfengine/bin/ \
|
|
13
|
+
&& ln -sf "$(command -v python3)" /var/cfengine/bin/cfengine-selected-python
|