fix(codebuild): enhance service functions (#4319)

Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
This commit is contained in:
Sergio Garcia
2024-06-26 11:27:50 -04:00
committed by GitHub
parent cf84875355
commit ff5c41f363
6 changed files with 129 additions and 83 deletions

View File

@@ -7,7 +7,7 @@ from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_
class codebuild_project_older_90_days(Check):
def execute(self):
findings = []
for project in codebuild_client.projects:
for project in codebuild_client.projects.values():
report = Check_Report_AWS(self.metadata())
report.region = project.region
report.resource_id = project.name

View File

@@ -7,7 +7,7 @@ from prowler.providers.aws.services.codebuild.codebuild_client import codebuild_
class codebuild_project_user_controlled_buildspec(Check):
def execute(self):
findings = []
for project in codebuild_client.projects:
for project in codebuild_client.projects.values():
report = Check_Report_AWS(self.metadata())
report.region = project.region
report.resource_id = project.name

View File

@@ -1,7 +1,8 @@
import datetime
from dataclasses import dataclass
from typing import Optional
from pydantic import BaseModel
from prowler.lib.logger import logger
from prowler.lib.scan_filters.scan_filters import is_resource_filtered
from prowler.providers.aws.lib.service.service import AWSService
@@ -12,12 +13,14 @@ class Codebuild(AWSService):
def __init__(self, provider):
# Call AWSService's __init__
super().__init__(__class__.__name__, provider)
self.projects = []
self.projects = {}
self.__threading_call__(self.__list_projects__)
self.__list_builds_for_project__()
self.__threading_call__(self.__list_builds_for_project__)
self.__threading_call__(self.__batch_get_builds__)
self.__threading_call__(self.__batch_get_projects__)
def __list_projects__(self, regional_client):
logger.info("Codebuild - listing projects")
logger.info("Codebuild - Listing projects...")
try:
list_projects_paginator = regional_client.get_paginator("list_projects")
for page in list_projects_paginator.paginate():
@@ -26,14 +29,10 @@ class Codebuild(AWSService):
if not self.audit_resources or (
is_resource_filtered(project_arn, self.audit_resources)
):
self.projects.append(
Project(
name=project,
arn=project_arn,
region=regional_client.region,
last_invoked_time=None,
buildspec=None,
)
self.projects[project_arn] = Project(
name=project,
arn=project_arn,
region=regional_client.region,
)
except Exception as error:
@@ -41,38 +40,78 @@ class Codebuild(AWSService):
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def __list_builds_for_project__(self):
logger.info("Codebuild - listing builds from projects")
def __list_builds_for_project__(self, regional_client):
logger.info("Codebuild - Listing builds...")
try:
for project in self.projects:
for region, client in self.regional_clients.items():
if project.region == region:
ids = client.list_builds_for_project(projectName=project.name)
if "ids" in ids:
if len(ids["ids"]) > 0:
builds = client.batch_get_builds(ids=[ids["ids"][0]])
if "builds" in builds:
if "endTime" in builds["builds"][0]:
project.last_invoked_time = builds["builds"][0][
"endTime"
]
for project in self.projects.values():
if project.region == regional_client.region:
try:
build_ids = regional_client.list_builds_for_project(
projectName=project.name
).get("ids", [])
if len(build_ids) > 0:
project.last_build = Build(id=build_ids[0])
except Exception as error:
logger.error(
f"{regional_client.region}: {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
projects = client.batch_get_projects(names=[project.name])[
"projects"
][0]["source"]
if "buildspec" in projects:
project.buildspec = projects["buildspec"]
def __batch_get_builds__(self, regional_client):
logger.info("Codebuild - Getting builds...")
try:
for project in self.projects.values():
if (
project.region == regional_client.region
and project.last_build
and project.last_build.id
):
try:
builds_by_id = regional_client.batch_get_builds(
ids=[project.last_build.id]
).get("builds", [])
if len(builds_by_id) > 0:
project.last_invoked_time = builds_by_id[0].get("endTime")
except Exception as error:
logger.error(
f"{regional_client.region}: {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def __batch_get_projects__(self, regional_client):
logger.info("Codebuild - Getting projects...")
try:
for project in self.projects.values():
if project.region == regional_client.region:
try:
project_source = regional_client.batch_get_projects(
names=[project.name]
)["projects"][0]["source"]
project.buildspec = project_source.get("buildspec", "")
except Exception as error:
logger.error(
f"{regional_client.region}: {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
@dataclass
class Project:
class Build(BaseModel):
id: str
class Project(BaseModel):
name: str
arn: str
region: str
last_build: Optional[Build]
last_invoked_time: Optional[datetime.datetime]
buildspec: Optional[str]

View File

@@ -13,15 +13,16 @@ class Test_codebuild_project_older_90_days:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=datetime.now(timezone.utc) - timedelta(days=100),
buildspec=None,
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,
@@ -47,15 +48,16 @@ class Test_codebuild_project_older_90_days:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=None,
buildspec=None,
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,
@@ -79,15 +81,16 @@ class Test_codebuild_project_older_90_days:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=datetime.now(timezone.utc) - timedelta(days=10),
buildspec=None,
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,

View File

@@ -12,15 +12,15 @@ class Test_codebuild_project_user_controlled_buildspec:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=None,
buildspec=None,
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,
@@ -47,15 +47,16 @@ class Test_codebuild_project_user_controlled_buildspec:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=None,
buildspec="arn:aws:s3:::my-codebuild-sample2/buildspec.out",
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,
@@ -82,15 +83,15 @@ class Test_codebuild_project_user_controlled_buildspec:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=None,
buildspec="arn:aws:s3:::my-codebuild-sample2/buildspec.yaml",
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,
@@ -116,15 +117,15 @@ class Test_codebuild_project_user_controlled_buildspec:
codebuild_client = mock.MagicMock
project_name = "test-project"
project_arn = f"arn:aws:codebuild:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
codebuild_client.projects = [
Project(
codebuild_client.projects = {
project_arn: Project(
name=project_name,
arn=project_arn,
region="eu-west-1",
last_invoked_time=None,
buildspec="arn:aws:s3:::my-codebuild-sample2/buildspecyaml",
)
]
}
with mock.patch(
"prowler.providers.aws.services.codebuild.codebuild_service.Codebuild",
codebuild_client,

View File

@@ -3,22 +3,34 @@ from unittest.mock import patch
import botocore
from prowler.providers.aws.services.codebuild.codebuild_service import Codebuild
from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider
from prowler.providers.aws.services.codebuild.codebuild_service import (
Build,
Codebuild,
Project,
)
from tests.providers.aws.utils import (
AWS_ACCOUNT_NUMBER,
AWS_COMMERCIAL_PARTITION,
AWS_REGION_EU_WEST_1,
set_mocked_aws_provider,
)
# last time invoked time
project_name = "test"
project_arn = f"arn:{AWS_COMMERCIAL_PARTITION}:codebuild:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:project/{project_name}"
build_spec_project_arn = "arn:aws:s3:::my-codebuild-sample2/buildspec.yml"
buildspec_type = "S3"
build_id = "test:93f838a7-cd20-48ae-90e5-c10fbbc78ca6"
last_invoked_time = datetime.now() - timedelta(days=2)
# Mocking batch_get_projects
make_api_call = botocore.client.BaseClient._make_api_call
def mock_make_api_call(self, operation_name, kwarg):
if operation_name == "ListProjects":
return {"projects": ["test"]}
return {"projects": [project_name]}
if operation_name == "ListBuildsForProject":
return {"ids": ["test:93f838a7-cd20-48ae-90e5-c10fbbc78ca6"]}
return {"ids": [build_id]}
if operation_name == "BatchGetBuilds":
return {"builds": [{"endTime": last_invoked_time}]}
if operation_name == "BatchGetProjects":
@@ -26,7 +38,8 @@ def mock_make_api_call(self, operation_name, kwarg):
"projects": [
{
"source": {
"buildspec": "arn:aws:s3:::my-codebuild-sample2/buildspec.yml"
"type": buildspec_type,
"buildspec": build_spec_project_arn,
}
}
]
@@ -50,28 +63,18 @@ def mock_generate_regional_clients(provider, service):
)
class Test_Codebuild_Service:
# Test Codebuild Session
def test__get_session__(self):
def test_codebuild_service(self):
codebuild = Codebuild(set_mocked_aws_provider())
assert codebuild.session.__class__.__name__ == "Session"
# Test Codebuild Service
def test__get_service__(self):
codebuild = Codebuild(set_mocked_aws_provider())
assert codebuild.session.__class__.__name__ == "Session"
assert codebuild.service == "codebuild"
def test__list_projects__(self):
codebuild = Codebuild(set_mocked_aws_provider())
assert len(codebuild.projects) == 1
assert codebuild.projects[0].name == "test"
assert codebuild.projects[0].region == AWS_REGION_EU_WEST_1
def test__list_builds_for_project__(self):
codebuild = Codebuild(set_mocked_aws_provider())
assert len(codebuild.projects) == 1
assert codebuild.projects[0].name == "test"
assert codebuild.projects[0].region == AWS_REGION_EU_WEST_1
assert codebuild.projects[0].last_invoked_time == last_invoked_time
assert (
codebuild.projects[0].buildspec
== "arn:aws:s3:::my-codebuild-sample2/buildspec.yml"
)
assert isinstance(codebuild.projects, dict)
assert isinstance(codebuild.projects[project_arn], Project)
assert codebuild.projects[project_arn].name == project_name
assert codebuild.projects[project_arn].arn == project_arn
assert codebuild.projects[project_arn].region == AWS_REGION_EU_WEST_1
assert codebuild.projects[project_arn].last_invoked_time == last_invoked_time
assert codebuild.projects[project_arn].last_build == Build(id=build_id)
assert codebuild.projects[project_arn].buildspec == build_spec_project_arn