chore: update asserts in every unit test

This commit is contained in:
Daniel Barranquero
2026-03-18 12:23:09 +01:00
parent fb62b81a9b
commit cc7fa7d49a
33 changed files with 347 additions and 92 deletions

View File

@@ -11,9 +11,6 @@ from prowler.providers.vercel.exceptions.exceptions import (
MAX_WORKERS = 10
# Vercel API base URL
VERCEL_API_BASE = "https://api.vercel.com"
class VercelService:
"""Base class for Vercel services to share provider context and HTTP client."""
@@ -32,6 +29,7 @@ class VercelService:
"Content-Type": "application/json",
}
)
self._base_url = provider.session.base_url
self._team_id = provider.session.team_id
# Thread pool for parallel API calls
@@ -58,7 +56,7 @@ class VercelService:
if self._team_id and "teamId" not in params:
params["teamId"] = self._team_id
url = f"{VERCEL_API_BASE}{path}"
url = f"{self._base_url}{path}"
max_retries = self.audit_config.get("max_retries", 3)
for attempt in range(max_retries + 1):

View File

@@ -11,6 +11,7 @@ class VercelSession(BaseModel):
token: str
team_id: Optional[str] = None
base_url: str = "https://api.vercel.com"
http_session: Any = Field(default=None, exclude=True)

View File

@@ -27,9 +27,6 @@ from prowler.providers.vercel.models import (
VercelTeamInfo,
)
# Vercel API base URL
VERCEL_API_BASE = "https://api.vercel.com"
class VercelProvider(Provider):
"""Vercel provider."""
@@ -189,7 +186,9 @@ class VercelProvider(Provider):
params = {"teamId": session.team_id} if session.team_id else {}
# Get user info
response = http.get(f"{VERCEL_API_BASE}/v2/user", params=params, timeout=30)
response = http.get(
f"{session.base_url}/v2/user", params=params, timeout=30
)
response.raise_for_status()
user_data = response.json().get("user", {})
@@ -202,7 +201,7 @@ class VercelProvider(Provider):
if session.team_id:
params = {"teamId": session.team_id}
team_response = http.get(
f"{VERCEL_API_BASE}/v2/teams/{session.team_id}",
f"{session.base_url}/v2/teams/{session.team_id}",
params=params,
timeout=30,
)
@@ -254,7 +253,7 @@ class VercelProvider(Provider):
if session.team_id:
params["teamId"] = session.team_id
response = session.http_session.get(
f"{VERCEL_API_BASE}/v2/user", params=params, timeout=30
f"{session.base_url}/v2/user", params=params, timeout=30
)
if response.status_code == 401:

View File

@@ -33,12 +33,13 @@ class Test_authentication_no_stale_tokens:
def test_token_active_recently(self):
token_id = "tok_1"
token_name = "Recent Token"
active_at = datetime.now(timezone.utc) - timedelta(days=10)
authentication_client = mock.MagicMock
authentication_client.tokens = {
token_id: VercelAuthToken(
id=token_id,
name=token_name,
active_at=datetime.now(timezone.utc) - timedelta(days=10),
active_at=active_at,
)
}
@@ -62,17 +63,23 @@ class Test_authentication_no_stale_tokens:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "PASS"
assert "was last active on" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) was last active on {active_at.strftime('%Y-%m-%d %H:%M UTC')} (within the last 90 days)."
)
assert result[0].team_id is None
def test_token_stale_90_days(self):
token_id = "tok_2"
token_name = "Stale Token"
active_at = datetime.now(timezone.utc) - timedelta(days=120)
days_inactive = (datetime.now(timezone.utc) - active_at).days
authentication_client = mock.MagicMock
authentication_client.tokens = {
token_id: VercelAuthToken(
id=token_id,
name=token_name,
active_at=datetime.now(timezone.utc) - timedelta(days=120),
active_at=active_at,
)
}
@@ -96,7 +103,11 @@ class Test_authentication_no_stale_tokens:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "FAIL"
assert "has not been used for" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) has not been used for {days_inactive} days (last active: {active_at.strftime('%Y-%m-%d %H:%M UTC')}). Threshold is 90 days."
)
assert result[0].team_id is None
def test_token_no_activity(self):
token_id = "tok_3"
@@ -130,4 +141,8 @@ class Test_authentication_no_stale_tokens:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "FAIL"
assert "no recorded activity" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) has no recorded activity and is considered stale."
)
assert result[0].team_id is None

