ECR: batch_get_repository_scanning_configuration() (#6924)
This commit is contained in:
parent
a0434335d2
commit
a1f261189e
@ -2510,12 +2510,12 @@
|
|||||||
|
|
||||||
## ecr
|
## ecr
|
||||||
<details>
|
<details>
|
||||||
<summary>63% implemented</summary>
|
<summary>68% implemented</summary>
|
||||||
|
|
||||||
- [ ] batch_check_layer_availability
|
- [ ] batch_check_layer_availability
|
||||||
- [X] batch_delete_image
|
- [X] batch_delete_image
|
||||||
- [X] batch_get_image
|
- [X] batch_get_image
|
||||||
- [ ] batch_get_repository_scanning_configuration
|
- [X] batch_get_repository_scanning_configuration
|
||||||
- [ ] complete_layer_upload
|
- [ ] complete_layer_upload
|
||||||
- [ ] create_pull_through_cache_rule
|
- [ ] create_pull_through_cache_rule
|
||||||
- [X] create_repository
|
- [X] create_repository
|
||||||
@ -2545,7 +2545,7 @@
|
|||||||
- [X] put_image_tag_mutability
|
- [X] put_image_tag_mutability
|
||||||
- [X] put_lifecycle_policy
|
- [X] put_lifecycle_policy
|
||||||
- [X] put_registry_policy
|
- [X] put_registry_policy
|
||||||
- [ ] put_registry_scanning_configuration
|
- [X] put_registry_scanning_configuration
|
||||||
- [X] put_replication_configuration
|
- [X] put_replication_configuration
|
||||||
- [X] set_repository_policy
|
- [X] set_repository_policy
|
||||||
- [X] start_image_scan
|
- [X] start_image_scan
|
||||||
|
@ -32,7 +32,7 @@ ecr
|
|||||||
The parameter AcceptedMediaTypes has not yet been implemented
|
The parameter AcceptedMediaTypes has not yet been implemented
|
||||||
|
|
||||||
|
|
||||||
- [ ] batch_get_repository_scanning_configuration
|
- [X] batch_get_repository_scanning_configuration
|
||||||
- [ ] complete_layer_upload
|
- [ ] complete_layer_upload
|
||||||
- [ ] create_pull_through_cache_rule
|
- [ ] create_pull_through_cache_rule
|
||||||
- [X] create_repository
|
- [X] create_repository
|
||||||
@ -70,7 +70,7 @@ ecr
|
|||||||
- [X] put_image_tag_mutability
|
- [X] put_image_tag_mutability
|
||||||
- [X] put_lifecycle_policy
|
- [X] put_lifecycle_policy
|
||||||
- [X] put_registry_policy
|
- [X] put_registry_policy
|
||||||
- [ ] put_registry_scanning_configuration
|
- [X] put_registry_scanning_configuration
|
||||||
- [X] put_replication_configuration
|
- [X] put_replication_configuration
|
||||||
- [X] set_repository_policy
|
- [X] set_repository_policy
|
||||||
- [X] start_image_scan
|
- [X] start_image_scan
|
||||||
|
@ -3,7 +3,7 @@ import json
|
|||||||
import re
|
import re
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any, Dict, List, Iterable, Optional
|
from typing import Any, Dict, List, Iterable, Optional, Tuple
|
||||||
|
|
||||||
from botocore.exceptions import ParamValidationError
|
from botocore.exceptions import ParamValidationError
|
||||||
|
|
||||||
@ -93,6 +93,13 @@ class Repository(BaseObject, CloudFormationModel):
|
|||||||
self.policy: Optional[str] = None
|
self.policy: Optional[str] = None
|
||||||
self.lifecycle_policy: Optional[str] = None
|
self.lifecycle_policy: Optional[str] = None
|
||||||
self.images: List[Image] = []
|
self.images: List[Image] = []
|
||||||
|
self.scanning_config = {
|
||||||
|
"repositoryArn": self.arn,
|
||||||
|
"repositoryName": self.name,
|
||||||
|
"scanOnPush": False,
|
||||||
|
"scanFrequency": "MANUAL",
|
||||||
|
"appliedScanFilters": [],
|
||||||
|
}
|
||||||
|
|
||||||
def _determine_encryption_config(
|
def _determine_encryption_config(
|
||||||
self, encryption_config: Optional[Dict[str, str]]
|
self, encryption_config: Optional[Dict[str, str]]
|
||||||
@ -789,6 +796,20 @@ class ECRBackend(BaseBackend):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def batch_get_repository_scanning_configuration(
|
||||||
|
self, names: List[str]
|
||||||
|
) -> Tuple[List[Dict[str, Any]], List[str]]:
|
||||||
|
configs = []
|
||||||
|
failing = []
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
configs.append(
|
||||||
|
self._get_repository(name=name, registry_id=None).scanning_config
|
||||||
|
)
|
||||||
|
except RepositoryNotFoundException:
|
||||||
|
failing.append(name)
|
||||||
|
return configs, failing
|
||||||
|
|
||||||
def list_tags_for_resource(self, arn: str) -> Dict[str, List[Dict[str, str]]]:
|
def list_tags_for_resource(self, arn: str) -> Dict[str, List[Dict[str, str]]]:
|
||||||
resource = self._parse_resource_arn(arn)
|
resource = self._parse_resource_arn(arn)
|
||||||
repo = self._get_repository(resource.repo_name, resource.account_id)
|
repo = self._get_repository(resource.repo_name, resource.account_id)
|
||||||
@ -1093,6 +1114,17 @@ class ECRBackend(BaseBackend):
|
|||||||
|
|
||||||
return {"replicationConfiguration": replication_config}
|
return {"replicationConfiguration": replication_config}
|
||||||
|
|
||||||
|
def put_registry_scanning_configuration(self, rules: List[Dict[str, Any]]) -> None:
|
||||||
|
for rule in rules:
|
||||||
|
for repo_filter in rule["repositoryFilters"]:
|
||||||
|
for repo in self.repositories.values():
|
||||||
|
if repo_filter["filter"] == repo.name or re.match(
|
||||||
|
repo_filter["filter"], repo.name
|
||||||
|
):
|
||||||
|
repo.scanning_config["scanFrequency"] = rule["scanFrequency"]
|
||||||
|
# AWS testing seems to indicate that this is always overwritten
|
||||||
|
repo.scanning_config["appliedScanFilters"] = [repo_filter]
|
||||||
|
|
||||||
def describe_registry(self) -> Dict[str, Any]:
|
def describe_registry(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"registryId": self.account_id,
|
"registryId": self.account_id,
|
||||||
|
@ -108,6 +108,25 @@ class ECRResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
return json.dumps(response)
|
return json.dumps(response)
|
||||||
|
|
||||||
|
def batch_get_repository_scanning_configuration(self) -> str:
|
||||||
|
names = self._get_param("repositoryNames")
|
||||||
|
configs, missing = self.ecr_backend.batch_get_repository_scanning_configuration(
|
||||||
|
names
|
||||||
|
)
|
||||||
|
return json.dumps(
|
||||||
|
{
|
||||||
|
"scanningConfigurations": configs,
|
||||||
|
"failures": [
|
||||||
|
{
|
||||||
|
"repositoryName": m,
|
||||||
|
"failureCode": "REPOSITORY_NOT_FOUND",
|
||||||
|
"failureReason": "REPOSITORY_NOT_FOUND",
|
||||||
|
}
|
||||||
|
for m in missing
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def complete_layer_upload(self) -> None:
|
def complete_layer_upload(self) -> None:
|
||||||
self.error_on_dryrun()
|
self.error_on_dryrun()
|
||||||
raise NotImplementedError("ECR.complete_layer_upload is not yet implemented")
|
raise NotImplementedError("ECR.complete_layer_upload is not yet implemented")
|
||||||
@ -303,5 +322,11 @@ class ECRResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def put_registry_scanning_configuration(self) -> str:
|
||||||
|
scan_type = self._get_param("scanType")
|
||||||
|
rules = self._get_param("rules")
|
||||||
|
self.ecr_backend.put_registry_scanning_configuration(rules)
|
||||||
|
return json.dumps({"scanType": scan_type, "rules": rules})
|
||||||
|
|
||||||
def describe_registry(self) -> str:
|
def describe_registry(self) -> str:
|
||||||
return json.dumps(self.ecr_backend.describe_registry())
|
return json.dumps(self.ecr_backend.describe_registry())
|
||||||
|
140
tests/test_ecr/test_ecr_scanning_config.py
Normal file
140
tests/test_ecr/test_ecr_scanning_config.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import boto3
|
||||||
|
from moto import mock_ecr
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecr
|
||||||
|
def test_batch_get_repository_scanning_configuration():
|
||||||
|
client = boto3.client("ecr", region_name="us-east-1")
|
||||||
|
repo_name = "test-repo"
|
||||||
|
repo_arn = client.create_repository(repositoryName=repo_name)["repository"][
|
||||||
|
"repositoryArn"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Default ScanningConfig is returned
|
||||||
|
resp = client.batch_get_repository_scanning_configuration(
|
||||||
|
repositoryNames=[repo_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp["scanningConfigurations"] == [
|
||||||
|
{
|
||||||
|
"repositoryArn": repo_arn,
|
||||||
|
"repositoryName": repo_name,
|
||||||
|
"scanOnPush": False,
|
||||||
|
"scanFrequency": "MANUAL",
|
||||||
|
"appliedScanFilters": [],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
assert resp["failures"] == []
|
||||||
|
|
||||||
|
# Non-existing repositories are returned as failures
|
||||||
|
resp = client.batch_get_repository_scanning_configuration(
|
||||||
|
repositoryNames=["unknown"]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp["scanningConfigurations"] == []
|
||||||
|
assert resp["failures"] == [
|
||||||
|
{
|
||||||
|
"repositoryName": "unknown",
|
||||||
|
"failureCode": "REPOSITORY_NOT_FOUND",
|
||||||
|
"failureReason": "REPOSITORY_NOT_FOUND",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecr
|
||||||
|
def test_put_registry_scanning_configuration():
|
||||||
|
client = boto3.client("ecr", region_name="us-east-1")
|
||||||
|
repo_name = "test-repo"
|
||||||
|
repo_arn = client.create_repository(repositoryName=repo_name)["repository"][
|
||||||
|
"repositoryArn"
|
||||||
|
]
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Creating a ScanningConfig where
|
||||||
|
# filter == repo_name
|
||||||
|
####
|
||||||
|
client.put_registry_scanning_configuration(
|
||||||
|
scanType="ENHANCED",
|
||||||
|
rules=[
|
||||||
|
{
|
||||||
|
"scanFrequency": "CONTINUOUS_SCAN",
|
||||||
|
"repositoryFilters": [{"filter": repo_name, "filterType": "WILDCARD"}],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.batch_get_repository_scanning_configuration(
|
||||||
|
repositoryNames=[repo_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp["scanningConfigurations"] == [
|
||||||
|
{
|
||||||
|
"repositoryArn": repo_arn,
|
||||||
|
"repositoryName": repo_name,
|
||||||
|
"scanOnPush": False,
|
||||||
|
"scanFrequency": "CONTINUOUS_SCAN",
|
||||||
|
"appliedScanFilters": [{"filter": repo_name, "filterType": "WILDCARD"}],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Creating a ScanningConfig where
|
||||||
|
# filter == repo*
|
||||||
|
####
|
||||||
|
client.put_registry_scanning_configuration(
|
||||||
|
scanType="ENHANCED",
|
||||||
|
rules=[
|
||||||
|
{
|
||||||
|
"scanFrequency": "SCAN_ON_PUSH",
|
||||||
|
"repositoryFilters": [
|
||||||
|
{"filter": f"{repo_name[:4]}*", "filterType": "WILDCARD"}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.batch_get_repository_scanning_configuration(
|
||||||
|
repositoryNames=[repo_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp["scanningConfigurations"] == [
|
||||||
|
{
|
||||||
|
"repositoryArn": repo_arn,
|
||||||
|
"repositoryName": repo_name,
|
||||||
|
"scanOnPush": False,
|
||||||
|
"scanFrequency": "SCAN_ON_PUSH",
|
||||||
|
"appliedScanFilters": [
|
||||||
|
{"filter": f"{repo_name[:4]}*", "filterType": "WILDCARD"}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Creating a ScanningConfig where
|
||||||
|
# filter == unknown_repo
|
||||||
|
####
|
||||||
|
client.put_registry_scanning_configuration(
|
||||||
|
scanType="ENHANCED",
|
||||||
|
rules=[
|
||||||
|
{
|
||||||
|
"scanFrequency": "MANUAL",
|
||||||
|
"repositoryFilters": [{"filter": "unknown", "filterType": "WILDCARD"}],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.batch_get_repository_scanning_configuration(
|
||||||
|
repositoryNames=[repo_name]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert resp["scanningConfigurations"] == [
|
||||||
|
{
|
||||||
|
"repositoryArn": repo_arn,
|
||||||
|
"repositoryName": repo_name,
|
||||||
|
"scanOnPush": False,
|
||||||
|
"scanFrequency": "SCAN_ON_PUSH",
|
||||||
|
"appliedScanFilters": [
|
||||||
|
{"filter": f"{repo_name[:4]}*", "filterType": "WILDCARD"}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user