mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
fix(vercel): handle team-scoped firewall config responses (#10695)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.vercel.services.project.project_service import Project
|
||||
from tests.providers.vercel.vercel_fixtures import (
|
||||
PROJECT_ID,
|
||||
PROJECT_NAME,
|
||||
TEAM_ID,
|
||||
set_mocked_vercel_provider,
|
||||
)
|
||||
|
||||
|
||||
class TestProjectService:
|
||||
def test_list_projects_parses_security_metadata(self):
|
||||
service = Project.__new__(Project)
|
||||
service.provider = set_mocked_vercel_provider()
|
||||
service.projects = {}
|
||||
service._paginate = mock.MagicMock(
|
||||
return_value=[
|
||||
{
|
||||
"id": PROJECT_ID,
|
||||
"name": PROJECT_NAME,
|
||||
"accountId": TEAM_ID,
|
||||
"security": {
|
||||
"firewallEnabled": True,
|
||||
"firewallConfigVersion": 42,
|
||||
"managedRules": {
|
||||
"owasp": {"active": True, "action": "log"},
|
||||
"ai_bots": {"active": False, "action": "deny"},
|
||||
},
|
||||
"botIdEnabled": True,
|
||||
},
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
service._list_projects()
|
||||
|
||||
project = service.projects[PROJECT_ID]
|
||||
assert project.firewall_enabled is True
|
||||
assert project.firewall_config_version == "42"
|
||||
assert project.managed_rules == {
|
||||
"owasp": {"active": True, "action": "log"},
|
||||
"ai_bots": {"active": False, "action": "deny"},
|
||||
}
|
||||
assert project.bot_id_enabled is True
|
||||
@@ -0,0 +1,199 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.vercel.services.project.project_service import VercelProject
|
||||
from prowler.providers.vercel.services.security.security_service import Security
|
||||
from tests.providers.vercel.vercel_fixtures import PROJECT_ID, PROJECT_NAME, TEAM_ID
|
||||
|
||||
|
||||
class TestSecurityService:
|
||||
def test_fetch_firewall_config_reads_active_version_and_normalizes_response(self):
|
||||
project = VercelProject(id=PROJECT_ID, name=PROJECT_NAME, team_id=TEAM_ID)
|
||||
service = Security.__new__(Security)
|
||||
service.firewall_configs = {}
|
||||
|
||||
service._get = mock.MagicMock(
|
||||
return_value={
|
||||
"active": {
|
||||
"firewallEnabled": True,
|
||||
"managedRules": {
|
||||
"owasp": {"active": True, "action": "deny"},
|
||||
"ai_bots": {"active": False, "action": "deny"},
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"id": "rule-custom",
|
||||
"name": "Block admin access",
|
||||
"active": True,
|
||||
"conditionGroup": [
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"type": "path",
|
||||
"op": "pre",
|
||||
"value": "/admin",
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"mitigate": {
|
||||
"action": "deny",
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "rule-rate-limit",
|
||||
"name": "Rate limit login",
|
||||
"active": True,
|
||||
"conditionGroup": [
|
||||
{
|
||||
"conditions": [
|
||||
{
|
||||
"type": "path",
|
||||
"op": "eq",
|
||||
"value": "/login",
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"mitigate": {
|
||||
"action": "deny",
|
||||
"rateLimit": {
|
||||
"algo": "fixed_window",
|
||||
"window": 60,
|
||||
"limit": 10,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"id": "ip-rule",
|
||||
"ip": "203.0.113.7",
|
||||
"action": "deny",
|
||||
}
|
||||
],
|
||||
},
|
||||
"draft": None,
|
||||
"versions": [1],
|
||||
}
|
||||
)
|
||||
|
||||
service._fetch_firewall_config(project)
|
||||
|
||||
service._get.assert_called_once_with(
|
||||
"/v1/security/firewall/config/active",
|
||||
params={"projectId": PROJECT_ID, "teamId": TEAM_ID},
|
||||
)
|
||||
|
||||
config = service.firewall_configs[PROJECT_ID]
|
||||
assert config.firewall_enabled is True
|
||||
assert config.managed_rulesets == {"owasp": {"active": True, "action": "deny"}}
|
||||
assert [rule["id"] for rule in config.custom_rules] == ["rule-custom"]
|
||||
assert [rule["id"] for rule in config.rate_limiting_rules] == [
|
||||
"rule-rate-limit"
|
||||
]
|
||||
assert [rule["id"] for rule in config.ip_blocking_rules] == ["ip-rule"]
|
||||
|
||||
def test_fetch_firewall_config_parses_crs_managed_rulesets(self):
|
||||
project = VercelProject(
|
||||
id=PROJECT_ID,
|
||||
name=PROJECT_NAME,
|
||||
team_id=TEAM_ID,
|
||||
firewall_config_version="1",
|
||||
)
|
||||
service = Security.__new__(Security)
|
||||
service.firewall_configs = {}
|
||||
|
||||
service._get = mock.MagicMock(
|
||||
return_value={
|
||||
"id": "waf_test",
|
||||
"version": 1,
|
||||
"firewallEnabled": True,
|
||||
"crs": {
|
||||
"gen": {"active": True, "action": "log"},
|
||||
"xss": {"active": True, "action": "deny"},
|
||||
"php": {"active": False, "action": "log"},
|
||||
},
|
||||
"rules": [],
|
||||
"ips": [],
|
||||
}
|
||||
)
|
||||
|
||||
service._fetch_firewall_config(project)
|
||||
|
||||
config = service.firewall_configs[PROJECT_ID]
|
||||
assert config.firewall_enabled is True
|
||||
assert config.managed_rulesets == {
|
||||
"gen": {"active": True, "action": "log"},
|
||||
"xss": {"active": True, "action": "deny"},
|
||||
}
|
||||
|
||||
def test_fetch_firewall_config_falls_back_to_wrapper_when_active_missing(self):
|
||||
project = VercelProject(id=PROJECT_ID, name=PROJECT_NAME, team_id=TEAM_ID)
|
||||
service = Security.__new__(Security)
|
||||
service.firewall_configs = {}
|
||||
|
||||
service._get = mock.MagicMock(
|
||||
side_effect=[
|
||||
Exception("404 active config not found"),
|
||||
{"active": None, "draft": None, "versions": []},
|
||||
]
|
||||
)
|
||||
|
||||
service._fetch_firewall_config(project)
|
||||
|
||||
assert service._get.call_args_list == [
|
||||
mock.call(
|
||||
"/v1/security/firewall/config/active",
|
||||
params={"projectId": PROJECT_ID, "teamId": TEAM_ID},
|
||||
),
|
||||
mock.call(
|
||||
"/v1/security/firewall/config",
|
||||
params={"projectId": PROJECT_ID, "teamId": TEAM_ID},
|
||||
),
|
||||
]
|
||||
|
||||
config = service.firewall_configs[PROJECT_ID]
|
||||
assert config.firewall_enabled is False
|
||||
assert config.managed_rulesets == {}
|
||||
assert config.custom_rules == []
|
||||
assert config.rate_limiting_rules == []
|
||||
assert config.ip_blocking_rules == []
|
||||
|
||||
def test_fetch_firewall_config_uses_project_security_metadata_when_config_empty(
|
||||
self,
|
||||
):
|
||||
project = VercelProject(
|
||||
id=PROJECT_ID,
|
||||
name=PROJECT_NAME,
|
||||
team_id=TEAM_ID,
|
||||
firewall_enabled=True,
|
||||
firewall_config_version="42",
|
||||
managed_rules={
|
||||
"owasp": {"active": True, "action": "log"},
|
||||
"ai_bots": {"active": False, "action": "deny"},
|
||||
},
|
||||
)
|
||||
service = Security.__new__(Security)
|
||||
service.firewall_configs = {}
|
||||
|
||||
service._get = mock.MagicMock(
|
||||
return_value={"active": None, "draft": None, "versions": []}
|
||||
)
|
||||
|
||||
service._fetch_firewall_config(project)
|
||||
|
||||
service._get.assert_called_once_with(
|
||||
"/v1/security/firewall/config/42",
|
||||
params={"projectId": PROJECT_ID, "teamId": TEAM_ID},
|
||||
)
|
||||
|
||||
config = service.firewall_configs[PROJECT_ID]
|
||||
assert config.firewall_enabled is True
|
||||
assert config.managed_rulesets == {"owasp": {"active": True, "action": "log"}}
|
||||
assert config.custom_rules == []
|
||||
assert config.rate_limiting_rules == []
|
||||
assert config.ip_blocking_rules == []
|
||||
Reference in New Issue
Block a user