Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/cfengine_cli/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,15 @@ def _lint_node(node: Node, policy_file: PolicyFile, state: State) -> int:
f"Error: Bundle type must be one of ({', '.join(ALLOWED_BUNDLE_TYPES)}), not '{_text(node)}' {location}"
)
return 1
if state.strict and (
node.type in ("bundle_block_name", "body_block_name")
and _text(node) in BUILTIN_FUNCTIONS
):
_highlight_range(node, lines)
print(
f"Error: {"Bundle" if "bundle" in node.type else "Body"} '{_text(node)}' conflicts with built-in function with the same name {location}"
)
return 1
if node.type == "calling_identifier":
name = _text(node)
qualified_name = _qualify(name, state.namespace)
Expand All @@ -515,6 +524,26 @@ def _lint_node(node: Node, policy_file: PolicyFile, state: State) -> int:
f"Error: Call to unknown function / bundle / body '{name}' {location}"
)
return 1
if (
name not in BUILTIN_FUNCTIONS
and state.promise_type == "vars"
and state.attribute_name not in ("action", "classes")
):
Comment on lines +527 to +531
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonThalvorsen Small nitpick: I think it makes a bit more sense to start "top-level" and go further specific in the condition. I would do:

Suggested change
if (
name not in BUILTIN_FUNCTIONS
and state.promise_type == "vars"
and state.attribute_name not in ("action", "classes")
):
if (
state.promise_type == "vars"
and state.attribute_name not in ("action", "classes")
and name not in BUILTIN_FUNCTIONS
):

It could even make sense to add state.block_keyword == "bundle" at the start for readability.

Also, if name not in BUILTIN_FUNCTIONS might be a slow operation, makes sense to save some time by doing the fast checks first.

_highlight_range(node, lines)
print(
f"Error: Call to unknown function '{name}' inside 'vars'-promise {location}"
)
return 1
if (
state.promise_type == "vars"
and state.attribute_name in ("action", "classes")
and qualified_name not in state.bodies
):
_highlight_range(node, lines)
print(
f"Error: '{name}' is not a defined body. Only bodies may be called with '{state.attribute_name}' {location}"
)
return 1
return 0


Expand Down
5 changes: 5 additions & 0 deletions tests/lint/009_bundle_shadows_function.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bundle agent isvariab
{
reports:
"isvariab is not a built-in function";
}
6 changes: 6 additions & 0 deletions tests/lint/009_bundle_shadows_function.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

bundle agent isvariable
^--------^
Error: Bundle 'isvariable' conflicts with built-in function with the same name at tests/lint/009_bundle_shadows_function.x.cf:1:14
FAIL: tests/lint/009_bundle_shadows_function.x.cf (1 error)
Failure, 1 error in total.
5 changes: 5 additions & 0 deletions tests/lint/009_bundle_shadows_function.x.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bundle agent isvariable
{
reports:
"isvariable is a built-in function";
}
22 changes: 22 additions & 0 deletions tests/lint/010_unknown_function_inside_vars.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
body classes bundle_class(a)
{
scope => "bundle";
promise_kept => { "$(a):bundle_context" };
}

bundle agent target(a)
{
reports:
"Hello, $(a)";
}

bundle agent helper
{
vars:
"x" string => isvariable("arg");
"y"
classes => bundle_class("arg"),
string => "";
methods:
"x" usebundle => target("arg");
}
12 changes: 12 additions & 0 deletions tests/lint/010_unknown_function_inside_vars.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

vars:
"x" string => target("arg");
^----^
Error: Call to unknown function 'target' inside 'vars'-promise at tests/lint/010_unknown_function_inside_vars.x.cf:16:19

"y"
classes => isvariable("arg"),
^--------^
Error: 'isvariable' is not a defined body. Only bodies may be called with 'classes' at tests/lint/010_unknown_function_inside_vars.x.cf:18:18
FAIL: tests/lint/010_unknown_function_inside_vars.x.cf (2 errors)
Failure, 2 errors in total.
22 changes: 22 additions & 0 deletions tests/lint/010_unknown_function_inside_vars.x.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
body classes bundle_class(a)
{
scope => "bundle";
promise_kept => { "$(a):bundle_context" };
}

bundle agent target(a)
{
reports:
"Hello, $(a)";
}

bundle agent helper
{
vars:
"x" string => target("arg");
"y"
classes => isvariable("arg"),
string => "";
methods:
"x" usebundle => target("arg");
}
Loading