Skip to content
Open
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
32 changes: 19 additions & 13 deletions src/cfengine_cli/lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@
"string",
}
PROMISE_BLOCK_ATTRIBUTES = ("path", "interpreter")

IMPLIES_BUNDLE = {"usebundle", "servicebundle", "service_bundle"}
IMPLIES_BODY = {"copy_from", "action"}
# Generally, IMPLIES_BUNDLE and IMPLIES_BODY might not be necessary
# in the future, when we're using syntax-description.json we will
# know if we expect a bundle or body (based on both promise type and attribute name)
# so "guessing" based on only attribute name can be dropped.

KNOWN_FAULTY_FUNCTION_DEFS = {"regex_replace", "peers"}
# Generally, we don't want to allow creating bodies / bundles with the same
# name as a built in function, as it can make things more confusing
Expand Down Expand Up @@ -652,19 +659,18 @@ def _lint_node(
f"Error: Call to bundle '{name}' inside custom promise: '{state.promise_type}' {location}"
)
return 1
if state.strict and (
qualified_name not in state.bundles
and (
state.attribute_name in IMPLIES_BUNDLE
or qualified_name not in state.bodies
)
and name not in syntax_data.BUILTIN_FUNCTIONS
):
_highlight_range(node, lines)
print(
f"Error: Call to unknown function / bundle / body '{name}' {location}"
if state.strict and name not in syntax_data.BUILTIN_FUNCTIONS:
allowed_in_bundles = state.attribute_name not in IMPLIES_BODY
allowed_in_bodies = state.attribute_name not in IMPLIES_BUNDLE
found = (allowed_in_bundles and qualified_name in state.bundles) or (
allowed_in_bodies and qualified_name in state.bodies
)
return 1
if not found:
_highlight_range(node, lines)
print(
f"Error: Call to unknown function / bundle / body '{name}' {location}"
)
return 1
if (
name not in syntax_data.BUILTIN_FUNCTIONS
and state.promise_type == "vars"
Expand Down Expand Up @@ -757,7 +763,7 @@ def _lint_node(
return 1

qualified_name = _qualify(call, state.namespace)
if qualified_name in state.bundles:
if qualified_name in state.bundles and state.attribute_name not in IMPLIES_BODY:
definitions = state.bundles[qualified_name]
valid_counts = {len(d.get("parameters", [])) for d in definitions}
if len(args) not in valid_counts:
Expand Down
12 changes: 12 additions & 0 deletions tests/lint/018_implies_body.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
body copy_from mycopy(from, server)
{
source => "$(from)";
servers => { "$(server)" };
}

bundle agent main
{
files:
"/tmp/test"
copy_from => mycopy("/src", "host1");
}
17 changes: 17 additions & 0 deletions tests/lint/018_implies_body.expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

"/tmp/test1"
copy_from => helper("oops");
^----^
Error: Call to unknown function / bundle / body 'helper' at tests/lint/018_implies_body.x.cf:17:20

"/tmp/test2"
copy_from => unknown_name("oops");
^----------^
Error: Call to unknown function / bundle / body 'unknown_name' at tests/lint/018_implies_body.x.cf:19:20

"/tmp/test3"
copy_from => mycopy("/src");
^------------^
Error: Expected 2 arguments, received 1 for body 'mycopy' at tests/lint/018_implies_body.x.cf:21:20
FAIL: tests/lint/018_implies_body.x.cf (3 errors)
Failure, 3 errors in total.
22 changes: 22 additions & 0 deletions tests/lint/018_implies_body.x.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
body copy_from mycopy(from, server)
{
source => "$(from)";
servers => { "$(server)" };
}

bundle agent helper(arg)
{
reports:
"$(arg)";
}

bundle agent main
{
files:
"/tmp/test1"
copy_from => helper("oops");
"/tmp/test2"
copy_from => unknown_name("oops");
"/tmp/test3"
copy_from => mycopy("/src");
}
Loading