View File

@@ -33,12 +33,13 @@ class Test_authentication_token_not_expired:
def test_token_not_expired(self):
token_id = "tok_1"
token_name = "My Token"
expires_at = datetime.now(timezone.utc) + timedelta(days=30)
authentication_client = mock.MagicMock
authentication_client.tokens = {
token_id: VercelAuthToken(
id=token_id,
name=token_name,
expires_at=datetime.now(timezone.utc) + timedelta(days=30),
expires_at=expires_at,
)
}
@@ -62,17 +63,22 @@ class Test_authentication_token_not_expired:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "PASS"
assert "is valid and expires" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) is valid and expires on {expires_at.strftime('%Y-%m-%d %H:%M UTC')}."
)
assert result[0].team_id is None
def test_token_expired(self):
token_id = "tok_2"
token_name = "Old Token"
expires_at = datetime.now(timezone.utc) - timedelta(days=1)
authentication_client = mock.MagicMock
authentication_client.tokens = {
token_id: VercelAuthToken(
id=token_id,
name=token_name,
expires_at=datetime.now(timezone.utc) - timedelta(days=1),
expires_at=expires_at,
)
}
@@ -96,7 +102,11 @@ class Test_authentication_token_not_expired:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "FAIL"
assert "has expired" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) has expired on {expires_at.strftime('%Y-%m-%d %H:%M UTC')}."
)
assert result[0].team_id is None
def test_token_no_expiration(self):
token_id = "tok_3"
@@ -130,4 +140,8 @@ class Test_authentication_token_not_expired:
assert result[0].resource_id == token_id
assert result[0].resource_name == token_name
assert result[0].status == "PASS"
assert "does not have an expiration" in result[0].status_extended
assert (
result[0].status_extended
== f"Token '{token_name}' ({token_id}) does not have an expiration date set and is currently valid."
)
assert result[0].team_id is None

View File

@@ -69,7 +69,11 @@ class Test_deployment_preview_not_publicly_accessible:
assert result[0].resource_id == DEPLOYMENT_ID
assert result[0].resource_name == "my-app-abc123"
assert result[0].status == "PASS"
assert "has deployment protection configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Preview deployment my-app-abc123 ({DEPLOYMENT_ID}) has deployment protection configured."
)
assert result[0].team_id == TEAM_ID
def test_preview_not_protected(self):
deployment_client = mock.MagicMock
@@ -106,9 +110,10 @@ class Test_deployment_preview_not_publicly_accessible:
assert result[0].resource_name == "my-app-abc123"
assert result[0].status == "FAIL"
assert (
"does not have deployment protection configured"
in result[0].status_extended
result[0].status_extended
== f"Preview deployment my-app-abc123 ({DEPLOYMENT_ID}) does not have deployment protection configured and is publicly accessible."
)
assert result[0].team_id == TEAM_ID
def test_production_deployment_skipped(self):
deployment_client = mock.MagicMock

View File

@@ -70,7 +70,11 @@ class Test_deployment_production_uses_stable_target:
assert result[0].resource_id == DEPLOYMENT_ID
assert result[0].resource_name == "my-app-abc123"
assert result[0].status == "PASS"
assert "stable branch" in result[0].status_extended
assert (
result[0].status_extended
== f"Production deployment my-app-abc123 ({DEPLOYMENT_ID}) is sourced from stable branch 'main'."
)
assert result[0].team_id == TEAM_ID
def test_non_stable_branch(self):
deployment_client = mock.MagicMock
@@ -107,7 +111,11 @@ class Test_deployment_production_uses_stable_target:
assert result[0].resource_id == DEPLOYMENT_ID
assert result[0].resource_name == "my-app-abc123"
assert result[0].status == "FAIL"
assert "instead of a" in result[0].status_extended
assert (
result[0].status_extended
== f"Production deployment my-app-abc123 ({DEPLOYMENT_ID}) is sourced from branch 'feature-xyz' instead of a configured stable branch (main, master)."
)
assert result[0].team_id == TEAM_ID
def test_non_production_skipped(self):
deployment_client = mock.MagicMock

