diff --git a/prowler/providers/vercel/services/authentication/authentication_service.py b/prowler/providers/vercel/services/authentication/authentication_service.py index 82e406e476..ef1ed5b2c7 100644 --- a/prowler/providers/vercel/services/authentication/authentication_service.py +++ b/prowler/providers/vercel/services/authentication/authentication_service.py @@ -33,7 +33,9 @@ class Authentication(VercelService): team_id: Team ID to fetch tokens for. None for personal tokens. """ try: - params = {"teamId": team_id} if team_id else {} + # Always set teamId key explicitly — _get won't auto-inject when key + # is present, and requests skips None values from query params. + params = {"teamId": team_id} data = self._get("/v5/user/tokens", params=params) if not data: return diff --git a/tests/providers/vercel/services/deployment/deployment_preview_not_publicly_accessible/deployment_preview_not_publicly_accessible_test.py b/tests/providers/vercel/services/deployment/deployment_preview_not_publicly_accessible/deployment_preview_not_publicly_accessible_test.py index e1e6802088..39a2ab2dd4 100644 --- a/tests/providers/vercel/services/deployment/deployment_preview_not_publicly_accessible/deployment_preview_not_publicly_accessible_test.py +++ b/tests/providers/vercel/services/deployment/deployment_preview_not_publicly_accessible/deployment_preview_not_publicly_accessible_test.py @@ -42,7 +42,7 @@ class Test_deployment_preview_not_publicly_accessible: id=DEPLOYMENT_ID, name="my-app-abc123", target="preview", - deployment_protection="standard", + deployment_protection={"level": "standard"}, project_id=PROJECT_ID, project_name=PROJECT_NAME, team_id=TEAM_ID, @@ -122,7 +122,7 @@ class Test_deployment_preview_not_publicly_accessible: id=DEPLOYMENT_ID, name="my-app-abc123", target="production", - deployment_protection="standard", + deployment_protection={"level": "standard"}, project_id=PROJECT_ID, project_name=PROJECT_NAME, team_id=TEAM_ID, diff --git a/tests/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid_test.py b/tests/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid_test.py index f053d17dcb..0b9ef8a51a 100644 --- a/tests/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid_test.py +++ b/tests/providers/vercel/services/domain/domain_ssl_certificate_valid/domain_ssl_certificate_valid_test.py @@ -65,7 +65,7 @@ class Test_domain_ssl_certificate_valid: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"Domain {DOMAIN_NAME} has a valid SSL certificate provisioned." + == f"Domain {DOMAIN_NAME} has an SSL certificate provisioned." ) assert result[0].team_id == TEAM_ID diff --git a/tests/providers/vercel/services/security/security_waf_enabled/security_waf_enabled_test.py b/tests/providers/vercel/services/security/security_waf_enabled/security_waf_enabled_test.py index 767502e459..1641868175 100644 --- a/tests/providers/vercel/services/security/security_waf_enabled/security_waf_enabled_test.py +++ b/tests/providers/vercel/services/security/security_waf_enabled/security_waf_enabled_test.py @@ -42,6 +42,7 @@ class Test_security_waf_enabled: project_name=PROJECT_NAME, team_id=TEAM_ID, firewall_enabled=True, + managed_rulesets={}, id=PROJECT_ID, name=PROJECT_NAME, ) @@ -81,6 +82,7 @@ class Test_security_waf_enabled: project_name=PROJECT_NAME, team_id=TEAM_ID, firewall_enabled=False, + managed_rulesets={}, id=PROJECT_ID, name=PROJECT_NAME, ) diff --git a/tests/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege_test.py b/tests/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege_test.py index e12c0bbbb7..ebcf8a156f 100644 --- a/tests/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege_test.py +++ b/tests/providers/vercel/services/team/team_member_role_least_privilege/team_member_role_least_privilege_test.py @@ -77,11 +77,12 @@ class Test_team_member_role_least_privilege: assert result[0].status == "PASS" assert ( result[0].status_extended - == f"Team {TEAM_NAME} has 0 owner(s) out of 1 active members (0%), which is within the recommended 20% threshold." + == f"Team {TEAM_NAME} has 0 owner(s) out of 1 active members. Small team with minimum required owner — least privilege threshold not applicable." ) assert result[0].team_id == "" - def test_member_owner_role(self): + def test_small_team_single_owner(self): + """Small team (<5 members) with 1 owner gets a PASS (small team exception).""" team_client = mock.MagicMock team_client.teams = { TEAM_ID: VercelTeam( @@ -100,6 +101,53 @@ class Test_team_member_role_least_privilege: ) } + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_vercel_provider(), + ), + mock.patch( + "prowler.providers.vercel.services.team.team_member_role_least_privilege.team_member_role_least_privilege.team_client", + new=team_client, + ), + ): + from prowler.providers.vercel.services.team.team_member_role_least_privilege.team_member_role_least_privilege import ( + team_member_role_least_privilege, + ) + + check = team_member_role_least_privilege() + result = check.execute() + assert len(result) == 1 + assert result[0].resource_id == TEAM_ID + assert result[0].resource_name == TEAM_NAME + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Team {TEAM_NAME} has 1 owner(s) out of 1 active members. Small team with minimum required owner — least privilege threshold not applicable." + ) + assert result[0].team_id == "" + + def test_large_team_too_many_owners(self): + """Large team (>=5 members) with >20% owners gets a FAIL.""" + team_client = mock.MagicMock + team_client.teams = { + TEAM_ID: VercelTeam( + id=TEAM_ID, + name=TEAM_NAME, + slug=TEAM_SLUG, + saml=SAMLConfig(status="disabled", enforced=False), + members=[ + VercelTeamMember( + id=f"member_{i}", + email=f"member{i}@example.com", + role="OWNER" if i <= 2 else "MEMBER", + status="active", + ) + for i in range(1, 6) + ], + ) + } + with ( mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", @@ -122,6 +170,6 @@ class Test_team_member_role_least_privilege: assert result[0].status == "FAIL" assert ( result[0].status_extended - == f"Team {TEAM_NAME} has 1 owner(s) out of 1 active members (100%), which exceeds the recommended 20% threshold." + == f"Team {TEAM_NAME} has 2 owner(s) out of 5 active members (40%), which exceeds the recommended 20% threshold." ) assert result[0].team_id == ""