cfengine 0.12.0__tar.gz → 0.12.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.12.0 → cfengine-0.12.2}/PKG-INFO +18 -1
- {cfengine-0.12.0 → cfengine-0.12.2}/README.md +17 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/PKG-INFO +18 -1
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/lint.py +65 -17
- {cfengine-0.12.0 → cfengine-0.12.2}/.github/dependabot.yml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.github/workflows/format.yml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.github/workflows/lint.yml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.github/workflows/pypi-publish.yml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.github/workflows/test.yml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.gitignore +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/.python-version +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/HACKING.md +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/LICENSE +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/ci/01-install.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/pyproject.toml +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/setup.cfg +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/SOURCES.txt +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/requires.txt +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/commands.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/docs.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/format.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/main.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/policy_language.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/__init__.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/004_comments.expected.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/run-format-tests.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/run-shell-tests.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/shell/001-help.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/shell/002-version.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/shell/003-format.sh +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/test_deps.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/test_paths.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/test_utils.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/tests/test_version.py +0 -0
- {cfengine-0.12.0 → cfengine-0.12.2}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -749,6 +749,23 @@ cfengine format
|
|
|
749
749
|
cfengine lint
|
|
750
750
|
```
|
|
751
751
|
|
|
752
|
+
You can also specify filenames or folders;
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
cfengine lint main.cf
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
When it finds a mistake, it points out where the problem is like this;
|
|
759
|
+
|
|
760
|
+
```
|
|
761
|
+
"Hello, CFEngine"
|
|
762
|
+
ifvarclass => "cfengine";
|
|
763
|
+
^--------^
|
|
764
|
+
Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
|
|
765
|
+
FAIL: main.cf (1 errors)
|
|
766
|
+
Failure, 1 errors in total.
|
|
767
|
+
```
|
|
768
|
+
|
|
752
769
|
Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
|
|
753
770
|
`cf-agent` could point out something as a syntax error, while `cfengine lint` does not and vice versa.
|
|
754
771
|
We aim to make the tree-sitter parser (used in this tool) more strict in general, so that when `cfengine lint` is happy with your policy, `cf-agent` will also accept it.
|
|
@@ -47,6 +47,23 @@ cfengine format
|
|
|
47
47
|
cfengine lint
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
You can also specify filenames or folders;
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
cfengine lint main.cf
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
When it finds a mistake, it points out where the problem is like this;
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
"Hello, CFEngine"
|
|
60
|
+
ifvarclass => "cfengine";
|
|
61
|
+
^--------^
|
|
62
|
+
Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
|
|
63
|
+
FAIL: main.cf (1 errors)
|
|
64
|
+
Failure, 1 errors in total.
|
|
65
|
+
```
|
|
66
|
+
|
|
50
67
|
Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
|
|
51
68
|
`cf-agent` could point out something as a syntax error, while `cfengine lint` does not and vice versa.
|
|
52
69
|
We aim to make the tree-sitter parser (used in this tool) more strict in general, so that when `cfengine lint` is happy with your policy, `cf-agent` will also accept it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -749,6 +749,23 @@ cfengine format
|
|
|
749
749
|
cfengine lint
|
|
750
750
|
```
|
|
751
751
|
|
|
752
|
+
You can also specify filenames or folders;
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
cfengine lint main.cf
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
When it finds a mistake, it points out where the problem is like this;
|
|
759
|
+
|
|
760
|
+
```
|
|
761
|
+
"Hello, CFEngine"
|
|
762
|
+
ifvarclass => "cfengine";
|
|
763
|
+
^--------^
|
|
764
|
+
Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
|
|
765
|
+
FAIL: main.cf (1 errors)
|
|
766
|
+
Failure, 1 errors in total.
|
|
767
|
+
```
|
|
768
|
+
|
|
752
769
|
Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
|
|
753
770
|
`cf-agent` could point out something as a syntax error, while `cfengine lint` does not and vice versa.
|
|
754
771
|
We aim to make the tree-sitter parser (used in this tool) more strict in general, so that when `cfengine lint` is happy with your policy, `cf-agent` will also accept it.
|
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import json
|
|
15
15
|
import itertools
|
|
16
16
|
import tree_sitter_cfengine as tscfengine
|
|
17
|
+
from dataclasses import dataclass
|
|
17
18
|
from tree_sitter import Language, Parser
|
|
18
19
|
from cfbs.validate import validate_config
|
|
19
20
|
from cfbs.cfbs_config import CFBSConfig
|
|
@@ -26,6 +27,39 @@ from cfengine_cli.policy_language import (
|
|
|
26
27
|
)
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
@dataclass
|
|
31
|
+
class _State:
|
|
32
|
+
block_type: str | None = None # "bundle" | "body" | "promise" | None
|
|
33
|
+
promise_type: str | None = None # "vars" | "files" | "classes" | ... | None
|
|
34
|
+
attribute_name: str | None = None # "if" | "string" | "slist" | ... | None
|
|
35
|
+
|
|
36
|
+
def update(self, node) -> "_State":
|
|
37
|
+
"""Updates and returns the state that should apply to the children of `node`."""
|
|
38
|
+
if node.type == "bundle_block":
|
|
39
|
+
return _State(block_type="bundle")
|
|
40
|
+
if node.type == "body_block":
|
|
41
|
+
return _State(block_type="body")
|
|
42
|
+
if node.type == "promise_block":
|
|
43
|
+
return _State(block_type="promise")
|
|
44
|
+
if node.type == "bundle_section":
|
|
45
|
+
for child in node.children:
|
|
46
|
+
if child.type == "promise_guard":
|
|
47
|
+
return _State(
|
|
48
|
+
block_type=self.block_type,
|
|
49
|
+
promise_type=_text(child)[:-1], # strip trailing ':'
|
|
50
|
+
)
|
|
51
|
+
return _State(block_type=self.block_type)
|
|
52
|
+
if node.type == "attribute":
|
|
53
|
+
for child in node.children:
|
|
54
|
+
if child.type == "attribute_name":
|
|
55
|
+
return _State(
|
|
56
|
+
block_type=self.block_type,
|
|
57
|
+
promise_type=self.promise_type,
|
|
58
|
+
attribute_name=_text(child),
|
|
59
|
+
)
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
|
|
29
63
|
def lint_cfbs_json(filename) -> int:
|
|
30
64
|
assert os.path.isfile(filename)
|
|
31
65
|
assert filename.endswith("cfbs.json")
|
|
@@ -93,16 +127,9 @@ def _find_node_type(filename, lines, node, node_type):
|
|
|
93
127
|
return matches
|
|
94
128
|
|
|
95
129
|
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
_walk_generic(filename, lines, node, visitor)
|
|
100
|
-
return matches
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def _single_node_checks(filename, lines, node, user_definition, strict):
|
|
104
|
-
"""Things which can be checked by only looking at one node,
|
|
105
|
-
not needing to recurse into children."""
|
|
130
|
+
def _node_checks(filename, lines, node, user_definition, strict, state: _State):
|
|
131
|
+
"""Checks we run on each node in the syntax tree,
|
|
132
|
+
utilizes state for checks which require context."""
|
|
106
133
|
line = node.range.start_point[0] + 1
|
|
107
134
|
column = node.range.start_point[1] + 1
|
|
108
135
|
if node.type == "attribute_name" and _text(node) == "ifvarclass":
|
|
@@ -133,7 +160,6 @@ def _single_node_checks(filename, lines, node, user_definition, strict):
|
|
|
133
160
|
f"Error: Undefined promise type '{promise_type}' at {filename}:{line}:{column}"
|
|
134
161
|
)
|
|
135
162
|
return 1
|
|
136
|
-
|
|
137
163
|
if node.type == "bundle_block_name":
|
|
138
164
|
if _text(node) != _text(node).lower():
|
|
139
165
|
_highlight_range(node, lines)
|
|
@@ -156,6 +182,16 @@ def _single_node_checks(filename, lines, node, user_definition, strict):
|
|
|
156
182
|
)
|
|
157
183
|
return 1
|
|
158
184
|
if node.type == "calling_identifier":
|
|
185
|
+
if (
|
|
186
|
+
strict
|
|
187
|
+
and _text(node) in user_definition.get("all_bundle_names", set())
|
|
188
|
+
and state.promise_type in user_definition.get("custom_promise_types", set())
|
|
189
|
+
):
|
|
190
|
+
_highlight_range(node, lines)
|
|
191
|
+
print(
|
|
192
|
+
f"Error: Call to bundle '{_text(node)}' inside custom promise: '{state.promise_type}' at {filename}:{line}:{column}"
|
|
193
|
+
)
|
|
194
|
+
return 1
|
|
159
195
|
if strict and (
|
|
160
196
|
_text(node)
|
|
161
197
|
not in BUILTIN_FUNCTIONS.union(
|
|
@@ -171,6 +207,22 @@ def _single_node_checks(filename, lines, node, user_definition, strict):
|
|
|
171
207
|
return 0
|
|
172
208
|
|
|
173
209
|
|
|
210
|
+
def _stateful_walk(
|
|
211
|
+
filename, lines, node, user_definition, strict, state: _State | None = None
|
|
212
|
+
) -> int:
|
|
213
|
+
if state is None:
|
|
214
|
+
state = _State()
|
|
215
|
+
|
|
216
|
+
errors = _node_checks(filename, lines, node, user_definition, strict, state)
|
|
217
|
+
|
|
218
|
+
child_state = state.update(node)
|
|
219
|
+
for child in node.children:
|
|
220
|
+
errors += _stateful_walk(
|
|
221
|
+
filename, lines, child, user_definition, strict, child_state
|
|
222
|
+
)
|
|
223
|
+
return errors
|
|
224
|
+
|
|
225
|
+
|
|
174
226
|
def _walk(filename, lines, node, user_definition=None, strict=True) -> int:
|
|
175
227
|
if user_definition is None:
|
|
176
228
|
user_definition = {}
|
|
@@ -187,11 +239,7 @@ def _walk(filename, lines, node, user_definition=None, strict=True) -> int:
|
|
|
187
239
|
line = node.range.start_point[0] + 1
|
|
188
240
|
column = node.range.start_point[1] + 1
|
|
189
241
|
|
|
190
|
-
|
|
191
|
-
for node in _find_nodes(filename, lines, node):
|
|
192
|
-
errors += _single_node_checks(filename, lines, node, user_definition, strict)
|
|
193
|
-
|
|
194
|
-
return errors
|
|
242
|
+
return _stateful_walk(filename, lines, node, user_definition, strict)
|
|
195
243
|
|
|
196
244
|
|
|
197
245
|
def _parse_user_definition(filename, lines, root_node):
|
|
@@ -348,4 +396,4 @@ def lint_single_arg(arg, strict=True):
|
|
|
348
396
|
return lint_folder(arg, strict)
|
|
349
397
|
assert os.path.isfile(arg)
|
|
350
398
|
|
|
351
|
-
return lint_single_file(arg, strict)
|
|
399
|
+
return lint_single_file(arg, strict=strict)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/check_download_matches_git.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_release_information.py
RENAMED
|
File without changes
|
|
File without changes
|
{cfengine-0.12.0 → cfengine-0.12.2}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|