View File

@@ -64,7 +64,11 @@ class Test_domain_dns_properly_configured:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "PASS"
assert "has DNS properly configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Domain {DOMAIN_NAME} has DNS properly configured."
)
assert result[0].team_id == TEAM_ID
def test_not_configured(self):
domain_client = mock.MagicMock
@@ -97,4 +101,8 @@ class Test_domain_dns_properly_configured:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "FAIL"
assert "does not have DNS properly configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Domain {DOMAIN_NAME} does not have DNS properly configured. The domain may not be resolving to Vercel's infrastructure."
)
assert result[0].team_id == TEAM_ID

View File

@@ -66,7 +66,11 @@ class Test_domain_no_wildcard_dns_exposure:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "PASS"
assert "no wildcard DNS records" in result[0].status_extended
assert (
result[0].status_extended
== f"Domain {DOMAIN_NAME} has no wildcard DNS records."
)
assert result[0].team_id == TEAM_ID
def test_has_wildcard_records(self):
domain_client = mock.MagicMock
@@ -105,4 +109,8 @@ class Test_domain_no_wildcard_dns_exposure:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "FAIL"
assert "wildcard DNS" in result[0].status_extended
assert (
result[0].status_extended
== f"Domain {DOMAIN_NAME} has 1 wildcard DNS record(s): *.example.com. This may expose unintended subdomains."
)
assert result[0].team_id == TEAM_ID

View File

@@ -64,8 +64,10 @@ class Test_domain_ssl_certificate_valid:
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "PASS"
assert (
"has a valid SSL certificate provisioned" in result[0].status_extended
result[0].status_extended
== f"Domain {DOMAIN_NAME} has a valid SSL certificate provisioned."
)
assert result[0].team_id == TEAM_ID
def test_ssl_missing(self):
domain_client = mock.MagicMock
@@ -100,6 +102,7 @@ class Test_domain_ssl_certificate_valid:
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "FAIL"
assert (
"does not have an SSL certificate provisioned"
in result[0].status_extended
result[0].status_extended
== f"Domain {DOMAIN_NAME} does not have an SSL certificate provisioned."
)
assert result[0].team_id == TEAM_ID

View File

@@ -64,7 +64,8 @@ class Test_domain_verified:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "PASS"
assert "is verified" in result[0].status_extended
assert result[0].status_extended == f"Domain {DOMAIN_NAME} is verified."
assert result[0].team_id == TEAM_ID
def test_not_verified(self):
domain_client = mock.MagicMock
@@ -97,4 +98,8 @@ class Test_domain_verified:
assert result[0].resource_id == DOMAIN_ID
assert result[0].resource_name == DOMAIN_NAME
assert result[0].status == "FAIL"
assert "is not verified" in result[0].status_extended
assert (
result[0].status_extended
== f"Domain {DOMAIN_NAME} is not verified. The domain may not be serving traffic correctly."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_project_auto_expose_system_env_disabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "does not automatically expose" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not automatically expose system environment variables to the build process."
)
assert result[0].team_id == TEAM_ID
def test_auto_expose_enabled(self):
project_client = mock.MagicMock
@@ -96,4 +100,8 @@ class Test_project_auto_expose_system_env_disabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "automatically exposes system" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} automatically exposes system environment variables to the build process."
)
assert result[0].team_id == TEAM_ID

View File

@@ -68,7 +68,11 @@ class Test_project_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "deployment protection enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has deployment protection enabled with level 'standard' on preview deployments."
)
assert result[0].team_id == TEAM_ID
def test_deployment_protection_disabled(self):
project_client = mock.MagicMock
@@ -103,7 +107,11 @@ class Test_project_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have deployment protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have deployment protection enabled on preview deployments."
)
assert result[0].team_id == TEAM_ID
def test_deployment_protection_none(self):
project_client = mock.MagicMock
@@ -136,3 +144,8 @@ class Test_project_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have deployment protection enabled on preview deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_project_directory_listing_disabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "has directory listing disabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has directory listing disabled."
)
assert result[0].team_id == TEAM_ID
def test_listing_enabled(self):
project_client = mock.MagicMock
@@ -96,4 +100,8 @@ class Test_project_directory_listing_disabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "has directory listing enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has directory listing enabled, which may expose the project's file structure to visitors."
)
assert result[0].team_id == TEAM_ID

