mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(codebuild): codebuild service and checks (#1467)
This commit is contained in:
0
providers/aws/services/codebuild/__init__.py
Normal file
0
providers/aws/services/codebuild/__init__.py
Normal file
@@ -1,63 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
# use this file except in compliance with the License. You may obtain a copy
|
|
||||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
CHECK_ID_extra7174="7.174"
|
|
||||||
CHECK_TITLE_extra7174="[extra7174] CodeBuild Project last invoked greater than 90 days"
|
|
||||||
CHECK_SCORED_extra7174="NOT_SCORED"
|
|
||||||
CHECK_CIS_LEVEL_extra7174="EXTRA"
|
|
||||||
CHECK_SEVERITY_extra7174="High"
|
|
||||||
CHECK_ASFF_TYPE_extra7174="AwsCodebuildProject"
|
|
||||||
CHECK_ALTERNATE_check7174="extra7174"
|
|
||||||
CHECK_SERVICENAME_extra7174="codebuild"
|
|
||||||
CHECK_RISK_extra7174='Older CodeBuild projects can be checked to see if they are currently in use'
|
|
||||||
CHECK_REMEDIATION_extra7174='Check if CodeBuild project are really in use and remove the stale ones'
|
|
||||||
CHECK_DOC_extra7174='https://docs.aws.amazon.com/codebuild/latest/userguide/delete-project.html'
|
|
||||||
CHECK_CAF_EPIC_extra7174='Infrastructure Security'
|
|
||||||
|
|
||||||
extra7174(){
|
|
||||||
# "Looking for all build projects with last build invocation greater then 90 days in all regions"
|
|
||||||
for regx in ${REGIONS}; do
|
|
||||||
LIST_OF_PROJECTS=$("${AWSCLI}" codebuild list-projects ${PROFILE_OPT} --region "${regx}" --query 'projects[*]' --output text 2>&1)
|
|
||||||
if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${LIST_OF_PROJECTS}"; then
|
|
||||||
textInfo "${regx}: Access Denied trying to list Codebuild projects" "${regx}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ "${LIST_OF_PROJECTS}" ]]; then
|
|
||||||
for project in ${LIST_OF_PROJECTS}; do
|
|
||||||
project_id=$("${AWSCLI}" codebuild list-builds-for-project ${PROFILE_OPT} --project-name "${project}" --query 'ids[0]' --region "${regx}" --output text | head -n 1 2>&1)
|
|
||||||
if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${project_id}"; then
|
|
||||||
textInfo "${regx}: Access Denied trying to fetch Id for Codebuild project" "${regx}" "${project}"
|
|
||||||
continue
|
|
||||||
elif grep -q -E 'None' <<< "${project_id}"; then
|
|
||||||
textInfo "${regx}: Codebuild project ${project} has been never build" "${regx}" "${project}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
last_invoked_time=$("${AWSCLI}" codebuild batch-get-builds ${PROFILE_OPT} --ids "${project_id}" --region "${regx}" --query 'builds[0].endTime' --output text 2>&1)
|
|
||||||
if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${last_invoked_time}"; then
|
|
||||||
textInfo "${regx}: Access Denied trying to get build details for Codebuild project ID" "${regx}" "${project}"
|
|
||||||
elif grep -q -E 'None' <<< "${last_invoked_time}"; then
|
|
||||||
textInfo "${regx}: Codebuild project ${project} has been never build" "${regx}" "${project}"
|
|
||||||
else
|
|
||||||
HOWOLDER=$(how_older_from_today "${last_invoked_time}")
|
|
||||||
if [ "${HOWOLDER}" -ge 90 ]; then
|
|
||||||
textFail "${regx}: CodeBuild project ${project} was last invoked greater then 90 days" "${regx}" "${project}"
|
|
||||||
else
|
|
||||||
textPass "${regx}: Codebuild project ${project} was last invoked in the past 90 days" "${regx}" "${project}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
textInfo "${regx}: No CodeBuild Projects found" "${regx}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
# use this file except in compliance with the License. You may obtain a copy
|
|
||||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software distributed
|
|
||||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations under the License.
|
|
||||||
|
|
||||||
CHECK_ID_extra7175="7.175"
|
|
||||||
CHECK_TITLE_extra7175="[extra7175] CodeBuild Project with an user controlled buildspec"
|
|
||||||
CHECK_SCORED_extra7175="NOT_SCORED"
|
|
||||||
CHECK_CIS_LEVEL_extra7175="EXTRA"
|
|
||||||
CHECK_SEVERITY_extra7175="High"
|
|
||||||
CHECK_ASFF_TYPE_extra7175="AwsCodebuildProject"
|
|
||||||
CHECK_ALTERNATE_check7175="extra7175"
|
|
||||||
CHECK_SERVICENAME_extra7175="codebuild"
|
|
||||||
CHECK_RISK_extra7175='The CodeBuild projects with user controlled buildspec'
|
|
||||||
CHECK_REMEDIATION_extra7175='Use buildspec.yml from a trusted source which user cant interfere with'
|
|
||||||
CHECK_DOC_extra7175='https://docs.aws.amazon.com/codebuild/latest/userguide/security.html'
|
|
||||||
CHECK_CAF_EPIC_extra7175='Infrastructure Security'
|
|
||||||
|
|
||||||
extra7175(){
|
|
||||||
# "Looking for all build projects with user controlled buildspec files"
|
|
||||||
for regx in ${REGIONS}; do
|
|
||||||
LIST_OF_PROJECTS=$("${AWSCLI}" codebuild list-projects ${PROFILE_OPT} --region "${regx}" --query 'projects[*]' --output text 2>&1)
|
|
||||||
if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${LIST_OF_PROJECTS}"; then
|
|
||||||
textInfo "${regx}: Access Denied trying to list Codebuild projects" "${regx}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ "${LIST_OF_PROJECTS}" ]]; then
|
|
||||||
for project in ${LIST_OF_PROJECTS}; do
|
|
||||||
buildspec_file=$("${AWSCLI}" codebuild batch-get-projects ${PROFILE_OPT} --name "${project}" --query 'projects[0].source.buildspec' --region "${regx}" --output text 2>&1)
|
|
||||||
if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "${buildspec_file}"; then
|
|
||||||
textInfo "${regx}: Access Denied trying to fetch Id for Codebuild project" "${regx}" "${project}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ $buildspec_file == *.yml ]];then
|
|
||||||
textFail "${regx}: Codebuild project ${project} uses a user controlled buildspec" "${regx}" "${project}"
|
|
||||||
else
|
|
||||||
textPass "${regx}: Codebuild project ${project} not uses a user controlled buildspec" "${regx}" "${project}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
textInfo "${regx}: No CodeBuild Projects found" "${regx}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
4
providers/aws/services/codebuild/codebuild_client.py
Normal file
4
providers/aws/services/codebuild/codebuild_client.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||||
|
from providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||||
|
|
||||||
|
codebuild_client = Codebuild(current_audit_info)
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Provider": "aws",
|
||||||
|
"CheckID": "codebuild_project_older_90_days",
|
||||||
|
"CheckTitle": "Ensure CodeBuild Project has been invoked in the last 90 days",
|
||||||
|
"CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards"],
|
||||||
|
"ServiceName": "codebuild",
|
||||||
|
"SubServiceName": "",
|
||||||
|
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||||
|
"Severity": "medium",
|
||||||
|
"ResourceType": "AwsCodeBuildProject",
|
||||||
|
"Description": "Ensure CodeBuild Project has been invoked in the last 90 days",
|
||||||
|
"Risk": "Older CodeBuild projects can be checked to see if they are currently in use.",
|
||||||
|
"RelatedUrl": "",
|
||||||
|
"Remediation": {
|
||||||
|
"Code": {
|
||||||
|
"CLI": "",
|
||||||
|
"NativeIaC": "",
|
||||||
|
"Other": "",
|
||||||
|
"Terraform": ""
|
||||||
|
},
|
||||||
|
"Recommendation": {
|
||||||
|
"Text": "Check if CodeBuild project are really in use and remove the stale ones",
|
||||||
|
"Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/delete-project.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Categories": [],
|
||||||
|
"Tags": {
|
||||||
|
"Tag1Key": "value",
|
||||||
|
"Tag2Key": "value"
|
||||||
|
},
|
||||||
|
"DependsOn": [],
|
||||||
|
"RelatedTo": [],
|
||||||
|
"Notes": "",
|
||||||
|
"Compliance": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from lib.check.models import Check, Check_Report
|
||||||
|
from providers.aws.services.codebuild.codebuild_client import codebuild_client
|
||||||
|
|
||||||
|
|
||||||
|
class codebuild_project_older_90_days(Check):
|
||||||
|
def execute(self):
|
||||||
|
findings = []
|
||||||
|
for project in codebuild_client.projects:
|
||||||
|
report = Check_Report(self.metadata)
|
||||||
|
report.region = project.region
|
||||||
|
report.resource_id = project.name
|
||||||
|
report.resource_arn = ""
|
||||||
|
report.status = "PASS"
|
||||||
|
report.status_extended = (
|
||||||
|
f"CodeBuild project {project.name} has been invoked in the last 90 days"
|
||||||
|
)
|
||||||
|
if project.last_invoked_time:
|
||||||
|
if (datetime.now(timezone.utc) - project.last_invoked_time).days > 90:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"CodeBuild project {project.name} has not been invoked in the last 90 days"
|
||||||
|
else:
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = (
|
||||||
|
f"CodeBuild project {project.name} has never been built"
|
||||||
|
)
|
||||||
|
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
|
return findings
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from re import search
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from providers.aws.services.codebuild.codebuild_service import CodebuildProject
|
||||||
|
|
||||||
|
|
||||||
|
class Test_codebuild_project_older_90_days:
|
||||||
|
def test_project_not_built_in_last_90_days(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test",
|
||||||
|
region="eu-west-1",
|
||||||
|
last_invoked_time=datetime.now(timezone.utc) - timedelta(days=100),
|
||||||
|
buildspec=None,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_older_90_days.codebuild_project_older_90_days import (
|
||||||
|
codebuild_project_older_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_older_90_days()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "FAIL"
|
||||||
|
assert search(
|
||||||
|
"has not been invoked in the last 90 days", result[0].status_extended
|
||||||
|
)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
|
|
||||||
|
def test_project_not_built(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test", region="eu-west-1", last_invoked_time=None, buildspec=None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_older_90_days.codebuild_project_older_90_days import (
|
||||||
|
codebuild_project_older_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_older_90_days()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "FAIL"
|
||||||
|
assert search("has never been built", result[0].status_extended)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
|
|
||||||
|
def test_project_built_in_last_90_days(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test",
|
||||||
|
region="eu-west-1",
|
||||||
|
last_invoked_time=datetime.now(timezone.utc) - timedelta(days=10),
|
||||||
|
buildspec=None,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_older_90_days.codebuild_project_older_90_days import (
|
||||||
|
codebuild_project_older_90_days,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_older_90_days()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "PASS"
|
||||||
|
assert search(
|
||||||
|
"has been invoked in the last 90 days", result[0].status_extended
|
||||||
|
)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Provider": "aws",
|
||||||
|
"CheckID": "codebuild_project_user_controlled_buildspec",
|
||||||
|
"CheckTitle": "Ensure CodeBuild Project uses a controlled buildspec",
|
||||||
|
"CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards"],
|
||||||
|
"ServiceName": "codebuild",
|
||||||
|
"SubServiceName": "",
|
||||||
|
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
|
||||||
|
"Severity": "medium",
|
||||||
|
"ResourceType": "AwsCodeBuildProject",
|
||||||
|
"Description": "Ensure CodeBuild Project uses a controlled buildspec",
|
||||||
|
"Risk": "The CodeBuild projects with user controlled buildspec",
|
||||||
|
"RelatedUrl": "",
|
||||||
|
"Remediation": {
|
||||||
|
"Code": {
|
||||||
|
"CLI": "",
|
||||||
|
"NativeIaC": "",
|
||||||
|
"Other": "",
|
||||||
|
"Terraform": ""
|
||||||
|
},
|
||||||
|
"Recommendation": {
|
||||||
|
"Text": "Use buildspec.yml from a trusted source which user cant interfere with",
|
||||||
|
"Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/security.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Categories": [],
|
||||||
|
"Tags": {
|
||||||
|
"Tag1Key": "value",
|
||||||
|
"Tag2Key": "value"
|
||||||
|
},
|
||||||
|
"DependsOn": [],
|
||||||
|
"RelatedTo": [],
|
||||||
|
"Notes": "",
|
||||||
|
"Compliance": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
from re import search
|
||||||
|
|
||||||
|
from lib.check.models import Check, Check_Report
|
||||||
|
from providers.aws.services.codebuild.codebuild_client import codebuild_client
|
||||||
|
|
||||||
|
|
||||||
|
class codebuild_project_user_controlled_buildspec(Check):
|
||||||
|
def execute(self):
|
||||||
|
findings = []
|
||||||
|
for project in codebuild_client.projects:
|
||||||
|
report = Check_Report(self.metadata)
|
||||||
|
report.region = project.region
|
||||||
|
report.resource_id = project.name
|
||||||
|
report.resource_arn = ""
|
||||||
|
report.status = "FAIL"
|
||||||
|
report.status_extended = f"CodeBuild project {project.name} does not use a user controlled buildspec"
|
||||||
|
if project.buildspec:
|
||||||
|
if search(".*\.yaml$", project.buildspec) or search(
|
||||||
|
".*\.yml$", project.buildspec
|
||||||
|
):
|
||||||
|
report.status = "PASS"
|
||||||
|
report.status_extended = f"CodeBuild project {project.name} uses a user controlled buildspec"
|
||||||
|
|
||||||
|
findings.append(report)
|
||||||
|
|
||||||
|
return findings
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
from re import search
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from providers.aws.services.codebuild.codebuild_service import CodebuildProject
|
||||||
|
|
||||||
|
|
||||||
|
class Test_codebuild_project_user_controlled_buildspec:
|
||||||
|
def test_project_not_buildspec(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test", region="eu-west-1", last_invoked_time=None, buildspec=None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_user_controlled_buildspec.codebuild_project_user_controlled_buildspec import (
|
||||||
|
codebuild_project_user_controlled_buildspec,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_user_controlled_buildspec()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "FAIL"
|
||||||
|
assert search(
|
||||||
|
"does not use a user controlled buildspec", result[0].status_extended
|
||||||
|
)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
|
|
||||||
|
def test_project_buildspec_not_yaml(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test",
|
||||||
|
region="eu-west-1",
|
||||||
|
last_invoked_time=None,
|
||||||
|
buildspec="arn:aws:s3:::my-codebuild-sample2/buildspec.out",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_user_controlled_buildspec.codebuild_project_user_controlled_buildspec import (
|
||||||
|
codebuild_project_user_controlled_buildspec,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_user_controlled_buildspec()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "FAIL"
|
||||||
|
assert search(
|
||||||
|
"does not use a user controlled buildspec", result[0].status_extended
|
||||||
|
)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
|
|
||||||
|
def test_project_valid_buildspec(self):
|
||||||
|
codebuild_client = mock.MagicMock
|
||||||
|
codebuild_client.projects = [
|
||||||
|
CodebuildProject(
|
||||||
|
name="test",
|
||||||
|
region="eu-west-1",
|
||||||
|
last_invoked_time=None,
|
||||||
|
buildspec="arn:aws:s3:::my-codebuild-sample2/buildspec.yaml",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
with mock.patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.Codebuild",
|
||||||
|
codebuild_client,
|
||||||
|
):
|
||||||
|
from providers.aws.services.codebuild.codebuild_project_user_controlled_buildspec.codebuild_project_user_controlled_buildspec import (
|
||||||
|
codebuild_project_user_controlled_buildspec,
|
||||||
|
)
|
||||||
|
|
||||||
|
check = codebuild_project_user_controlled_buildspec()
|
||||||
|
result = check.execute()
|
||||||
|
|
||||||
|
assert len(result) == 1
|
||||||
|
assert result[0].status == "PASS"
|
||||||
|
assert search("uses a user controlled buildspec", result[0].status_extended)
|
||||||
|
assert result[0].resource_id == "test"
|
||||||
|
assert result[0].resource_arn == ""
|
||||||
85
providers/aws/services/codebuild/codebuild_service.py
Normal file
85
providers/aws/services/codebuild/codebuild_service.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import datetime
|
||||||
|
import threading
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from lib.logger import logger
|
||||||
|
from providers.aws.aws_provider import generate_regional_clients
|
||||||
|
|
||||||
|
|
||||||
|
################### Codebuild
|
||||||
|
class Codebuild:
|
||||||
|
def __init__(self, audit_info):
|
||||||
|
self.service = "codebuild"
|
||||||
|
self.session = audit_info.audit_session
|
||||||
|
self.audited_account = audit_info.audited_account
|
||||||
|
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
||||||
|
self.projects = []
|
||||||
|
self.__threading_call__(self.__list_projects__)
|
||||||
|
self.__list_builds_for_project__()
|
||||||
|
|
||||||
|
def __get_session__(self):
|
||||||
|
return self.session
|
||||||
|
|
||||||
|
def __threading_call__(self, call):
|
||||||
|
threads = []
|
||||||
|
for regional_client in self.regional_clients.values():
|
||||||
|
threads.append(threading.Thread(target=call, args=(regional_client,)))
|
||||||
|
for t in threads:
|
||||||
|
t.start()
|
||||||
|
for t in threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
def __list_projects__(self, regional_client):
|
||||||
|
logger.info("Codebuild - listing projects")
|
||||||
|
try:
|
||||||
|
list_projects_paginator = regional_client.get_paginator("list_projects")
|
||||||
|
for page in list_projects_paginator.paginate():
|
||||||
|
for project in page["projects"]:
|
||||||
|
self.projects.append(
|
||||||
|
CodebuildProject(
|
||||||
|
name=project,
|
||||||
|
region=regional_client.region,
|
||||||
|
last_invoked_time=None,
|
||||||
|
buildspec=None,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(
|
||||||
|
f"{regional_client.region} -- {error.__class__.__name__}: {error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __list_builds_for_project__(self):
|
||||||
|
logger.info("Codebuild - listing builds from projects")
|
||||||
|
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:
|
||||||
|
builds = client.batch_get_builds(ids=[ids["ids"][0]])
|
||||||
|
if "builds" in builds:
|
||||||
|
project.last_invoked_time = builds["builds"][0][
|
||||||
|
"endTime"
|
||||||
|
]
|
||||||
|
|
||||||
|
project.buildspec = client.batch_get_projects(
|
||||||
|
names=[project.name]
|
||||||
|
)["projects"][0]["source"]["buildspec"]
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
logger.error(f"{client.region} -- {error.__class__.__name__}: {error}")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CodebuildProject:
|
||||||
|
name: str
|
||||||
|
region: str
|
||||||
|
last_invoked_time: datetime
|
||||||
|
buildspec: str
|
||||||
|
|
||||||
|
def __init__(self, name, region, last_invoked_time, buildspec):
|
||||||
|
self.name = name
|
||||||
|
self.region = region
|
||||||
|
self.last_invoked_time = last_invoked_time
|
||||||
|
self.buildspec = buildspec
|
||||||
101
providers/aws/services/codebuild/codebuild_service_test.py
Normal file
101
providers/aws/services/codebuild/codebuild_service_test.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import botocore
|
||||||
|
from boto3 import session
|
||||||
|
|
||||||
|
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||||
|
from providers.aws.lib.audit_info.models import AWS_Audit_Info
|
||||||
|
from providers.aws.services.codebuild.codebuild_service import Codebuild
|
||||||
|
|
||||||
|
# Mock Test Region
|
||||||
|
AWS_REGION = "eu-west-1"
|
||||||
|
AWS_ACCOUNT_NUMBER = 123456789012
|
||||||
|
|
||||||
|
# last time invoked time
|
||||||
|
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"]}
|
||||||
|
if operation_name == "ListBuildsForProject":
|
||||||
|
return {"ids": ["test:93f838a7-cd20-48ae-90e5-c10fbbc78ca6"]}
|
||||||
|
if operation_name == "BatchGetBuilds":
|
||||||
|
return {"builds": [{"endTime": last_invoked_time}]}
|
||||||
|
if operation_name == "BatchGetProjects":
|
||||||
|
return {
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"source": {
|
||||||
|
"buildspec": "arn:aws:s3:::my-codebuild-sample2/buildspec.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return make_api_call(self, operation_name, kwarg)
|
||||||
|
|
||||||
|
|
||||||
|
# Mock generate_regional_clients()
|
||||||
|
def mock_generate_regional_clients(service, audit_info):
|
||||||
|
regional_client = audit_info.audit_session.client(service, region_name=AWS_REGION)
|
||||||
|
regional_client.region = AWS_REGION
|
||||||
|
return {AWS_REGION: regional_client}
|
||||||
|
|
||||||
|
|
||||||
|
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||||
|
@patch(
|
||||||
|
"providers.aws.services.codebuild.codebuild_service.generate_regional_clients",
|
||||||
|
new=mock_generate_regional_clients,
|
||||||
|
)
|
||||||
|
class Test_Codebuild_Service:
|
||||||
|
def set_mocked_audit_info(self):
|
||||||
|
audit_info = AWS_Audit_Info(
|
||||||
|
original_session=None,
|
||||||
|
audit_session=session.Session(
|
||||||
|
profile_name=None,
|
||||||
|
botocore_session=None,
|
||||||
|
),
|
||||||
|
audited_account=AWS_ACCOUNT_NUMBER,
|
||||||
|
audited_user_id=None,
|
||||||
|
audited_partition="aws",
|
||||||
|
audited_identity_arn=None,
|
||||||
|
profile=None,
|
||||||
|
profile_region=None,
|
||||||
|
credentials=None,
|
||||||
|
assumed_role_info=None,
|
||||||
|
audited_regions=None,
|
||||||
|
organizations_metadata=None,
|
||||||
|
)
|
||||||
|
return audit_info
|
||||||
|
|
||||||
|
# Test Codebuild Session
|
||||||
|
def test__get_session__(self):
|
||||||
|
codebuild = Codebuild(current_audit_info)
|
||||||
|
assert codebuild.session.__class__.__name__ == "Session"
|
||||||
|
|
||||||
|
# Test Codebuild Service
|
||||||
|
def test__get_service__(self):
|
||||||
|
codebuild = Codebuild(current_audit_info)
|
||||||
|
assert codebuild.service == "codebuild"
|
||||||
|
|
||||||
|
def test__list_projects__(self):
|
||||||
|
codebuild = Codebuild(current_audit_info)
|
||||||
|
assert len(codebuild.projects) == 1
|
||||||
|
assert codebuild.projects[0].name == "test"
|
||||||
|
assert codebuild.projects[0].region == AWS_REGION
|
||||||
|
|
||||||
|
def test__list_builds_for_project__(self):
|
||||||
|
codebuild = Codebuild(current_audit_info)
|
||||||
|
assert len(codebuild.projects) == 1
|
||||||
|
assert codebuild.projects[0].name == "test"
|
||||||
|
assert codebuild.projects[0].region == AWS_REGION
|
||||||
|
assert codebuild.projects[0].last_invoked_time == last_invoked_time
|
||||||
|
assert (
|
||||||
|
codebuild.projects[0].buildspec
|
||||||
|
== "arn:aws:s3:::my-codebuild-sample2/buildspec.yml"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user