mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-25 12:54:18 +00:00
feat(checks): PHP runtime coverage after the October security release (#13127)
Co-authored-by: Rubén De la Torre Vico <98956809+puchy22@users.noreply.github.com>
This commit is contained in:
1 parent
35d25a7218
commit
669df91ac9
63 files changed
+1928
-732
No files matched your search
@@ -111,6 +111,19 @@ config_aws = {
|
||||
"max_idle_disconnect_timeout_in_seconds": 600,
|
||||
"max_disconnect_timeout_in_seconds": 300,
|
||||
"max_session_duration_seconds": 36000,
|
||||
"elasticbeanstalk_php_min_branch": "8.2",
|
||||
"elasticbeanstalk_php_min_platform_version": "4.13.13",
|
||||
"lightsail_php_blueprints": [
|
||||
"wordpress",
|
||||
"lamp",
|
||||
"nginx",
|
||||
"drupal",
|
||||
"joomla",
|
||||
"magento",
|
||||
"prestashop",
|
||||
"plesk",
|
||||
"cpanel",
|
||||
],
|
||||
"obsolete_lambda_runtimes": [
|
||||
"java8",
|
||||
"go1.x",
|
||||
|
||||
@@ -93,6 +93,28 @@ aws:
|
||||
# aws.appstream_fleet_maximum_session_duration
|
||||
max_session_duration_seconds: 36000 # 10 Hours
|
||||
|
||||
# AWS Elastic Beanstalk Configuration
|
||||
# aws.elasticbeanstalk_environment_php_platform_updated
|
||||
# Oldest PHP branch still receiving security fixes
|
||||
elasticbeanstalk_php_min_branch: "8.2"
|
||||
# Oldest Amazon Linux 2023 PHP platform version bundling the fixed PHP release
|
||||
elasticbeanstalk_php_min_platform_version: "4.13.13"
|
||||
|
||||
# AWS Lightsail Configuration
|
||||
# aws.lightsail_instance_php_blueprint_updated
|
||||
# Blueprint id prefixes that ship PHP and require manual runtime verification
|
||||
lightsail_php_blueprints:
|
||||
[
|
||||
"wordpress",
|
||||
"lamp",
|
||||
"nginx",
|
||||
"drupal",
|
||||
"joomla",
|
||||
"magento",
|
||||
"prestashop",
|
||||
"plesk",
|
||||
"cpanel",
|
||||
]
|
||||
# AWS Lambda Configuration
|
||||
# aws.awslambda_function_using_supported_runtimes
|
||||
obsolete_lambda_runtimes:
|
||||
@@ -415,6 +437,7 @@ azure:
|
||||
defender_attack_path_minimal_risk_level: "High"
|
||||
|
||||
# Azure App Service
|
||||
# Minimum runtime versions; any newer version passes
|
||||
# azure.app_ensure_php_version_is_latest
|
||||
php_latest_version: "8.2"
|
||||
# azure.app_ensure_python_version_is_latest
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_service import (
|
||||
Environment,
|
||||
)
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_EU_WEST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_php_platform_updated.elasticbeanstalk_environment_php_platform_updated"
|
||||
ENV_ARN = f"arn:aws:elasticbeanstalk:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:environment/test-app/test-env"
|
||||
|
||||
|
||||
def _environment(solution_stack_name="", platform_arn=""):
|
||||
return Environment(
|
||||
id="e-abc123",
|
||||
name="test-env",
|
||||
arn=ENV_ARN,
|
||||
region=AWS_REGION_EU_WEST_1,
|
||||
application_name="test-app",
|
||||
solution_stack_name=solution_stack_name,
|
||||
platform_arn=platform_arn,
|
||||
)
|
||||
|
||||
|
||||
def _run_check(environments, audit_config=None):
|
||||
elasticbeanstalk_client = mock.MagicMock()
|
||||
elasticbeanstalk_client.environments = environments
|
||||
elasticbeanstalk_client.audit_config = audit_config or {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider([AWS_REGION_EU_WEST_1]),
|
||||
),
|
||||
mock.patch(
|
||||
f"{CHECK_PATH}.elasticbeanstalk_client", new=elasticbeanstalk_client
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_php_platform_updated.elasticbeanstalk_environment_php_platform_updated import (
|
||||
elasticbeanstalk_environment_php_platform_updated,
|
||||
)
|
||||
|
||||
return elasticbeanstalk_environment_php_platform_updated().execute()
|
||||
|
||||
|
||||
class Test_elasticbeanstalk_environment_php_platform_updated:
|
||||
def test_no_environments(self):
|
||||
assert len(_run_check({})) == 0
|
||||
|
||||
def test_non_php_environment_is_skipped(self):
|
||||
environments = {
|
||||
ENV_ARN: _environment("64bit Amazon Linux 2023 v4.7.3 running Python 3.12")
|
||||
}
|
||||
assert len(_run_check(environments)) == 0
|
||||
|
||||
def test_environment_without_stack_is_skipped(self):
|
||||
assert len(_run_check({ENV_ARN: _environment()})) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"solution_stack_name,expected_status,expected_message",
|
||||
[
|
||||
(
|
||||
"64bit Amazon Linux 2023 v4.13.13 running PHP 8.4",
|
||||
"PASS",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.4 on platform version 4.13.13, which includes the fixed PHP release.",
|
||||
),
|
||||
(
|
||||
"64bit Amazon Linux 2023 v4.14.0 running PHP 8.2",
|
||||
"PASS",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.2 on platform version 4.14.0, which includes the fixed PHP release.",
|
||||
),
|
||||
(
|
||||
"64bit Amazon Linux 2023 v4.13.12 running PHP 8.5",
|
||||
"FAIL",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.5 on platform version 4.13.12, below the minimum fixed platform version 4.13.13.",
|
||||
),
|
||||
(
|
||||
"64bit Amazon Linux 2023 v4.9.2 running PHP 8.3",
|
||||
"FAIL",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.3 on platform version 4.9.2, below the minimum fixed platform version 4.13.13.",
|
||||
),
|
||||
(
|
||||
"64bit Amazon Linux 2023 v4.13.13 running PHP 8.1",
|
||||
"FAIL",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.1, a branch that no longer receives security fixes (minimum supported branch is 8.2).",
|
||||
),
|
||||
(
|
||||
"64bit Amazon Linux 2 v3.9.5 running PHP 8.2",
|
||||
"FAIL",
|
||||
"Elastic Beanstalk environment test-env runs PHP 8.2 on platform '64bit Amazon Linux 2 v3.9.5 running PHP 8.2', a platform family without fixed PHP releases; migrate it to a PHP 8.2 Amazon Linux 2023 platform version 4.13.13 or newer.",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_php_environment(
|
||||
self, solution_stack_name, expected_status, expected_message
|
||||
):
|
||||
result = _run_check({ENV_ARN: _environment(solution_stack_name)})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == expected_status
|
||||
assert result[0].status_extended == expected_message
|
||||
assert result[0].resource_id == "e-abc123"
|
||||
assert result[0].resource_arn == ENV_ARN
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
def test_platform_arn_fallback(self):
|
||||
environments = {
|
||||
ENV_ARN: _environment(
|
||||
platform_arn=f"arn:aws:elasticbeanstalk:{AWS_REGION_EU_WEST_1}::platform/PHP 8.3 running on 64bit Amazon Linux 2023/4.13.13"
|
||||
)
|
||||
}
|
||||
result = _run_check(environments)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
def test_custom_minimums(self):
|
||||
environments = {
|
||||
ENV_ARN: _environment("64bit Amazon Linux 2023 v4.13.13 running PHP 8.3")
|
||||
}
|
||||
result = _run_check(
|
||||
environments,
|
||||
{
|
||||
"elasticbeanstalk_php_min_branch": "8.4",
|
||||
"elasticbeanstalk_php_min_platform_version": "4.13.13",
|
||||
},
|
||||
)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Elastic Beanstalk environment test-env runs PHP 8.3, a branch that no longer receives security fixes (minimum supported branch is 8.4)."
|
||||
)
|
||||
@@ -7,7 +7,11 @@ from moto import mock_aws
|
||||
from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_service import (
|
||||
ElasticBeanstalk,
|
||||
)
|
||||
from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_EU_WEST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
@@ -120,6 +124,44 @@ class Test_ElasticBeanstalk_Service:
|
||||
== "test-app"
|
||||
)
|
||||
|
||||
@mock_aws
|
||||
def test_describe_environments_platform(self):
|
||||
environment_arn = f"arn:aws:elasticbeanstalk:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:environment/test-app/test-env"
|
||||
|
||||
def mock_describe_environments(self, operation_name, kwarg):
|
||||
if operation_name == "DescribeEnvironments":
|
||||
return {
|
||||
"Environments": [
|
||||
{
|
||||
"EnvironmentId": "e-abc123",
|
||||
"EnvironmentArn": environment_arn,
|
||||
"ApplicationName": "test-app",
|
||||
"EnvironmentName": "test-env",
|
||||
"SolutionStackName": "64bit Amazon Linux 2023 v4.13.13 running PHP 8.4",
|
||||
"PlatformArn": f"arn:aws:elasticbeanstalk:{AWS_REGION_EU_WEST_1}::platform/PHP 8.4 running on 64bit Amazon Linux 2023/4.13.13",
|
||||
}
|
||||
]
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
with patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_describe_environments,
|
||||
):
|
||||
elasticbeanstalk = ElasticBeanstalk(
|
||||
set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
)
|
||||
|
||||
environment = elasticbeanstalk.environments[environment_arn]
|
||||
assert (
|
||||
environment.solution_stack_name
|
||||
== "64bit Amazon Linux 2023 v4.13.13 running PHP 8.4"
|
||||
)
|
||||
assert (
|
||||
environment.platform_arn
|
||||
== f"arn:aws:elasticbeanstalk:{AWS_REGION_EU_WEST_1}::platform/PHP 8.4 running on 64bit Amazon Linux 2023/4.13.13"
|
||||
)
|
||||
|
||||
# Test _describe_configuration_settings
|
||||
@mock_aws
|
||||
def test_describe_configuration_settings(self):
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from prowler.providers.aws.services.lightsail.lightsail_service import Instance
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_REGION_US_EAST_1,
|
||||
AWS_REGION_US_EAST_1_AZA,
|
||||
BASE_LIGHTSAIL_ARN,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.aws.services.lightsail.lightsail_instance_php_blueprint_updated.lightsail_instance_php_blueprint_updated"
|
||||
INSTANCE_ARN = f"{BASE_LIGHTSAIL_ARN}:Instance/test-instance"
|
||||
|
||||
|
||||
def _instance(blueprint_id, blueprint_name=""):
|
||||
return Instance(
|
||||
name="test-instance",
|
||||
id="1234/5678",
|
||||
arn=INSTANCE_ARN,
|
||||
tags=[],
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
availability_zone=AWS_REGION_US_EAST_1_AZA,
|
||||
static_ip=False,
|
||||
public_ip="",
|
||||
private_ip="172.16.2.3",
|
||||
ipv6_addresses=[],
|
||||
ip_address_type="ipv4",
|
||||
ports=[],
|
||||
auto_snapshot=False,
|
||||
blueprint_id=blueprint_id,
|
||||
blueprint_name=blueprint_name,
|
||||
)
|
||||
|
||||
|
||||
def _run_check(instances, audit_config=None):
|
||||
lightsail_client = MagicMock
|
||||
lightsail_client.instances = instances
|
||||
lightsail_client.audit_config = audit_config or {}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider([AWS_REGION_US_EAST_1]),
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.aws.services.lightsail.lightsail_service.Lightsail",
|
||||
new=lightsail_client,
|
||||
),
|
||||
patch(f"{CHECK_PATH}.lightsail_client", new=lightsail_client),
|
||||
):
|
||||
from prowler.providers.aws.services.lightsail.lightsail_instance_php_blueprint_updated.lightsail_instance_php_blueprint_updated import (
|
||||
lightsail_instance_php_blueprint_updated,
|
||||
)
|
||||
|
||||
return lightsail_instance_php_blueprint_updated().execute()
|
||||
|
||||
|
||||
class Test_lightsail_instance_php_blueprint_updated:
|
||||
def test_no_instances(self):
|
||||
assert len(_run_check({})) == 0
|
||||
|
||||
@pytest.mark.parametrize("blueprint_id", ["ubuntu_22_04", "nodejs", "mean", ""])
|
||||
def test_non_php_blueprint_is_skipped(self, blueprint_id):
|
||||
assert len(_run_check({INSTANCE_ARN: _instance(blueprint_id)})) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"blueprint_id",
|
||||
["wordpress", "wordpress_multisite", "lamp_8_bitnami", "nginx", "drupal"],
|
||||
)
|
||||
def test_php_blueprint_is_manual(self, blueprint_id):
|
||||
result = _run_check({INSTANCE_ARN: _instance(blueprint_id, "WordPress")})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "MANUAL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Lightsail instance test-instance was created from the PHP blueprint '{blueprint_id}'; the PHP runtime cannot be inspected through the API, verify over SSH that it runs a fixed release (8.2.35, 8.3.36, 8.4.27, 8.5.12 or newer); Bitnami-packaged blueprints bundle a PHP copy that apt never updates, so migrate them to the Lightsail-packaged blueprint or replace the bundled PHP with a package-managed one."
|
||||
)
|
||||
assert result[0].resource_id == "1234/5678"
|
||||
assert result[0].resource_arn == INSTANCE_ARN
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
def test_custom_blueprint_list(self):
|
||||
instances = {INSTANCE_ARN: _instance("custom_php_app")}
|
||||
assert len(_run_check(instances)) == 0
|
||||
result = _run_check(instances, {"lightsail_php_blueprints": ["custom_php"]})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "MANUAL"
|
||||
@@ -202,6 +202,14 @@ class TestLightsailService:
|
||||
== f"{BASE_LIGHTSAIL_ARN}:Instance/test-id"
|
||||
)
|
||||
assert lightsail.instances[f"{BASE_LIGHTSAIL_ARN}:Instance/test-id"].tags == []
|
||||
assert (
|
||||
lightsail.instances[f"{BASE_LIGHTSAIL_ARN}:Instance/test-id"].blueprint_id
|
||||
== "wordpress"
|
||||
)
|
||||
assert (
|
||||
lightsail.instances[f"{BASE_LIGHTSAIL_ARN}:Instance/test-id"].blueprint_name
|
||||
== "WordPress"
|
||||
)
|
||||
assert (
|
||||
lightsail.instances[f"{BASE_LIGHTSAIL_ARN}:Instance/test-id"].region
|
||||
== AWS_REGION_US_EAST_1
|
||||
|
||||
@@ -207,7 +207,24 @@ class Test_WAFv2_Service:
|
||||
"CloudWatchMetricsEnabled": True,
|
||||
"MetricName": "web-acl-test-metric",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "AWS-AWSManagedRulesPHPRuleSet",
|
||||
"Priority": 2,
|
||||
"Statement": {
|
||||
"ManagedRuleGroupStatement": {
|
||||
"VendorName": "AWS",
|
||||
"Name": "AWSManagedRulesPHPRuleSet",
|
||||
"Version": "Version_2.3",
|
||||
}
|
||||
},
|
||||
"OverrideAction": {"None": {}},
|
||||
"VisibilityConfig": {
|
||||
"SampledRequestsEnabled": True,
|
||||
"CloudWatchMetricsEnabled": True,
|
||||
"MetricName": "php-rule-set",
|
||||
},
|
||||
},
|
||||
],
|
||||
VisibilityConfig={
|
||||
"SampledRequestsEnabled": False,
|
||||
@@ -221,6 +238,11 @@ class Test_WAFv2_Service:
|
||||
aws = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
wafv2 = WAFv2(aws)
|
||||
assert len(wafv2.web_acls) == 1
|
||||
assert len(wafv2.web_acls[waf_arn].rules) == 1
|
||||
assert len(wafv2.web_acls[waf_arn].rules) == 2
|
||||
assert wafv2.web_acls[waf_arn].rules[0].name == "rule-on"
|
||||
assert wafv2.web_acls[waf_arn].rules[0].cloudwatch_metrics_enabled
|
||||
assert wafv2.web_acls[waf_arn].rules[0].managed_rule_group is None
|
||||
managed = wafv2.web_acls[waf_arn].rules[1].managed_rule_group
|
||||
assert managed.vendor_name == "AWS"
|
||||
assert managed.name == "AWSManagedRulesPHPRuleSet"
|
||||
assert managed.version == "Version_2.3"
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.aws.services.wafv2.wafv2_service import (
|
||||
ManagedRuleGroup,
|
||||
Rule,
|
||||
WebAclv2,
|
||||
)
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.aws.services.wafv2.wafv2_webacl_managed_rule_groups_enabled.wafv2_webacl_managed_rule_groups_enabled"
|
||||
WEB_ACL_ARN = f"arn:aws:wafv2:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:regional/webacl/test-acl/abc"
|
||||
|
||||
|
||||
def _web_acl(rules):
|
||||
return WebAclv2(
|
||||
arn=WEB_ACL_ARN,
|
||||
name="test-acl",
|
||||
id="abc",
|
||||
albs=[],
|
||||
user_pools=[],
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
tags=[],
|
||||
rules=rules,
|
||||
)
|
||||
|
||||
|
||||
def _run_check(web_acls):
|
||||
wafv2_client = mock.MagicMock()
|
||||
wafv2_client.web_acls = web_acls
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_aws_provider([AWS_REGION_US_EAST_1]),
|
||||
),
|
||||
mock.patch(f"{CHECK_PATH}.wafv2_client", new=wafv2_client),
|
||||
):
|
||||
from prowler.providers.aws.services.wafv2.wafv2_webacl_managed_rule_groups_enabled.wafv2_webacl_managed_rule_groups_enabled import (
|
||||
wafv2_webacl_managed_rule_groups_enabled,
|
||||
)
|
||||
|
||||
return wafv2_webacl_managed_rule_groups_enabled().execute()
|
||||
|
||||
|
||||
class Test_wafv2_webacl_managed_rule_groups_enabled:
|
||||
def test_no_web_acls(self):
|
||||
assert len(_run_check({})) == 0
|
||||
|
||||
def test_no_managed_rule_groups(self):
|
||||
result = _run_check({WEB_ACL_ARN: _web_acl([Rule(name="custom-rule")])})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS WAFv2 Web ACL test-acl does not use any managed rule group."
|
||||
)
|
||||
assert result[0].resource_id == "abc"
|
||||
assert result[0].resource_arn == WEB_ACL_ARN
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
def test_managed_rule_groups(self):
|
||||
rules = [
|
||||
Rule(name="custom-rule"),
|
||||
Rule(
|
||||
name="AWS-AWSManagedRulesCommonRuleSet",
|
||||
managed_rule_group=ManagedRuleGroup(
|
||||
vendor_name="AWS", name="AWSManagedRulesCommonRuleSet"
|
||||
),
|
||||
),
|
||||
Rule(
|
||||
name="AWS-AWSManagedRulesPHPRuleSet",
|
||||
managed_rule_group=ManagedRuleGroup(
|
||||
vendor_name="AWS",
|
||||
name="AWSManagedRulesPHPRuleSet",
|
||||
version="Version_2.3",
|
||||
),
|
||||
),
|
||||
]
|
||||
result = _run_check({WEB_ACL_ARN: _web_acl(rules)})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS WAFv2 Web ACL test-acl uses managed rule groups: AWS/AWSManagedRulesCommonRuleSet, AWS/AWSManagedRulesPHPRuleSet."
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
import pytest
|
||||
|
||||
from prowler.providers.azure.lib.runtime.runtime_version import (
|
||||
parse_java_version,
|
||||
parse_runtime_version,
|
||||
runtime_version_at_least,
|
||||
)
|
||||
|
||||
|
||||
class Test_runtime_version_helpers:
|
||||
@pytest.mark.parametrize(
|
||||
"value,expected",
|
||||
[
|
||||
("PHP|8.3", (8, 3)),
|
||||
("php|8.0", (8, 0)),
|
||||
("PYTHON|3.12", (3, 12)),
|
||||
("8.2.35", (8, 2, 35)),
|
||||
("", ()),
|
||||
(None, ()),
|
||||
("PHP|latest", ()),
|
||||
],
|
||||
)
|
||||
def test_parse_runtime_version(self, value, expected):
|
||||
assert parse_runtime_version(value) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value,expected",
|
||||
[
|
||||
("JAVA|17-java17", (17,)),
|
||||
("TOMCAT|10.0-java11", (11,)),
|
||||
("JBOSSEAP|7-java8", (8,)),
|
||||
("JAVA|8-jre8", (8,)),
|
||||
("java1.8", (8,)),
|
||||
("17", (17,)),
|
||||
("", ()),
|
||||
],
|
||||
)
|
||||
def test_parse_java_version(self, value, expected):
|
||||
assert parse_java_version(value) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"current,minimum,expected",
|
||||
[
|
||||
((8, 3), (8, 2), True),
|
||||
((8, 2), (8, 2), True),
|
||||
((8, 1), (8, 2), False),
|
||||
((8, 2), (8, 2, 35), True),
|
||||
((9,), (8, 2), True),
|
||||
((), (8, 2), False),
|
||||
((8, 2), (), False),
|
||||
],
|
||||
)
|
||||
def test_runtime_version_at_least(self, current, minimum, expected):
|
||||
assert runtime_version_at_least(current, minimum) is expected
|
||||
+144
-310
@@ -1,6 +1,8 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_DISPLAY,
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
@@ -8,333 +10,165 @@ from tests.providers.azure.azure_fixtures import (
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest"
|
||||
|
||||
|
||||
def _run_check(app_client):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(f"{CHECK_PATH}.app_client", new=app_client),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
|
||||
return app_ensure_java_version_is_latest().execute()
|
||||
|
||||
|
||||
def _app_client(configurations, audit_config=None):
|
||||
# app_service imports monitor_client, which needs the provider patched at import time
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.audit_config = audit_config or {}
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=configurations,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
return app_client, resource_id
|
||||
|
||||
|
||||
class Test_app_ensure_java_version_is_latest:
|
||||
def test_app_no_subscriptions(self):
|
||||
app_client = mock.MagicMock
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {}
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_app_subscriptions_empty(self):
|
||||
app_client = mock.MagicMock
|
||||
def test_app_subscription_empty(self):
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {AZURE_SUBSCRIPTION_ID: {}}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_configurations_none(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client, _ = _app_client(None)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
def test_app_linux_fx_version_none_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, java_version=None)
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_linux_fx_version_none_uses_windows_version(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, java_version="17")
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
def test_app_other_runtime_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="php|8.0", java_version=None)
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"configurations,minimum,expected_status,expected_message",
|
||||
[
|
||||
(
|
||||
{"linux_fx_version": "Tomcat|9.0-java11", "java_version": None},
|
||||
"17",
|
||||
"FAIL",
|
||||
"Java version is set to 'Tomcat|9.0-java11', which is below the minimum supported version 'java 17',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "Tomcat|9.0-java17", "java_version": None},
|
||||
"17",
|
||||
"PASS",
|
||||
"Java version is set to 'Tomcat|9.0-java17', which meets the minimum supported version 'java 17',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=None,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_app_linux_java_version_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"java_latest_version": "17"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "JAVA|21-java21", "java_version": None},
|
||||
"17",
|
||||
"PASS",
|
||||
"Java version is set to 'JAVA|21-java21', which meets the minimum supported version 'java 17',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "JAVA|8-jre8", "java_version": None},
|
||||
"17",
|
||||
"FAIL",
|
||||
"Java version is set to 'JAVA|8-jre8', which is below the minimum supported version 'java 17',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(
|
||||
linux_fx_version="Tomcat|9.0-java17", java_version=None
|
||||
),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Java version is set to 'java 17' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_linux_java_version_not_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"java_latest_version": "17"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "JBOSSEAP|7-java8", "java_version": None},
|
||||
"11",
|
||||
"FAIL",
|
||||
"Java version is set to 'JBOSSEAP|7-java8', which is below the minimum supported version 'java 11',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "", "java_version": "11"},
|
||||
"17",
|
||||
"FAIL",
|
||||
"Java version is set to 'java11', which is below the minimum supported version 'java 17',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(
|
||||
linux_fx_version="Tomcat|9.0-java11", java_version=None
|
||||
),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Java version is set to 'Tomcat|9.0-java11', but should be set to 'java 17' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_windows_java_version_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"java_latest_version": "17"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "", "java_version": "17"},
|
||||
"17",
|
||||
"PASS",
|
||||
"Java version is set to 'java17', which meets the minimum supported version 'java 17',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "", "java_version": "1.8"},
|
||||
"17",
|
||||
"FAIL",
|
||||
"Java version is set to 'java1.8', which is below the minimum supported version 'java 17',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
],
|
||||
)
|
||||
def test_app_java_version(
|
||||
self, configurations, minimum, expected_status, expected_message
|
||||
):
|
||||
app_client, resource_id = _app_client(
|
||||
mock.MagicMock(**configurations), {"java_latest_version": minimum}
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == expected_status
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"{expected_message} for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(
|
||||
linux_fx_version="", java_version="17"
|
||||
),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Java version is set to 'java 17' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_windows_java_version_not_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.audit_config = {"java_latest_version": "17"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(
|
||||
linux_fx_version="", java_version="11"
|
||||
),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Java version is set to 'java11', but should be set to 'java 17' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_linux_php_version_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"java_latest_version": "17"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_java_version_is_latest.app_ensure_java_version_is_latest import (
|
||||
app_ensure_java_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(
|
||||
linux_fx_version="php|8.0", java_version=None
|
||||
),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_java_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
def test_app_default_minimum(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="JAVA|21-java21", java_version=None)
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
+157
-164
@@ -1,6 +1,8 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_DISPLAY,
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
@@ -8,186 +10,177 @@ from tests.providers.azure.azure_fixtures import (
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest"
|
||||
|
||||
|
||||
def _run_check(app_client):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(f"{CHECK_PATH}.app_client", new=app_client),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
|
||||
return app_ensure_php_version_is_latest().execute()
|
||||
|
||||
|
||||
def _app_client(configurations, audit_config=None):
|
||||
# app_service imports monitor_client, which needs the provider patched at import time
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.audit_config = audit_config or {}
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=configurations,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
return app_client, resource_id
|
||||
|
||||
|
||||
class Test_app_ensure_php_version_is_latest:
|
||||
def test_app_no_subscriptions(self):
|
||||
app_client = mock.MagicMock
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_php_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_subscription_empty(self):
|
||||
app_client = mock.MagicMock
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {AZURE_SUBSCRIPTION_ID: {}}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_php_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_configurations_none(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client, _ = _app_client(None)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
def test_app_linux_fx_version_none_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, php_version="")
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_linux_fx_version_none_uses_windows_version(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, php_version="8.5")
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
def test_app_other_runtime_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="PYTHON|3.12", php_version="")
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"configurations,minimum,expected_status,expected_message",
|
||||
[
|
||||
(
|
||||
{"linux_fx_version": "php|8.0", "php_version": ""},
|
||||
"8.2",
|
||||
"FAIL",
|
||||
"PHP version is set to 'php|8.0', which is below the minimum supported version '8.2',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.1", "php_version": ""},
|
||||
"8.2",
|
||||
"FAIL",
|
||||
"PHP version is set to 'PHP|8.1', which is below the minimum supported version '8.2',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=None,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_php_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_app_php_version_not_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"php_latest_version": "8.2"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.2", "php_version": ""},
|
||||
"8.2",
|
||||
"PASS",
|
||||
"PHP version is set to 'PHP|8.2', which meets the minimum supported version '8.2',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.3", "php_version": ""},
|
||||
"8.2",
|
||||
"PASS",
|
||||
"PHP version is set to 'PHP|8.3', which meets the minimum supported version '8.2',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(linux_fx_version="php|8.0"),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_php_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"PHP version is set to 'php|8.0', the latest version that you could use is the '8.2' version, for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_php_version_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"php_latest_version": "8.2"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.5", "php_version": ""},
|
||||
"8.2",
|
||||
"PASS",
|
||||
"PHP version is set to 'PHP|8.5', which meets the minimum supported version '8.2',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.3", "php_version": ""},
|
||||
"8.4",
|
||||
"FAIL",
|
||||
"PHP version is set to 'PHP|8.3', which is below the minimum supported version '8.4',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_php_version_is_latest.app_ensure_php_version_is_latest import (
|
||||
app_ensure_php_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
(
|
||||
{"linux_fx_version": "PHP|8.2", "php_version": ""},
|
||||
"8.2.35",
|
||||
"PASS",
|
||||
"PHP version is set to 'PHP|8.2', which meets the minimum supported version '8.2.35',",
|
||||
),
|
||||
(
|
||||
{"linux_fx_version": "", "php_version": "7.4"},
|
||||
"8.2",
|
||||
"FAIL",
|
||||
"PHP version is set to '7.4', which is below the minimum supported version '8.2',",
|
||||
),
|
||||
(
|
||||
{"linux_fx_version": "", "php_version": "8.2"},
|
||||
"8.2",
|
||||
"PASS",
|
||||
"PHP version is set to '8.2', which meets the minimum supported version '8.2',",
|
||||
),
|
||||
(
|
||||
{"linux_fx_version": "PHP|latest", "php_version": ""},
|
||||
"8.2",
|
||||
"FAIL",
|
||||
"PHP version is set to 'PHP|latest', which is below the minimum supported version '8.2',",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_app_php_version(
|
||||
self, configurations, minimum, expected_status, expected_message
|
||||
):
|
||||
app_client, resource_id = _app_client(
|
||||
mock.MagicMock(**configurations), {"php_latest_version": minimum}
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == expected_status
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"{expected_message} for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(linux_fx_version="php|8.2"),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_php_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"PHP version is set to '8.2' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
def test_app_default_minimum(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="PHP|8.5", php_version="")
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
+135
-165
@@ -1,6 +1,8 @@
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.providers.azure.azure_fixtures import (
|
||||
AZURE_SUBSCRIPTION_DISPLAY,
|
||||
AZURE_SUBSCRIPTION_ID,
|
||||
@@ -8,185 +10,153 @@ from tests.providers.azure.azure_fixtures import (
|
||||
set_mocked_azure_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest"
|
||||
|
||||
|
||||
def _run_check(app_client):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(f"{CHECK_PATH}.app_client", new=app_client),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
|
||||
return app_ensure_python_version_is_latest().execute()
|
||||
|
||||
|
||||
def _app_client(configurations, audit_config=None):
|
||||
# app_service imports monitor_client, which needs the provider patched at import time
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.audit_config = audit_config or {}
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=configurations,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
return app_client, resource_id
|
||||
|
||||
|
||||
class Test_app_ensure_python_version_is_latest:
|
||||
def test_app_no_subscriptions(self):
|
||||
app_client = mock.MagicMock
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {}
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_python_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_app_subscriptions_empty(self):
|
||||
app_client = mock.MagicMock
|
||||
def test_app_subscription_empty(self):
|
||||
app_client = mock.MagicMock()
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
app_client.apps = {AZURE_SUBSCRIPTION_ID: {}}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
|
||||
check = app_ensure_python_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_configurations_none(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
app_client, _ = _app_client(None)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_linux_fx_version_none_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, python_version="")
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
def test_app_linux_fx_version_none_uses_windows_version(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version=None, python_version="3.12")
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
def test_app_other_runtime_is_skipped(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="PHP|8.2", python_version="")
|
||||
)
|
||||
assert len(_run_check(app_client)) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"configurations,minimum,expected_status,expected_message",
|
||||
[
|
||||
(
|
||||
{"linux_fx_version": "python|3.10", "python_version": ""},
|
||||
"3.12",
|
||||
"FAIL",
|
||||
"Python version is set to 'python|3.10', which is below the minimum supported version '3.12',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "PYTHON|3.12", "python_version": ""},
|
||||
"3.12",
|
||||
"PASS",
|
||||
"Python version is set to 'PYTHON|3.12', which meets the minimum supported version '3.12',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=None,
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_python_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_app_python_version_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"python_latest_version": "3.12"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "PYTHON|3.13", "python_version": ""},
|
||||
"3.12",
|
||||
"PASS",
|
||||
"Python version is set to 'PYTHON|3.13', which meets the minimum supported version '3.12',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "PYTHON|3.9", "python_version": ""},
|
||||
"3.10",
|
||||
"FAIL",
|
||||
"Python version is set to 'PYTHON|3.9', which is below the minimum supported version '3.10',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(linux_fx_version="python|3.12"),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_python_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Python version is set to '3.12' for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
def test_app_python_version_not_latest(self):
|
||||
resource_id = f"/subscriptions/{uuid4()}"
|
||||
app_client = mock.MagicMock
|
||||
app_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}
|
||||
|
||||
app_client.audit_config = {"python_latest_version": "3.12"}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_azure_provider(),
|
||||
(
|
||||
{"linux_fx_version": "", "python_version": "3.4"},
|
||||
"3.12",
|
||||
"FAIL",
|
||||
"Python version is set to '3.4', which is below the minimum supported version '3.12',",
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest.app_client",
|
||||
new=app_client,
|
||||
(
|
||||
{"linux_fx_version": "", "python_version": "3.12"},
|
||||
"3.12",
|
||||
"PASS",
|
||||
"Python version is set to '3.12', which meets the minimum supported version '3.12',",
|
||||
),
|
||||
):
|
||||
from prowler.providers.azure.services.app.app_ensure_python_version_is_latest.app_ensure_python_version_is_latest import (
|
||||
app_ensure_python_version_is_latest,
|
||||
)
|
||||
from prowler.providers.azure.services.app.app_service import WebApp
|
||||
],
|
||||
)
|
||||
def test_app_python_version(
|
||||
self, configurations, minimum, expected_status, expected_message
|
||||
):
|
||||
app_client, resource_id = _app_client(
|
||||
mock.MagicMock(**configurations), {"python_latest_version": minimum}
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == expected_status
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"{expected_message} for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
|
||||
app_client.apps = {
|
||||
AZURE_SUBSCRIPTION_ID: {
|
||||
resource_id: WebApp(
|
||||
resource_id=resource_id,
|
||||
name="app_id-1",
|
||||
auth_enabled=True,
|
||||
configurations=mock.MagicMock(linux_fx_version="python|3.10"),
|
||||
client_cert_mode="Ignore",
|
||||
https_only=False,
|
||||
identity=None,
|
||||
location="West Europe",
|
||||
)
|
||||
}
|
||||
}
|
||||
check = app_ensure_python_version_is_latest()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Python version is 'python|3.10', the latest version that you could use is the '3.12' version, for app 'app_id-1' in subscription '{AZURE_SUBSCRIPTION_DISPLAY}'."
|
||||
)
|
||||
assert result[0].resource_id == resource_id
|
||||
assert result[0].resource_name == "app_id-1"
|
||||
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
|
||||
assert result[0].location == "West Europe"
|
||||
def test_app_default_minimum(self):
|
||||
app_client, _ = _app_client(
|
||||
mock.MagicMock(linux_fx_version="PYTHON|3.13", python_version="")
|
||||
)
|
||||
result = _run_check(app_client)
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
@@ -93,6 +93,7 @@ class TestGCPProvider:
|
||||
"max_unused_account_days": 180,
|
||||
"storage_min_retention_days": 90,
|
||||
"secretmanager_max_rotation_days": 90,
|
||||
"appengine_php_min_version": "8.2",
|
||||
"mig_min_zones": 2,
|
||||
"max_snapshot_age_days": 90,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
from prowler.providers.gcp.services.appengine.appengine_service import AppEngine
|
||||
from tests.providers.gcp.gcp_fixtures import (
|
||||
GCP_PROJECT_ID,
|
||||
GCP_US_CENTER1_LOCATION,
|
||||
mock_is_api_active,
|
||||
set_mocked_gcp_provider,
|
||||
)
|
||||
|
||||
|
||||
def _make_appengine_client(versions, app_error=None):
|
||||
client = MagicMock()
|
||||
apps = client.apps()
|
||||
if app_error:
|
||||
apps.get().execute.side_effect = app_error
|
||||
else:
|
||||
apps.get().execute.return_value = {
|
||||
"id": GCP_PROJECT_ID,
|
||||
"locationId": GCP_US_CENTER1_LOCATION,
|
||||
}
|
||||
apps.services().list().execute.return_value = {"services": [{"id": "default"}]}
|
||||
apps.services().list_next.return_value = None
|
||||
apps.services().versions().list().execute.return_value = {"versions": versions}
|
||||
apps.services().versions().list_next.return_value = None
|
||||
return client
|
||||
|
||||
|
||||
def _patched_service(client):
|
||||
return (
|
||||
patch(
|
||||
"prowler.providers.gcp.lib.service.service.GCPService.__is_api_active__",
|
||||
new=mock_is_api_active,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.gcp.lib.service.service.GCPService.__generate_client__",
|
||||
new=lambda *_, **__: client,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class TestAppEngineService:
|
||||
def test_get_versions(self):
|
||||
client = _make_appengine_client(
|
||||
[
|
||||
{
|
||||
"name": f"apps/{GCP_PROJECT_ID}/services/default/versions/v1",
|
||||
"id": "v1",
|
||||
"runtime": "php82",
|
||||
"env": "standard",
|
||||
"servingStatus": "SERVING",
|
||||
},
|
||||
{
|
||||
"id": "v2",
|
||||
"runtime": "php",
|
||||
"env": "flexible",
|
||||
"servingStatus": "STOPPED",
|
||||
},
|
||||
]
|
||||
)
|
||||
api_active, generate_client = _patched_service(client)
|
||||
with api_active, generate_client:
|
||||
appengine = AppEngine(set_mocked_gcp_provider(project_ids=[GCP_PROJECT_ID]))
|
||||
|
||||
assert len(appengine.versions) == 2
|
||||
first = appengine.versions[0]
|
||||
assert first.id == f"apps/{GCP_PROJECT_ID}/services/default/versions/v1"
|
||||
assert first.name == "default/v1"
|
||||
assert first.version_id == "v1"
|
||||
assert first.service == "default"
|
||||
assert first.project_id == GCP_PROJECT_ID
|
||||
assert first.location == GCP_US_CENTER1_LOCATION
|
||||
assert first.runtime == "php82"
|
||||
assert first.env == "standard"
|
||||
assert first.serving_status == "SERVING"
|
||||
second = appengine.versions[1]
|
||||
assert second.id == f"apps/{GCP_PROJECT_ID}/services/default/versions/v2"
|
||||
assert second.env == "flexible"
|
||||
assert second.serving_status == "STOPPED"
|
||||
|
||||
def test_project_without_application(self):
|
||||
response = MagicMock(status=404)
|
||||
client = _make_appengine_client([], app_error=HttpError(response, b"not found"))
|
||||
api_active, generate_client = _patched_service(client)
|
||||
with api_active, generate_client:
|
||||
appengine = AppEngine(set_mocked_gcp_provider(project_ids=[GCP_PROJECT_ID]))
|
||||
|
||||
assert appengine.versions == []
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.providers.gcp.gcp_fixtures import (
|
||||
GCP_PROJECT_ID,
|
||||
GCP_US_CENTER1_LOCATION,
|
||||
set_mocked_gcp_provider,
|
||||
)
|
||||
|
||||
CHECK_PATH = "prowler.providers.gcp.services.appengine.appengine_version_php_runtime_supported.appengine_version_php_runtime_supported"
|
||||
|
||||
|
||||
def _version(runtime, env="standard", serving_status="SERVING"):
|
||||
from prowler.providers.gcp.services.appengine.appengine_service import Version
|
||||
|
||||
return Version(
|
||||
id=f"apps/{GCP_PROJECT_ID}/services/default/versions/v1",
|
||||
name="default/v1",
|
||||
version_id="v1",
|
||||
service="default",
|
||||
project_id=GCP_PROJECT_ID,
|
||||
location=GCP_US_CENTER1_LOCATION,
|
||||
runtime=runtime,
|
||||
env=env,
|
||||
serving_status=serving_status,
|
||||
)
|
||||
|
||||
|
||||
def _run_check(versions, audit_config=None):
|
||||
appengine_client = mock.MagicMock()
|
||||
appengine_client.versions = versions
|
||||
appengine_client.audit_config = audit_config or {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_gcp_provider(),
|
||||
),
|
||||
mock.patch(f"{CHECK_PATH}.appengine_client", new=appengine_client),
|
||||
):
|
||||
from prowler.providers.gcp.services.appengine.appengine_version_php_runtime_supported.appengine_version_php_runtime_supported import (
|
||||
appengine_version_php_runtime_supported,
|
||||
)
|
||||
|
||||
return appengine_version_php_runtime_supported().execute()
|
||||
|
||||
|
||||
class Test_appengine_version_php_runtime_supported:
|
||||
def test_no_versions(self):
|
||||
assert len(_run_check([])) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"runtime,env,serving_status",
|
||||
[
|
||||
("python312", "standard", "SERVING"),
|
||||
("nodejs20", "standard", "SERVING"),
|
||||
("php82", "standard", "STOPPED"),
|
||||
("custom", "flexible", "SERVING"),
|
||||
],
|
||||
)
|
||||
def test_skipped_versions(self, runtime, env, serving_status):
|
||||
assert len(_run_check([_version(runtime, env, serving_status)])) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"runtime,expected_status,expected_message",
|
||||
[
|
||||
(
|
||||
"php82",
|
||||
"PASS",
|
||||
"App Engine version default/v1 runs PHP 8.2 ('php82'), a supported runtime that receives security fixes automatically.",
|
||||
),
|
||||
(
|
||||
"php85",
|
||||
"PASS",
|
||||
"App Engine version default/v1 runs PHP 8.5 ('php85'), a supported runtime that receives security fixes automatically.",
|
||||
),
|
||||
(
|
||||
"php81",
|
||||
"FAIL",
|
||||
"App Engine version default/v1 runs PHP 8.1 ('php81'), a runtime that no longer receives security fixes (minimum supported version is 8.2).",
|
||||
),
|
||||
(
|
||||
"php55",
|
||||
"FAIL",
|
||||
"App Engine version default/v1 runs PHP 5.5 ('php55'), a runtime that no longer receives security fixes (minimum supported version is 8.2).",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_standard_runtime(self, runtime, expected_status, expected_message):
|
||||
result = _run_check([_version(runtime)])
|
||||
assert len(result) == 1
|
||||
assert result[0].status == expected_status
|
||||
assert result[0].status_extended == expected_message
|
||||
assert (
|
||||
result[0].resource_id
|
||||
== f"apps/{GCP_PROJECT_ID}/services/default/versions/v1"
|
||||
)
|
||||
assert result[0].resource_name == "default/v1"
|
||||
assert result[0].project_id == GCP_PROJECT_ID
|
||||
assert result[0].location == GCP_US_CENTER1_LOCATION
|
||||
|
||||
def test_flexible_runtime_is_manual(self):
|
||||
result = _run_check([_version("php", env="flexible")])
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "MANUAL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "App Engine version default/v1 runs on the flexible environment with runtime 'php', which is not patched in place; redeploy it on a fixed PHP release (8.2 or newer) and verify the image."
|
||||
)
|
||||
|
||||
def test_custom_minimum(self):
|
||||
result = _run_check([_version("php83")], {"appengine_php_min_version": "8.4"})
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
Reference in new issue
Block a user