View File

@@ -74,7 +74,11 @@ class Test_project_environment_no_overly_broad_target:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "no environment variables targeting" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has no environment variables targeting all three environments simultaneously."
)
assert result[0].team_id == TEAM_ID
def test_var_targets_all_envs(self):
project_client = mock.MagicMock
@@ -115,4 +119,8 @@ class Test_project_environment_no_overly_broad_target:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "targeting all three environments" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has 1 environment variable(s) targeting all three environments: SHARED_VAR."
)
assert result[0].team_id == TEAM_ID

View File

@@ -73,7 +73,11 @@ class Test_project_environment_no_secrets_in_plain_type:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "no secret-like environment variables" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has no secret-like environment variables stored as plain text."
)
assert result[0].team_id == TEAM_ID
def test_secret_key_plain(self):
project_client = mock.MagicMock
@@ -113,7 +117,11 @@ class Test_project_environment_no_secrets_in_plain_type:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "stored as plain text" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has 1 secret-like environment variable(s) stored as plain text: MY_API_KEY."
)
assert result[0].team_id == TEAM_ID
def test_non_secret_key_plain(self):
project_client = mock.MagicMock
@@ -153,4 +161,8 @@ class Test_project_environment_no_secrets_in_plain_type:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "no secret-like environment variables" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has no secret-like environment variables stored as plain text."
)
assert result[0].team_id == TEAM_ID

View File

@@ -74,7 +74,11 @@ class Test_project_environment_production_vars_not_in_preview:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "no sensitive production environment" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has no sensitive production environment variables leaking to preview deployments."
)
assert result[0].team_id == TEAM_ID
def test_prod_and_preview_secret(self):
project_client = mock.MagicMock
@@ -115,7 +119,11 @@ class Test_project_environment_production_vars_not_in_preview:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "also targeting preview" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has 1 sensitive production environment variable(s) also targeting preview: DB_PASSWORD."
)
assert result[0].team_id == TEAM_ID
def test_prod_and_preview_plain(self):
project_client = mock.MagicMock
@@ -156,4 +164,8 @@ class Test_project_environment_production_vars_not_in_preview:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "no sensitive production environment" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has no sensitive production environment variables leaking to preview deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -73,7 +73,11 @@ class Test_project_environment_sensitive_vars_encrypted:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "properly encrypted" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has all sensitive environment variables properly encrypted or uses no sensitive variables."
)
assert result[0].team_id == TEAM_ID
def test_sensitive_var_plain_text(self):
project_client = mock.MagicMock
@@ -113,8 +117,11 @@ class Test_project_environment_sensitive_vars_encrypted:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "plain text" in result[0].status_extended
assert "API_KEY" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has 1 sensitive environment variable(s) stored as plain text: API_KEY."
)
assert result[0].team_id == TEAM_ID
def test_no_sensitive_vars(self):
project_client = mock.MagicMock
@@ -154,4 +161,8 @@ class Test_project_environment_sensitive_vars_encrypted:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "properly encrypted" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has all sensitive environment variables properly encrypted or uses no sensitive variables."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_project_git_fork_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "has Git fork protection enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has Git fork protection enabled, preventing untrusted forks from accessing secrets."
)
assert result[0].team_id == TEAM_ID
def test_fork_protection_disabled(self):
project_client = mock.MagicMock
@@ -96,4 +100,8 @@ class Test_project_git_fork_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have Git fork protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have Git fork protection enabled, allowing forks to access environment variables and trigger deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_project_password_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "has password protection configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has password protection configured to restrict access to deployments."
)
assert result[0].team_id == TEAM_ID
def test_no_password_protection(self):
project_client = mock.MagicMock
@@ -96,4 +100,8 @@ class Test_project_password_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have password protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have password protection configured for deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -68,7 +68,11 @@ class Test_project_production_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "production deployment protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has production deployment protection enabled with level 'standard'."
)
assert result[0].team_id == TEAM_ID
def test_protection_none_level(self):
project_client = mock.MagicMock
@@ -103,7 +107,11 @@ class Test_project_production_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have deployment protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have deployment protection enabled on production deployments."
)
assert result[0].team_id == TEAM_ID
def test_protection_null(self):
project_client = mock.MagicMock
@@ -136,4 +144,8 @@ class Test_project_production_deployment_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have deployment protection" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have deployment protection enabled on production deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_project_skew_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "has skew protection enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} has skew protection enabled, ensuring consistent deployment versions during rollouts."
)
assert result[0].team_id == TEAM_ID
def test_skew_protection_disabled(self):
project_client = mock.MagicMock
@@ -96,4 +100,8 @@ class Test_project_skew_protection_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have skew protection enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} does not have skew protection enabled, which may cause version mismatches during deployments."
)
assert result[0].team_id == TEAM_ID

