Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(kustomize): Add origin annotations to calculate bases of kustomize checks #5298

Merged
merged 29 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8b7a65c
Added basic implementation of adding and removing buildmetadata origi…
bo156 Jul 2, 2023
3b1b263
Only remove the new buildmetadata if it wasn't added successfully by …
bo156 Jul 2, 2023
2955869
middle of debugging
bo156 Jul 3, 2023
145b7a0
more improvements
bo156 Jul 3, 2023
05c6372
Successfully updated the file path
bo156 Jul 3, 2023
a4b7938
middle of adding correct base code lines
bo156 Jul 4, 2023
b740fb4
Fixed calculation of caller file path
bo156 Jul 5, 2023
f0d7c0d
another debug way
bo156 Jul 5, 2023
8563e37
Another addition
bo156 Jul 5, 2023
169b640
Fixed bug where we calculate the base for overlay incorrectly, causin…
bo156 Jul 5, 2023
3907850
Calculated relative directory to new base
bo156 Jul 5, 2023
96af719
Allowed empty caller file lines and fixed all kustomize tests
bo156 Jul 5, 2023
2ac9ebc
Added tests for caller file paths
bo156 Jul 6, 2023
18e2ce8
Added support for caller file path in graph reports and updated tests…
bo156 Jul 6, 2023
485d13f
Fixed parsing of kustomization files with resources which actually re…
bo156 Jul 6, 2023
0199111
Added env variable to allow kustomize file edits
bo156 Jul 6, 2023
054914e
Removed comment
bo156 Jul 6, 2023
fc51eda
Updated _get_caller_file_path signature
bo156 Jul 6, 2023
c572d37
Linters
bo156 Jul 6, 2023
e4edeca
nosec on subprocess.Popen as we are incharge of the command
bo156 Jul 6, 2023
d43adfa
Added condition that annotations are not None
bo156 Jul 6, 2023
2e75759
CR
bo156 Jul 9, 2023
9f5309a
find correct parent without loop
bo156 Jul 9, 2023
0adcd68
don't check len
bo156 Jul 9, 2023
ad8a44e
Used subprocess.run
bo156 Jul 9, 2023
a54d27e
moved env var to another place in the instance
bo156 Jul 9, 2023
abaac96
Fixed all tests:
bo156 Jul 9, 2023
e4bf7f7
Check for origin_relative_path before concat
bo156 Jul 10, 2023
e5c71a5
Added documentation
bo156 Jul 10, 2023
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
1 change: 1 addition & 0 deletions checkov/common/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,4 @@ class _EntityContext(TypedDict, total=False):
policy: str
code_lines: list[tuple[int, str]]
skipped_checks: list[_SkippedCheck]
origin_relative_path: str
67 changes: 42 additions & 25 deletions checkov/kubernetes/kubernetes_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,34 +138,25 @@ def build_definitions_context(
resource_id = get_resource_id(resource)
if not resource_id:
continue
start_line = resource[START_LINE]
end_line = min(resource[END_LINE], len(definitions_raw[file_path]))
first_line_index = 0
# skip empty lines
while not str.strip(definitions_raw[file_path][first_line_index][1]):
first_line_index += 1
# check if the file is a json file
if str.strip(definitions_raw[file_path][first_line_index][1])[0] == "{":
start_line += 1
end_line += 1
else:
# add resource comments to definition lines
current_line = str.strip(definitions_raw[file_path][start_line - 1][1])
while not current_line or current_line[0] == YAML_COMMENT_MARK:
start_line -= 1
current_line = str.strip(definitions_raw[file_path][start_line - 1][1])

# remove next resource comments from definition lines
current_line = str.strip(definitions_raw[file_path][end_line - 1][1])
while not current_line or current_line[0] == YAML_COMMENT_MARK:
end_line -= 1
current_line = str.strip(definitions_raw[file_path][end_line - 1][1])

code_lines = definitions_raw[file_path][start_line - 1: end_line]

relative_resource_path = None
if 'metadata' in resource:
metadata = resource['metadata']
if 'annotations' in metadata and metadata['annotations'] is not None\
and 'config.kubernetes.io/origin' in metadata['annotations']:
metadata_path = metadata['annotations']['config.kubernetes.io/origin']
if 'path:' in metadata_path:
relative_resource_path = metadata_path.split('path:')[1].strip()

resource_start_line = resource[START_LINE]
resource_end_line = min(resource[END_LINE], len(definitions_raw[file_path]))
raw_code = definitions_raw[file_path]
code_lines, start_line, end_line = calculate_code_lines(raw_code, resource_start_line, resource_end_line)
dpath.new(
definitions_context,
[file_path, resource_id],
{"start_line": start_line, "end_line": end_line, "code_lines": code_lines},
{"start_line": start_line, "end_line": end_line, "code_lines": code_lines,
"origin_relative_path": relative_resource_path},
)

skipped_checks = get_skipped_checks(resource)
Expand All @@ -177,6 +168,32 @@ def build_definitions_context(
return definitions_context


def calculate_code_lines(raw_code: list[tuple[int, str]], start_line: int, end_line: int) \
-> tuple[list[tuple[int, str]], int, int]:
first_line_index = 0
# skip empty lines
while not str.strip(raw_code[first_line_index][1]):
first_line_index += 1
# check if the file is a json file
if str.strip(raw_code[first_line_index][1])[0] == "{":
start_line += 1
end_line += 1
else:
# add resource comments to definition lines
current_line = str.strip(raw_code[start_line - 1][1])
while not current_line or current_line[0] == YAML_COMMENT_MARK:
start_line -= 1
current_line = str.strip(raw_code[start_line - 1][1])

# remove next resource comments from definition lines
current_line = str.strip(raw_code[end_line - 1][1])
while not current_line or current_line[0] == YAML_COMMENT_MARK:
end_line -= 1
current_line = str.strip(raw_code[end_line - 1][1])
code_lines = raw_code[start_line - 1: end_line]
return code_lines, start_line, end_line


def is_invalid_k8_definition(definition: Dict[str, Any]) -> bool:
return (
not isinstance(definition, dict)
Expand Down
4 changes: 3 additions & 1 deletion checkov/kubernetes/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ def check_definitions(
# TODO? - Variable Eval Message!
variable_evaluations: "dict[str, Any]" = {}

report = self.mutate_kubernetes_results(results, report, k8_file, k8_file_path, file_abs_path, entity_conf, variable_evaluations)
report = self.mutate_kubernetes_results(results, report, k8_file, k8_file_path, file_abs_path,
entity_conf, variable_evaluations, root_folder)
self.pbar.update()
self.pbar.close()
return report
Expand All @@ -194,6 +195,7 @@ def mutate_kubernetes_results(
file_abs_path: str,
entity_conf: dict[str, Any],
variable_evaluations: dict[str, Any],
root_folder: str | None = None
) -> Report:
# Moves report generation logic out of run() method in Runner class.
# Allows function overriding of a much smaller function than run() for other "child" frameworks such as Kustomize, Helm
Expand Down
Loading