feat(codeartifact): add new fixer codeartifact_packages_external_public_publishing_disabled_fixer (#6263)

This commit is contained in:
Daniel Barranquero
2024-12-19 16:05:01 +01:00
committed by GitHub
parent c87aaeba04
commit 5964b68c86
4 changed files with 162 additions and 9 deletions
@@ -15,7 +15,7 @@ class codeartifact_packages_external_public_publishing_disabled(Check):
for package in repository.packages:
report = Check_Report_AWS(self.metadata())
report.region = repository.region
report.resource_id = package.name
report.resource_id = f"{repository.domain_name}/{package.name}"
report.resource_arn = f"{repository.arn}/{package.namespace + ':' if package.namespace else ''}{package.name}"
report.resource_tags = repository.tags
@@ -28,10 +28,10 @@ class codeartifact_packages_external_public_publishing_disabled(Check):
== RestrictionValues.ALLOW
):
report.status = "FAIL"
report.status_extended = f"Internal package {package.name} is vulnerable to dependency confusion in repository {repository.arn}."
report.status_extended = f"Internal package {package.name} is vulnerable to dependency confusion in repository {repository.domain_name}."
else:
report.status = "PASS"
report.status_extended = f"Internal package {package.name} is not vulnerable to dependency confusion in repository {repository.arn}."
report.status_extended = f"Internal package {package.name} is not vulnerable to dependency confusion in repository {repository.domain_name}."
findings.append(report)
@@ -0,0 +1,59 @@
from prowler.lib.logger import logger
from prowler.providers.aws.services.codeartifact.codeartifact_client import (
codeartifact_client,
)
def fixer(resource_id: str, region: str) -> bool:
"""
Modify the CodeArtifact package's configuration to restrict public access.
Specifically, this fixer changes the package's configuration to block public access by
setting restrictions on the "publish" and "upstream" actions.
Requires the codeartifact:PutPackageOriginConfiguration permission.
Permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codeartifact:PutPackageOriginConfiguration",
"Resource": "*"
}
]
}
Args:
resource_id (str): The CodeArtifact package name in the format "domain_name/package_name".
region (str): AWS region where the CodeArtifact package exists.
Returns:
bool: True if the operation is successful (configuration updated), False otherwise.
"""
try:
domain_name, package_name = resource_id.split("/")
regional_client = codeartifact_client.regional_clients[region]
for repository in codeartifact_client.repositories.values():
if repository.domain_name == domain_name:
for package in repository.packages:
if package.name == package_name:
publish_value = (
package.origin_configuration.restrictions.publish.value
)
regional_client.put_package_origin_configuration(
domain=domain_name,
repository=repository.name,
format=package.format,
package=package_name,
restrictions={
"publish": publish_value,
"upstream": "BLOCK",
},
)
except Exception as error:
logger.error(
f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return False
else:
return True
@@ -0,0 +1,85 @@
from unittest import mock
import botocore
from moto import mock_aws
from prowler.providers.aws.services.codeartifact.codeartifact_service import (
CodeArtifact,
)
from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider
mock_make_api_call = botocore.client.BaseClient._make_api_call
def mock_make_api_call_codeartifact(self, operation_name, kwarg):
if operation_name == "PutPackageOriginConfiguration":
return {
"PackageOriginConfiguration": {
"Restrictions": {
"Publish": "BLOCK",
"Upstream": "BLOCK",
}
}
}
return mock_make_api_call(self, operation_name, kwarg)
def mock_make_api_call_codeartifact_error(self, operation_name, kwarg):
if operation_name == "PutPackageOriginConfiguration":
raise botocore.exceptions.ClientError(
{
"Error": {
"Code": "PackageNotFound",
"Message": "PackageNotFound",
}
},
operation_name,
)
return mock_make_api_call(self, operation_name, kwarg)
class Test_codeartifact_packages_external_public_publishing_disabled_fixer:
@mock_aws
def test_repository_package_public_publishing_origin_internal(self):
with mock.patch(
"botocore.client.BaseClient._make_api_call",
new=mock_make_api_call_codeartifact,
):
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client",
new=CodeArtifact(aws_provider),
):
# Test Fixer
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import (
fixer,
)
assert fixer("test/test-package", AWS_REGION_EU_WEST_1)
@mock_aws
def test_repository_package_public_publishing_origin_internal_error(self):
with mock.patch(
"botocore.client.BaseClient._make_api_call",
new=mock_make_api_call_codeartifact_error,
):
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
), mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client",
new=CodeArtifact(aws_provider),
):
# Test Fixer
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled_fixer import (
fixer,
)
assert not fixer("non-existing-package", AWS_REGION_EU_WEST_1)
@@ -23,6 +23,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
with mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact",
new=codeartifact_client,
), mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client",
new=codeartifact_client,
):
# Test Check
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import (
@@ -69,7 +72,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
"test-repository": Repository(
name="test-repository",
arn=repository_arn,
domain_name="",
domain_name="test",
domain_owner="",
region=AWS_REGION,
packages=[
@@ -97,6 +100,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
with mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact",
new=codeartifact_client,
), mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client",
new=codeartifact_client,
):
# Test Check
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import (
@@ -108,7 +114,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
assert len(result) == 1
assert result[0].region == AWS_REGION
assert result[0].resource_id == "test-package"
assert result[0].resource_id == "test/test-package"
assert (
result[0].resource_arn
== repository_arn + "/" + package_namespace + ":" + package_name
@@ -117,7 +123,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Internal package {package_name} is vulnerable to dependency confusion in repository {repository_arn}."
== f"Internal package {package_name} is vulnerable to dependency confusion in repository test."
)
def test_repository_package_private_publishing_origin_internal(self):
@@ -129,7 +135,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
"test-repository": Repository(
name="test-repository",
arn=repository_arn,
domain_name="",
domain_name="test",
domain_owner="",
region=AWS_REGION,
packages=[
@@ -157,6 +163,9 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
with mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_service.CodeArtifact",
new=codeartifact_client,
), mock.patch(
"prowler.providers.aws.services.codeartifact.codeartifact_client.codeartifact_client",
new=codeartifact_client,
):
# Test Check
from prowler.providers.aws.services.codeartifact.codeartifact_packages_external_public_publishing_disabled.codeartifact_packages_external_public_publishing_disabled import (
@@ -168,7 +177,7 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
assert len(result) == 1
assert result[0].region == AWS_REGION
assert result[0].resource_id == "test-package"
assert result[0].resource_id == "test/test-package"
assert (
result[0].resource_arn
== repository_arn + "/" + package_namespace + ":" + package_name
@@ -177,5 +186,5 @@ class Test_codeartifact_packages_external_public_publishing_disabled:
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Internal package {package_name} is not vulnerable to dependency confusion in repository {repository_arn}."
== f"Internal package {package_name} is not vulnerable to dependency confusion in repository test."
)