View File

@@ -67,7 +67,11 @@ class Test_security_custom_rules_configured:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "custom firewall rule(s) configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) has 1 custom firewall rule(s) configured."
)
assert result[0].team_id == TEAM_ID
def test_no_custom_rules(self):
security_client = mock.MagicMock
@@ -103,5 +107,7 @@ class Test_security_custom_rules_configured:
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert (
"does not have any custom firewall rules" in result[0].status_extended
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) does not have any custom firewall rules configured."
)
assert result[0].team_id == TEAM_ID

View File

@@ -67,7 +67,11 @@ class Test_security_ip_blocking_rules_configured:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "IP blocking rule(s) configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) has 1 IP blocking rule(s) configured."
)
assert result[0].team_id == TEAM_ID
def test_no_ip_rules(self):
security_client = mock.MagicMock
@@ -102,4 +106,8 @@ class Test_security_ip_blocking_rules_configured:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have any IP blocking rules" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) does not have any IP blocking rules configured."
)
assert result[0].team_id == TEAM_ID

View File

@@ -68,7 +68,11 @@ class Test_security_managed_rulesets_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "managed WAF rulesets enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) has managed WAF rulesets enabled."
)
assert result[0].team_id == TEAM_ID
def test_managed_rulesets_disabled(self):
security_client = mock.MagicMock
@@ -105,9 +109,10 @@ class Test_security_managed_rulesets_enabled:
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert (
"does not have managed WAF rulesets enabled"
in result[0].status_extended
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) does not have managed WAF rulesets enabled."
)
assert result[0].team_id == TEAM_ID
def test_managed_rulesets_plan_gated(self):
security_client = mock.MagicMock
@@ -143,5 +148,8 @@ class Test_security_managed_rulesets_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "MANUAL"
assert "could not be assessed" in result[0].status_extended
assert "Enterprise plan" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) could not be assessed for managed rulesets. Enterprise plan required to access this feature."
)
assert result[0].team_id == TEAM_ID

View File

@@ -67,7 +67,11 @@ class Test_security_rate_limiting_configured:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "rate limiting rule(s) configured" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) has 1 rate limiting rule(s) configured."
)
assert result[0].team_id == TEAM_ID
def test_no_rate_limiting(self):
security_client = mock.MagicMock
@@ -102,4 +106,8 @@ class Test_security_rate_limiting_configured:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert "does not have any rate limiting rules" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) does not have any rate limiting rules configured."
)
assert result[0].team_id == TEAM_ID

View File

@@ -67,7 +67,11 @@ class Test_security_waf_enabled:
assert result[0].resource_id == PROJECT_ID
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "PASS"
assert "Web Application Firewall enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) has the Web Application Firewall enabled."
)
assert result[0].team_id == TEAM_ID
def test_waf_disabled(self):
security_client = mock.MagicMock
@@ -103,6 +107,7 @@ class Test_security_waf_enabled:
assert result[0].resource_name == PROJECT_NAME
assert result[0].status == "FAIL"
assert (
"does not have the Web Application Firewall enabled"
in result[0].status_extended
result[0].status_extended
== f"Project {PROJECT_NAME} ({PROJECT_ID}) does not have the Web Application Firewall enabled."
)
assert result[0].team_id == TEAM_ID

