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(general): Allow skipping multiple checks in a single line #6622

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2ce5cef
added the possibility to allow multiple skips in a single line
shoshiGit Jul 30, 2024
cda4f42
Merge branch 'main' into multiple_skips
shoshiGit Jul 30, 2024
aebaea6
Update base_parser.py
esterKoren Jul 30, 2024
cfdcc5f
add enum
shoshiGit Jul 30, 2024
43297bf
Merge remote-tracking branch 'origin/multiple_skips' into multiple_skips
shoshiGit Jul 30, 2024
a55fb47
Update enum.py
esterKoren Jul 30, 2024
71e3c71
changed folder name
shoshiGit Jul 31, 2024
2ed8228
Merge remote-tracking branch 'origin/multiple_skips' into multiple_skips
shoshiGit Jul 31, 2024
ea9da32
added the possibility to allow multiple skips in a single line
shoshiGit Jul 31, 2024
5e9c9e5
Merge branch 'main' into multiple_skips
shoshiGit Jul 31, 2024
e1fe308
added the possibility to allow multiple skips in a single line
shoshiGit Aug 1, 2024
898f628
Merge remote-tracking branch 'origin/multiple_skips' into multiple_skips
shoshiGit Aug 1, 2024
2d30cb8
Merge branch 'main' into multiple_skips
shoshiGit Aug 1, 2024
2ec21b9
Merge remote-tracking branch 'origin/multiple_skips' into multiple_skips
shoshiGit Aug 1, 2024
6bed1fa
fixed the possibility to allow multiple skips in a single line
shoshiGit Aug 1, 2024
ba4d28c
fixed the possibility to allow multiple skips in a single line
shoshiGit Aug 5, 2024
cc4b0bb
Merge branch 'main' into multiple_skips
shoshiGit Aug 5, 2024
614a82c
updated the possibility to allow multiple skips in a single line
shoshiGit Aug 8, 2024
6fe5c1f
Merge remote-tracking branch 'origin/multiple_skips' into multiple_skips
shoshiGit Aug 8, 2024
ea8df14
updated strtobool
shoshiGit Aug 8, 2024
a34645f
updated strtobool 2
shoshiGit Aug 8, 2024
1f28ea3
Merge branch 'main' into multiple_skips
esterKoren Aug 9, 2024
d91dfd5
Merge branch 'main' into multiple_skips
shoshiGit Aug 31, 2024
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
11 changes: 11 additions & 0 deletions checkov/common/comment/enum.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import re
from typing import Pattern

# Default regex pattern
COMMENT_REGEX = re.compile(r'(checkov:skip=|bridgecrew:skip=) *([A-Za-z_\d]+)(:[^\n]+)?')
# Custom regex pattern if needed
MULTIPLE_CHECKS_SKIP_REGEX = re.compile(r'(checkov:skip=|bridgecrew:skip=) *([A-Za-z_\d]+(?:,[A-Za-z_\d]+)*)*(:[^\n]+)?')


def get_comment_regex(allow_multiple_skips: bool) -> Pattern[str]:
"""
Returns the appropriate regex pattern based on the environment variable.
"""
return MULTIPLE_CHECKS_SKIP_REGEX if allow_multiple_skips else COMMENT_REGEX
39 changes: 28 additions & 11 deletions checkov/terraform/context_parsers/base_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import logging
import os
import re
from abc import ABC, abstractmethod
from collections import defaultdict
Expand All @@ -10,10 +11,12 @@

import dpath

from checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import integration as metadata_integration
from checkov.common.comment.enum import COMMENT_REGEX
from checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import \
integration as metadata_integration
from checkov.common.comment.enum import get_comment_regex
from checkov.common.models.enums import ContextCategories
from checkov.common.resource_code_logger_filter import add_resource_code_filter_to_logger
from checkov.common.runners.base_runner import strtobool
from checkov.terraform import TFDefinitionKey, get_abs_path
from checkov.terraform.context_parsers.registry import parser_registry

