Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
MS99-9 authored Dec 18, 2024
2 parents ae5551d + e9dfff0 commit b68e129
Show file tree
Hide file tree
Showing 52 changed files with 4,526 additions and 3,818 deletions.
30 changes: 29 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
# CHANGELOG

## [Unreleased](https://github.com/bridgecrewio/checkov/compare/3.2.332...HEAD)
## [Unreleased](https://github.com/bridgecrewio/checkov/compare/3.2.339...HEAD)

## [3.2.339](https://github.com/bridgecrewio/checkov/compare/3.2.336...3.2.339) - 2024-12-17

### Bug Fix

- **general:** Fix jsonpath-key handling for special characters like "/" and reduce log size - [#6907](https://github.com/bridgecrewio/checkov/pull/6907)
- **serverless:** Fix serverless check crash - [#6909](https://github.com/bridgecrewio/checkov/pull/6909)

## [3.2.336](https://github.com/bridgecrewio/checkov/compare/3.2.334...3.2.336) - 2024-12-16

### Feature

- **general:** add cortex:skip for suppressions - [#6908](https://github.com/bridgecrewio/checkov/pull/6908)

### Bug Fix

- **terraform:** fix CKV_AZURE_136 for replicas - [#6895](https://github.com/bridgecrewio/checkov/pull/6895)
- **terraform:** Fix CKV_AZURE_227 for Azure V4 - [#6906](https://github.com/bridgecrewio/checkov/pull/6906)

## [3.2.334](https://github.com/bridgecrewio/checkov/compare/3.2.332...3.2.334) - 2024-12-08

### Feature

- **serverless:** Serverless graph vertices - [#6894](https://github.com/bridgecrewio/checkov/pull/6894)

### Bug Fix

- **secrets:** fix indentation to remove duplications - [#6626](https://github.com/bridgecrewio/checkov/pull/6626)

## [3.2.332](https://github.com/bridgecrewio/checkov/compare/3.2.328...3.2.332) - 2024-12-05

Expand Down
2 changes: 1 addition & 1 deletion checkov/arm/checks/resource/FunctionAppMinTLSVersion.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def get_expected_value(self) -> Any:
return 1.2

def get_expected_values(self) -> List[Any]:
return ["1.2", 1.2]
return ["1.2", 1.2, "1.3", 1.3]


check = FunctionAppMinTLSVersion()
15 changes: 10 additions & 5 deletions checkov/arm/checks/resource/MySQLPublicAccessDisabled.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List

from checkov.common.models.enums import CheckCategories
from checkov.arm.base_resource_value_check import BaseResourceValueCheck

Expand All @@ -6,18 +8,21 @@ class MySQLPublicAccessDisabled(BaseResourceValueCheck):
def __init__(self) -> None:
name = "Ensure 'public network access enabled' is set to 'False' for mySQL servers"
id = "CKV_AZURE_53"
supported_resources = ("Microsoft.DBforMySQL/servers",)
supported_resources = ("Microsoft.DBforMySQL/servers", "Microsoft.DBforMySQL/flexibleServers",)
categories = (CheckCategories.NETWORKING,)
super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources)

def get_inspected_key(self) -> str:
return "properties/publicNetworkAccess"
if self.entity_type == "Microsoft.DBforMySQL/servers":
return "properties/publicNetworkAccess"
else:
return "properties/network/publicNetworkAccess"

def get_expected_value(self) -> str:
"""
Returns the default expected value, governed by provider best practices
"""
return "disabled"

def get_expected_values(self) -> List[str]:
return ["disabled", "Disabled"]


check = MySQLPublicAccessDisabled()
12 changes: 0 additions & 12 deletions checkov/cloudformation/graph_builder/graph_components/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,3 @@ def _should_add_previous_breadcrumbs(change_origin_id: Optional[int],
@staticmethod
def _should_set_changed_attributes(change_origin_id: Optional[int], attribute_at_dest: Optional[str]) -> bool:
return change_origin_id is not None and attribute_at_dest is not None

def _handle_unique_key_characters(self, key: str) -> str:
# `::` is not a valid jsonpath character, but cloudformation have multiple functions like `Fn::If` which use it,
# so we solve it with escaping using parenthesis
key_parts = key.split(".")
updated_key = ""
for part in key_parts:
if part.startswith("Fn::"):
updated_key += f'"{part}"'
else:
updated_key += part
return updated_key
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,9 @@ def _handle_sub_with_pseudo_param(attr_key: str, attr_value: Any, vertex: Cloudf
try:
inner_value = json.loads(inner_value)
except Exception as e:
logging.warning(f"[Cloudformation_evaluate_non_rendered_values]- "
f"Inner_value - {inner_value} is not a valid json. "
f"Full exception - {str(e)}")
logging.debug(f"[Cloudformation_evaluate_non_rendered_values]- "
f"Inner_value - {inner_value} is not a valid json. "
f"Full exception - {str(e)}")
if is_pseudo_param_in_value:
vertex.update_attribute(
attribute_key=attr_key, attribute_value=inner_value, change_origin_id=None,
Expand Down
2 changes: 1 addition & 1 deletion checkov/common/comment/enum.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import re

COMMENT_REGEX = re.compile(r'(checkov:skip=|bridgecrew:skip=) *([A-Za-z_\d]+(?:,[A-Za-z_\d]+)*)?(:[^\n]*)?')
COMMENT_REGEX = re.compile(r'(checkov:skip=|bridgecrew:skip=|cortex:skip=) *([A-Za-z_\d]+(?:,[A-Za-z_\d]+)*)?(:[^\n]*)?')
22 changes: 12 additions & 10 deletions checkov/common/graph/graph_builder/graph_components/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ def update_attribute(
try:
self._update_attribute_based_on_jsonpath_key(attribute_value, key)
except Exception as e:
logging.debug(f"Failed updating attribute for key: {key} and value {attribute_value} for"
f"vertex attributes {self.attributes}. Falling back to explicitly setting it."
logging.debug(f"Failed updating attribute for key: {key} and value {attribute_value}."
f"Falling back to explicitly setting it."
f"Exception - {e}")
self.attributes[key] = attribute_value
else:
Expand Down Expand Up @@ -204,21 +204,23 @@ def _update_attribute_based_on_jsonpath_key(self, attribute_value: Any, key: str
match[0].value = attribute_value
return None

def _get_jsonpath_key(self, key: str) -> str:
key = self._handle_unique_key_characters(key)
# Replace .0 with [0] to match jsonpath style
@staticmethod
def _get_jsonpath_key(key: str) -> str:
jsonpath_key = "$."
key_parts = key.split(".")
updated_parts = []
for part in key_parts:
if part.isnumeric():
jsonpath_key += f"[{part}]"
updated_parts.append(f"[{part}]")
elif "/" in part or "::" in part:
updated_parts.append(f'"{part}"')
else:
jsonpath_key += part
updated_parts.append(part)
jsonpath_key += ".".join(updated_parts)
# Replace .0 with [0] to match jsonpath style
jsonpath_key = jsonpath_key.replace(".[", "[")
return jsonpath_key

def _handle_unique_key_characters(self, key: str) -> str:
return key

def update_inner_attribute(
self, attribute_key: str, nested_attributes: list[Any] | dict[str, Any], value_to_update: Any
) -> None:
Expand Down
14 changes: 14 additions & 0 deletions checkov/serverless/graph_builder/definition_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import annotations

from typing import Any


def build_definitions_context(definitions: dict[str, dict[str, Any]], definitions_raw: dict[str, list[tuple[int, str]]]
) -> dict[str, dict[str, Any]]:
return {}


def add_resource_to_definitions_context(definitions_context: dict[str, dict[str, Any]], resource_key: str,
resource_attributes: dict[str, Any], definition_attribute: str,
definitions_raw: dict[str, Any], file_path: str) -> None:
pass
12 changes: 0 additions & 12 deletions checkov/serverless/graph_builder/graph_components/block_types.py

This file was deleted.

55 changes: 55 additions & 0 deletions checkov/serverless/graph_builder/graph_to_definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from __future__ import annotations

import os
from pathlib import Path
from typing import Any, TYPE_CHECKING

from checkov.serverless.utils import ServerlessElements

if TYPE_CHECKING:
from checkov.serverless.graph_builder.graph_components.blocks import ServerlessBlock


def convert_graph_vertices_to_definitions(vertices: list[ServerlessBlock], root_folder: str | Path | None) \
-> tuple[dict[str, dict[str, Any]], dict[str, dict[str, Any]]]:
serverless_definitions: dict[str, dict[str, Any]] = {}
breadcrumbs: dict[str, dict[str, Any]] = {}
for vertex in vertices:
block_path = vertex.path
element_name = vertex.name.split('.')[-1]
# Plugins section is formatted as a list
if vertex.block_type == ServerlessElements.PLUGINS:
serverless_definitions.setdefault(block_path, {}).setdefault(vertex.block_type, []).append(element_name)

# If there is a ket named 'value' in the config it means that
# this vertex's config contains only a single string
elif 'value' in vertex.config:
# If the vertex is provider or service and it only contains a string the section should look like:
# provider: <value>
# service: <value>
if element_name == ServerlessElements.PROVIDER or element_name == ServerlessElements.SERVICE:
serverless_definitions.setdefault(block_path, {})[vertex.block_type] = vertex.config['value']

# Otherwise it's a vertex of a specific nested attribute and need to include the full path
# Examples:
# provider:
# runtime: nodejs20.x
# custom:
# myCustomVar: value
else:
serverless_definitions.setdefault(block_path, {}).setdefault(vertex.block_type, {})[element_name] = \
vertex.config['value']

# Otherwise, the vertex config is a dict
else:
serverless_definitions.setdefault(block_path, {}).setdefault(vertex.block_type, {})[
element_name] = vertex.config

if vertex.breadcrumbs:
relative_block_path = f"/{os.path.relpath(block_path, root_folder)}"
add_breadcrumbs(vertex, breadcrumbs, relative_block_path)
return serverless_definitions, breadcrumbs


def add_breadcrumbs(vertex: ServerlessBlock, breadcrumbs: dict[str, dict[str, Any]], relative_block_path: str) -> None:
breadcrumbs.setdefault(relative_block_path, {})[vertex.name] = vertex.breadcrumbs
89 changes: 84 additions & 5 deletions checkov/serverless/graph_builder/local_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,99 @@

from typing import Any

from checkov.common.graph.graph_builder import CustomAttributes
from checkov.common.graph.graph_builder.local_graph import LocalGraph, _Block
from checkov.common.util.consts import LINE_FIELD_NAMES
from checkov.common.util.data_structures_utils import pickle_deepcopy
from checkov.serverless.graph_builder.graph_components.blocks import ServerlessBlock
from checkov.serverless.utils import ServerlessElements


class ServerlessLocalGraph(LocalGraph[ServerlessBlock]):
def __init__(self, definitions: dict[str, dict[str, Any]]) -> None:
super().__init__()
self.vertices: list[ServerlessBlock] = []
self.definitions = definitions
self.vertices_by_path_and_id: dict[tuple[str, str], int] = {}
self.vertices_by_name: dict[str, int] = {}
self.vertices_by_path_and_name: dict[tuple[str, str], int] = {}

def build_graph(self, render_variables: bool = True) -> None:
self._create_vertices()

def _create_vertices(self) -> None:
for file_path, definition in self.definitions.items():
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.FUNCTIONS)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.PARAMS)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.PROVIDER)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.LAYERS)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.CUSTOM)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.PACKAGE)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.PLUGINS)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.SERVICE)
self._create_vertex(file_path=file_path, definition=definition, element_type=ServerlessElements.RESOURCES)

for i, vertex in enumerate(self.vertices):
self.vertices_by_block_type[vertex.block_type].append(i)
self.vertices_by_path_and_name[(vertex.path, vertex.name)] = i

self.in_edges[i] = []
self.out_edges[i] = []

def _create_vertex(self, file_path: str, definition: dict[str, Any] | None,
element_type: ServerlessElements) -> None:
if not definition:
return
resources = definition.get(element_type)
if not resources:
return

elif isinstance(resources, str):
self.vertices.append(ServerlessBlock(
name=f'{element_type}',
config={"value": pickle_deepcopy(resources)},
path=file_path,
block_type=element_type,
attributes={"value": pickle_deepcopy(resources)},
id=f"{file_path}:{element_type}"
))

else:
for attribute in resources:
if isinstance(attribute, str) and attribute in LINE_FIELD_NAMES:
continue

if isinstance(resources, list):
full_conf = {"value": pickle_deepcopy(attribute)}
self.vertices.append(ServerlessBlock(
name=f'{element_type}.{attribute}',
config=full_conf,
path=file_path,
block_type=element_type,
attributes=full_conf,
id=f"{file_path}:{element_type}.{attribute}"
))

else:
attribute_value = resources[attribute]
if not isinstance(attribute_value, dict):
full_conf = {"value": pickle_deepcopy(attribute_value)}
else:
full_conf = attribute_value

config = pickle_deepcopy(full_conf)

resource_type = element_type

attributes = pickle_deepcopy(config)
attributes[CustomAttributes.RESOURCE_TYPE] = resource_type

self.vertices.append(ServerlessBlock(
name=f'{resource_type}.{attribute}',
config=config,
path=file_path,
block_type=resource_type,
attributes=attributes,
id=f"{file_path}:{resource_type}.{attribute}"
))

def get_resources_types_in_graph(self) -> list[str]:
# not used
Expand All @@ -25,6 +107,3 @@ def update_vertex_config(vertex: _Block, changed_attributes: list[str] | dict[st

def update_vertices_configs(self) -> None:
pass

def build_graph(self, render_variables: bool) -> None:
pass
Loading

0 comments on commit b68e129

Please sign in to comment.