View File

@@ -63,7 +63,11 @@ class Test_team_directory_sync_enabled:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "has directory sync (SCIM) enabled" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has directory sync (SCIM) enabled for automated user provisioning."
)
assert result[0].team_id == ""
def test_directory_sync_disabled(self):
team_client = mock.MagicMock
@@ -97,6 +101,7 @@ class Test_team_directory_sync_enabled:
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert (
"does not have directory sync (SCIM) enabled"
in result[0].status_extended
result[0].status_extended
== f"Team {TEAM_NAME} does not have directory sync (SCIM) enabled. User provisioning and deprovisioning must be managed manually."
)
assert result[0].team_id == ""

View File

@@ -75,7 +75,11 @@ class Test_team_member_no_stale_access:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "no members with access older" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has no members with access older than 90 days requiring review."
)
assert result[0].team_id == ""
def test_stale_member(self):
team_client = mock.MagicMock
@@ -116,7 +120,11 @@ class Test_team_member_no_stale_access:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert "joined more than" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has 1 member(s) who joined more than 90 days ago and may require an access review."
)
assert result[0].team_id == ""
def test_non_active_member_skipped(self):
team_client = mock.MagicMock
@@ -157,4 +165,8 @@ class Test_team_member_no_stale_access:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "no members with access older" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has no members with access older than 90 days requiring review."
)
assert result[0].team_id == ""

View File

@@ -75,7 +75,11 @@ class Test_team_member_role_least_privilege:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "within the recommended 20% threshold" in result[0].status_extended
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."
)
assert result[0].team_id == ""
def test_member_owner_role(self):
team_client = mock.MagicMock
@@ -116,4 +120,8 @@ class Test_team_member_role_least_privilege:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert "exceeds the recommended 20% threshold" in result[0].status_extended
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."
)
assert result[0].team_id == ""

View File

@@ -75,7 +75,11 @@ class Test_team_no_stale_invitations:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "no stale pending invitations" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has no stale pending invitations older than 30 days."
)
assert result[0].team_id == ""
def test_stale_invitation(self):
team_client = mock.MagicMock
@@ -116,5 +120,8 @@ class Test_team_no_stale_invitations:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert "stale" in result[0].status_extended
assert "pending invitation(s)" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has 1 stale pending invitation(s) older than 30 days."
)
assert result[0].team_id == ""

View File

@@ -64,7 +64,10 @@ class Test_team_saml_sso_enabled:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert f"Team {TEAM_NAME} has SAML SSO enabled" in result[0].status_extended
assert (
result[0].status_extended == f"Team {TEAM_NAME} has SAML SSO enabled."
)
assert result[0].team_id == ""
def test_saml_disabled(self):
team_client = mock.MagicMock
@@ -99,6 +102,7 @@ class Test_team_saml_sso_enabled:
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert (
f"Team {TEAM_NAME} does not have SAML SSO enabled"
in result[0].status_extended
result[0].status_extended
== f"Team {TEAM_NAME} does not have SAML SSO enabled."
)
assert result[0].team_id == ""

View File

@@ -63,7 +63,11 @@ class Test_team_saml_sso_enforced:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "PASS"
assert "enforces SAML SSO" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} enforces SAML SSO for all members."
)
assert result[0].team_id == ""
def test_saml_enabled_not_enforced(self):
team_client = mock.MagicMock
@@ -96,7 +100,11 @@ class Test_team_saml_sso_enforced:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert "does not enforce it" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} has SAML SSO enabled but does not enforce it. Members can still authenticate without SSO."
)
assert result[0].team_id == ""
def test_saml_disabled(self):
team_client = mock.MagicMock
@@ -129,4 +137,8 @@ class Test_team_saml_sso_enforced:
assert result[0].resource_id == TEAM_ID
assert result[0].resource_name == TEAM_NAME
assert result[0].status == "FAIL"
assert "does not have SAML SSO enforced" in result[0].status_extended
assert (
result[0].status_extended
== f"Team {TEAM_NAME} does not have SAML SSO enforced."
)
assert result[0].team_id == ""