Expand Down Expand Up @@ -91,8 +94,10 @@ def _collect_skip_comments(self, definition_blocks: List[Dict[str, Any]]) -> Dic
"""
Collects checkov skip comments to all definition blocks
:param definition_blocks: parsed definition blocks
:return: context enriched with with skipped checks per skipped entity
:return: context enriched with skipped checks per skipped entity
"""
should_allow_multi_checks_skip = bool(strtobool(os.getenv('CHECKOV_ALLOW_SKIP_MULTIPLE_ONE_LINE', 'False')))
comment_regex = get_comment_regex(should_allow_multi_checks_skip)
bc_id_mapping = metadata_integration.bc_to_ckv_id_mapping
comments = [
(
Expand All @@ -104,7 +109,7 @@ def _collect_skip_comments(self, definition_blocks: List[Dict[str, Any]]) -> Dic
)
for (line_num, x) in self.file_lines
if self.is_optional_comment_line(x)
for match in [re.search(COMMENT_REGEX, x)]
for match in [re.search(comment_regex, x)]
if match
]
for entity_block in definition_blocks:
Expand All @@ -124,13 +129,25 @@ def _collect_skip_comments(self, definition_blocks: List[Dict[str, Any]]) -> Dic
for (skip_check_line_num, skip_check) in comments:
if "start_line" in entity_context and "end_line" in entity_context \
and entity_context["start_line"] < skip_check_line_num < entity_context["end_line"]:
# No matter which ID was used to skip, save the pair of IDs in the appropriate fields
if bc_id_mapping and skip_check["id"] in bc_id_mapping:
skip_check["bc_id"] = skip_check["id"]
skip_check["id"] = bc_id_mapping[skip_check["id"]]
elif metadata_integration.check_metadata:
skip_check["bc_id"] = metadata_integration.get_bc_id(skip_check["id"])
skipped_checks.append(skip_check)
if should_allow_multi_checks_skip:
skip_check_ids = skip_check["id"].split(',')
for skip_check_id in skip_check_ids:
single_skip_check = {"id": skip_check_id.strip(),
"suppress_comment": skip_check["suppress_comment"]}
if bc_id_mapping and single_skip_check["id"] in bc_id_mapping:
single_skip_check["bc_id"] = single_skip_check["id"]
single_skip_check["id"] = bc_id_mapping[single_skip_check["id"]]
elif metadata_integration.check_metadata:
single_skip_check["bc_id"] = metadata_integration.get_bc_id(skip_check["id"])
skipped_checks.append(single_skip_check)
else:
if bc_id_mapping and skip_check["id"] in bc_id_mapping:
skip_check["bc_id"] = skip_check["id"]
skip_check["id"] = bc_id_mapping[skip_check["id"]]
elif metadata_integration.check_metadata:
skip_check["bc_id"] = metadata_integration.get_bc_id(skip_check["id"])
skipped_checks.append(skip_check)

dpath.new(self.context, entity_context_path + ["skipped_checks"], skipped_checks)
return self.context

Expand Down
36 changes: 36 additions & 0 deletions tests/terraform/checks/a_example_skip/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

resource "azurerm_storage_account" "default" {
#checkov:skip=CKV_AZURE_33
name = "storageaccountname"
resource_group_name = "azurerm_resource_group.example.name"
location = "azurerm_resource_group.example.location"
account_tier = "Standard"
account_replication_type = "GRS"
}

resource "azurerm_storage_account" "skip_more_than_one" {
#checkov:skip=CKV_AZURE_33,CKV_AZURE_59: Skipped by user
name = "storageaccountname"
resource_group_name = "azurerm_resource_group.example.name"
location = "azurerm_resource_group.example.location"
account_tier = "Standard"
account_replication_type = "GRS"
}

resource "azurerm_storage_account" "skip_invalid" {
#checkov:skip=CKV_AZURE_33,bla bla bla: Skipped by user
name = "storageaccountname"
resource_group_name = "azurerm_resource_group.example.name"
location = "azurerm_resource_group.example.location"
account_tier = "Standard"
account_replication_type = "GRS"
}

resource "azurerm_storage_account" "skip_all_checks" {
#checkov:skip=CKV_AZURE_33,CKV_AZURE_59,CKV_AZURE_999,CKV_AZURE_190: Skipping multiple checks
name = "storageaccountname"
resource_group_name = "azurerm_resource_group.example.name"
location = "azurerm_resource_group.example.location"
account_tier = "Standard"
account_replication_type = "GRS"
}
44 changes: 44 additions & 0 deletions tests/terraform/checks/test_multiple_skips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import os
import unittest
from pathlib import Path
from unittest.mock import patch

from checkov.runner_filter import RunnerFilter
from checkov.terraform.runner import Runner


class TestMultipleSkips(unittest.TestCase):
@patch.dict(os.environ, {'CHECKOV_ALLOW_SKIP_MULTIPLE_ONE_LINE': 'True'})
def test(self) -> None:
# given
test_files_dir = Path(__file__).parent / "a_example_skip"

# when
report = Runner().run(root_folder=str(test_files_dir), runner_filter=RunnerFilter(checks=[]))

# then
summary = report.get_summary()
Copy link
Contributor

Choose a reason for hiding this comment

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

Please assert the skipped part in the reports by resource -
We want to be sure default and skip_invalid are with one skip, and skip_more_than_one is with 2 skips.


skipped_resources = {
"azurerm_storage_account.default": 1,
"azurerm_storage_account.skip_invalid": 1,
"azurerm_storage_account.skip_more_than_one": 2,
"azurerm_storage_account.skip_all_checks": 3,
}

for skipped_check in report.skipped_checks:
resource = skipped_check.resource # Access resource attribute directly
if resource in skipped_resources:
skipped_resources[resource] -= 1

for resource, count in skipped_resources.items():
self.assertEqual(count, 0, f"{resource} did not skip the expected number of checks")

self.assertEqual(summary["passed"], 16)
self.assertEqual(summary["failed"], 33)
self.assertEqual(summary["skipped"], 7)
self.assertEqual(summary["parsing_errors"], 0)


if __name__ == "__main__":
unittest.main()
Loading