mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-05-06 08:47:18 +00:00
feat(aws): add bedrock_prompt_management_exists security check (#10878)
This commit is contained in:
committed by
GitHub
parent
6cb770fcc8
commit
921f49a0de
@@ -10,6 +10,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Universal compliance pipeline integrated into the CLI: `--list-compliance` and `--list-compliance-requirements` show universal frameworks, and CSV plus OCSF outputs are generated for any framework declaring a `TableConfig` [(#10301)](https://github.com/prowler-cloud/prowler/pull/10301)
|
||||
- ASD Essential Eight Maturity Model compliance framework for AWS (Maturity Level One, Nov 2023) [(#10808)](https://github.com/prowler-cloud/prowler/pull/10808)
|
||||
- Update Vercel checks to return personalized finding status extended depending on billing plan and classify them with billing-plan categories [(#10663)](https://github.com/prowler-cloud/prowler/pull/10663)
|
||||
- `bedrock_prompt_management_exists` check for AWS provider [(#10878)](https://github.com/prowler-cloud/prowler/pull/10878)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
|
||||
@@ -2897,6 +2897,7 @@
|
||||
"bedrock_guardrails_configured",
|
||||
"bedrock_model_invocation_logging_enabled",
|
||||
"bedrock_model_invocation_logs_encryption_enabled",
|
||||
"bedrock_prompt_management_exists",
|
||||
"cloudformation_stack_outputs_find_secrets",
|
||||
"cloudfront_distributions_custom_ssl_certificate",
|
||||
"cloudfront_distributions_default_root_object",
|
||||
|
||||
@@ -2901,6 +2901,7 @@
|
||||
"bedrock_guardrails_configured",
|
||||
"bedrock_model_invocation_logging_enabled",
|
||||
"bedrock_model_invocation_logs_encryption_enabled",
|
||||
"bedrock_prompt_management_exists",
|
||||
"cloudformation_stack_outputs_find_secrets",
|
||||
"cloudfront_distributions_custom_ssl_certificate",
|
||||
"cloudfront_distributions_default_root_object",
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "bedrock_prompt_management_exists",
|
||||
"CheckTitle": "Amazon Bedrock Prompt Management prompts exist in the region",
|
||||
"CheckType": [
|
||||
"Software and Configuration Checks/AWS Security Best Practices"
|
||||
],
|
||||
"ServiceName": "bedrock",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "low",
|
||||
"ResourceType": "Other",
|
||||
"ResourceGroup": "ai_ml",
|
||||
"Description": "**Bedrock Prompt Management** enables centralized creation, versioning, and governance of prompts used with foundation models.\n\nThis region-level check verifies whether at least one managed prompt exists in each scanned region, used as an adoption signal for Prompt Management. The presence of a prompt does not by itself guarantee that every application prompt is managed.",
|
||||
"Risk": "Without **Prompt Management**, prompts are scattered across applications with no central oversight, versioning, or auditability over instructions sent to foundation models, weakening governance and compliance posture.\n\nManaged prompts are a governance enabler; **prompt injection** defenses are provided by Bedrock **guardrails**, covered by separate checks.",
|
||||
"RelatedUrl": "",
|
||||
"AdditionalURLs": [
|
||||
"https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-management.html",
|
||||
"https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-management-create.html"
|
||||
],
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws bedrock-agent create-prompt --name example_prompt --default-variant default --variants '[{\"name\":\"default\",\"templateType\":\"TEXT\",\"templateConfiguration\":{\"text\":{\"text\":\"Your prompt template here.\"}}}]'",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Open the Amazon Bedrock console\n2. Navigate to Prompt Management\n3. Click Create prompt\n4. Provide a name and configure the prompt template (a prompt can contain at most one variant; additional variants are created via CreatePromptVersion)\n5. Save the prompt",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Adopt **Bedrock Prompt Management** to centralize prompt definitions, enforce versioning, and maintain governance over model interactions.\n\nUse managed prompts with **guardrails** and apply **least privilege** access controls to restrict who can create or modify prompts.",
|
||||
"Url": "https://hub.prowler.com/check/bedrock_prompt_management_exists"
|
||||
}
|
||||
},
|
||||
"Categories": [
|
||||
"gen-ai"
|
||||
],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Results are generated per scanned region. Regions where `ListPrompts` cannot be queried are omitted from the findings."
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
"""Check for region-level Bedrock Prompt Management adoption."""
|
||||
|
||||
from prowler.lib.check.models import Check, Check_Report_AWS
|
||||
from prowler.providers.aws.services.bedrock.bedrock_agent_client import (
|
||||
bedrock_agent_client,
|
||||
)
|
||||
|
||||
|
||||
class bedrock_prompt_management_exists(Check):
|
||||
"""Check whether Amazon Bedrock Prompt Management prompts exist in the region.
|
||||
|
||||
A region is reported only when ListPrompts succeeded for it; regions where
|
||||
the API call failed (e.g. AccessDenied, unsupported region) are skipped at
|
||||
the service layer and produce no finding.
|
||||
|
||||
- PASS: At least one managed prompt exists in the region (one finding per prompt).
|
||||
- FAIL: No managed prompts exist in the region (one finding per region).
|
||||
"""
|
||||
|
||||
def execute(self) -> list[Check_Report_AWS]:
|
||||
"""Execute the Bedrock Prompt Management exists check.
|
||||
|
||||
Returns:
|
||||
A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for region in sorted(bedrock_agent_client.prompt_scanned_regions):
|
||||
regional_prompts = sorted(
|
||||
(
|
||||
prompt
|
||||
for prompt in bedrock_agent_client.prompts.values()
|
||||
if prompt.region == region
|
||||
),
|
||||
key=lambda prompt: prompt.name,
|
||||
)
|
||||
|
||||
if regional_prompts:
|
||||
for prompt in regional_prompts:
|
||||
report = Check_Report_AWS(metadata=self.metadata(), resource=prompt)
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Bedrock Prompt Management prompt {prompt.name} exists in region {region}."
|
||||
findings.append(report)
|
||||
else:
|
||||
report = Check_Report_AWS(metadata=self.metadata(), resource={})
|
||||
report.region = region
|
||||
report.resource_id = "prompt-management"
|
||||
report.resource_arn = f"arn:{bedrock_agent_client.audited_partition}:bedrock:{region}:{bedrock_agent_client.audited_account}:prompt-management"
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"No Bedrock Prompt Management prompts exist in region {region}."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -140,7 +140,10 @@ class BedrockAgent(AWSService):
|
||||
# Call AWSService's __init__
|
||||
super().__init__("bedrock-agent", provider)
|
||||
self.agents = {}
|
||||
self.prompts = {}
|
||||
self.prompt_scanned_regions: set = set()
|
||||
self.__threading_call__(self._list_agents)
|
||||
self.__threading_call__(self._list_prompts)
|
||||
self.__threading_call__(self._list_tags_for_resource, self.agents.values())
|
||||
|
||||
def _list_agents(self, regional_client):
|
||||
@@ -167,7 +170,32 @@ class BedrockAgent(AWSService):
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def _list_prompts(self, regional_client):
|
||||
"""List all prompts in a region.
|
||||
|
||||
Prompt Management is evaluated as a region-level adoption signal, so
|
||||
prompt collection is intentionally not filtered by audit_resources.
|
||||
"""
|
||||
logger.info("Bedrock Agent - Listing Prompts...")
|
||||
try:
|
||||
paginator = regional_client.get_paginator("list_prompts")
|
||||
for page in paginator.paginate():
|
||||
for prompt in page.get("promptSummaries", []):
|
||||
prompt_arn = prompt.get("arn", "")
|
||||
self.prompts[prompt_arn] = Prompt(
|
||||
id=prompt.get("id", ""),
|
||||
name=prompt.get("name", ""),
|
||||
arn=prompt_arn,
|
||||
region=regional_client.region,
|
||||
)
|
||||
self.prompt_scanned_regions.add(regional_client.region)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def _list_tags_for_resource(self, resource):
|
||||
"""List tags for a Bedrock Agent resource."""
|
||||
logger.info("Bedrock Agent - Listing Tags for Resource...")
|
||||
try:
|
||||
agent_tags = (
|
||||
@@ -190,3 +218,12 @@ class Agent(BaseModel):
|
||||
guardrail_id: Optional[str] = None
|
||||
region: str
|
||||
tags: Optional[list] = []
|
||||
|
||||
|
||||
class Prompt(BaseModel):
|
||||
"""Model representing a Bedrock Prompt Management prompt."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
arn: str
|
||||
region: str
|
||||
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
from unittest import mock
|
||||
|
||||
import botocore
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_aws
|
||||
|
||||
from tests.providers.aws.utils import (
|
||||
AWS_ACCOUNT_NUMBER,
|
||||
AWS_REGION_EU_WEST_1,
|
||||
AWS_REGION_US_EAST_1,
|
||||
set_mocked_aws_provider,
|
||||
)
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
PROMPT_ARN = (
|
||||
f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt/test-prompt-id"
|
||||
)
|
||||
|
||||
|
||||
def mock_make_api_call_list_prompts_access_denied(self, operation_name, kwarg):
|
||||
"""Mock API call where ListPrompts fails with AccessDeniedException."""
|
||||
if operation_name == "ListPrompts":
|
||||
raise ClientError(
|
||||
{
|
||||
"Error": {
|
||||
"Code": "AccessDeniedException",
|
||||
"Message": "User is not authorized to perform: bedrock:ListPrompts",
|
||||
}
|
||||
},
|
||||
operation_name,
|
||||
)
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
def mock_make_api_call_with_prompts(self, operation_name, kwarg):
|
||||
"""Mock API call that returns prompts."""
|
||||
if operation_name == "ListPrompts":
|
||||
return {
|
||||
"promptSummaries": [
|
||||
{
|
||||
"id": "test-prompt-id",
|
||||
"name": "test-prompt",
|
||||
"arn": PROMPT_ARN,
|
||||
}
|
||||
]
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
def mock_make_api_call_with_multiple_prompts(self, operation_name, kwarg):
|
||||
"""Mock API call that returns multiple prompts."""
|
||||
if operation_name == "ListPrompts":
|
||||
return {
|
||||
"promptSummaries": [
|
||||
{
|
||||
"id": "test-prompt-id-1",
|
||||
"name": "test-prompt-1",
|
||||
"arn": f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt/test-prompt-id-1",
|
||||
},
|
||||
{
|
||||
"id": "test-prompt-id-2",
|
||||
"name": "test-prompt-2",
|
||||
"arn": f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt/test-prompt-id-2",
|
||||
},
|
||||
{
|
||||
"id": "test-prompt-id-3",
|
||||
"name": "test-prompt-3",
|
||||
"arn": f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt/test-prompt-id-3",
|
||||
},
|
||||
]
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
def mock_make_api_call_no_prompts(self, operation_name, kwarg):
|
||||
"""Mock API call that returns no prompts."""
|
||||
if operation_name == "ListPrompts":
|
||||
return {"promptSummaries": []}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
class Test_bedrock_prompt_management_exists:
|
||||
@mock.patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_make_api_call_no_prompts,
|
||||
)
|
||||
@mock_aws
|
||||
def test_no_prompts(self):
|
||||
"""Test FAIL when no prompts exist in the region."""
|
||||
from prowler.providers.aws.services.bedrock.bedrock_service import BedrockAgent
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists.bedrock_agent_client",
|
||||
new=BedrockAgent(aws_provider),
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists import (
|
||||
bedrock_prompt_management_exists,
|
||||
)
|
||||
|
||||
check = bedrock_prompt_management_exists()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"No Bedrock Prompt Management prompts exist in region {AWS_REGION_US_EAST_1}."
|
||||
)
|
||||
assert result[0].resource_id == "prompt-management"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
result[0].resource_arn
|
||||
== f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt-management"
|
||||
)
|
||||
|
||||
@mock.patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_make_api_call_with_prompts,
|
||||
)
|
||||
@mock_aws
|
||||
def test_prompts_exist(self):
|
||||
"""Test PASS when prompts exist in the region."""
|
||||
from prowler.providers.aws.services.bedrock.bedrock_service import BedrockAgent
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists.bedrock_agent_client",
|
||||
new=BedrockAgent(aws_provider),
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists import (
|
||||
bedrock_prompt_management_exists,
|
||||
)
|
||||
|
||||
check = bedrock_prompt_management_exists()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Bedrock Prompt Management prompt test-prompt exists in region {AWS_REGION_US_EAST_1}."
|
||||
)
|
||||
assert result[0].resource_id == "test-prompt-id"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
assert result[0].resource_arn == PROMPT_ARN
|
||||
|
||||
@mock.patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_make_api_call_with_multiple_prompts,
|
||||
)
|
||||
@mock_aws
|
||||
def test_multiple_prompts_exist(self):
|
||||
"""Test PASS with one finding per prompt when multiple prompts exist."""
|
||||
from prowler.providers.aws.services.bedrock.bedrock_service import BedrockAgent
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists.bedrock_agent_client",
|
||||
new=BedrockAgent(aws_provider),
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists import (
|
||||
bedrock_prompt_management_exists,
|
||||
)
|
||||
|
||||
check = bedrock_prompt_management_exists()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 3
|
||||
for index, finding in enumerate(result, start=1):
|
||||
expected_name = f"test-prompt-{index}"
|
||||
expected_id = f"test-prompt-id-{index}"
|
||||
assert finding.status == "PASS"
|
||||
assert (
|
||||
finding.status_extended
|
||||
== f"Bedrock Prompt Management prompt {expected_name} exists in region {AWS_REGION_US_EAST_1}."
|
||||
)
|
||||
assert finding.resource_id == expected_id
|
||||
assert finding.region == AWS_REGION_US_EAST_1
|
||||
assert (
|
||||
finding.resource_arn
|
||||
== f"arn:aws:bedrock:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:prompt/{expected_id}"
|
||||
)
|
||||
|
||||
@mock.patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_make_api_call_no_prompts,
|
||||
)
|
||||
@mock_aws
|
||||
def test_no_prompts_multiple_regions(self):
|
||||
"""Test FAIL in multiple regions when no prompts exist."""
|
||||
from prowler.providers.aws.services.bedrock.bedrock_service import BedrockAgent
|
||||
|
||||
aws_provider = set_mocked_aws_provider(
|
||||
[AWS_REGION_US_EAST_1, 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.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists.bedrock_agent_client",
|
||||
new=BedrockAgent(aws_provider),
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists import (
|
||||
bedrock_prompt_management_exists,
|
||||
)
|
||||
|
||||
check = bedrock_prompt_management_exists()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
for finding in result:
|
||||
assert finding.status == "FAIL"
|
||||
assert (
|
||||
finding.status_extended
|
||||
== f"No Bedrock Prompt Management prompts exist in region {finding.region}."
|
||||
)
|
||||
assert finding.resource_id == "prompt-management"
|
||||
assert (
|
||||
finding.resource_arn
|
||||
== f"arn:aws:bedrock:{finding.region}:{AWS_ACCOUNT_NUMBER}:prompt-management"
|
||||
)
|
||||
regions = {finding.region for finding in result}
|
||||
assert regions == {AWS_REGION_US_EAST_1, AWS_REGION_EU_WEST_1}
|
||||
|
||||
@mock.patch(
|
||||
"botocore.client.BaseClient._make_api_call",
|
||||
new=mock_make_api_call_list_prompts_access_denied,
|
||||
)
|
||||
@mock_aws
|
||||
def test_list_prompts_client_error_skips_region(self):
|
||||
"""Test that regions where ListPrompts fails produce no findings."""
|
||||
from prowler.providers.aws.services.bedrock.bedrock_service import BedrockAgent
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists.bedrock_agent_client",
|
||||
new=BedrockAgent(aws_provider),
|
||||
),
|
||||
):
|
||||
from prowler.providers.aws.services.bedrock.bedrock_prompt_management_exists.bedrock_prompt_management_exists import (
|
||||
bedrock_prompt_management_exists,
|
||||
)
|
||||
|
||||
check = bedrock_prompt_management_exists()
|
||||
result = check.execute()
|
||||
|
||||
assert result == []
|
||||
@@ -341,3 +341,125 @@ class TestBedrockAgentPagination:
|
||||
# Verify paginator was used
|
||||
regional_client.get_paginator.assert_called_once_with("list_agents")
|
||||
paginator.paginate.assert_called_once()
|
||||
|
||||
|
||||
class TestBedrockPromptPagination:
|
||||
"""Test suite for Bedrock Prompt pagination logic."""
|
||||
|
||||
def test_list_prompts_pagination(self):
|
||||
"""Test that list_prompts iterates through all pages."""
|
||||
# Mock the audit_info
|
||||
audit_info = MagicMock()
|
||||
audit_info.audited_partition = "aws"
|
||||
audit_info.audited_account = "123456789012"
|
||||
audit_info.audit_resources = None
|
||||
|
||||
# Mock the regional client
|
||||
regional_client = MagicMock()
|
||||
regional_client.region = "us-east-1"
|
||||
|
||||
# Mock paginator
|
||||
paginator = MagicMock()
|
||||
page1 = {
|
||||
"promptSummaries": [
|
||||
{
|
||||
"id": "prompt-1",
|
||||
"name": "prompt-name-1",
|
||||
"arn": "arn:aws:bedrock:us-east-1:123456789012:prompt/prompt-1",
|
||||
}
|
||||
]
|
||||
}
|
||||
page2 = {
|
||||
"promptSummaries": [
|
||||
{
|
||||
"id": "prompt-2",
|
||||
"name": "prompt-name-2",
|
||||
"arn": "arn:aws:bedrock:us-east-1:123456789012:prompt/prompt-2",
|
||||
}
|
||||
]
|
||||
}
|
||||
paginator.paginate.return_value = [page1, page2]
|
||||
regional_client.get_paginator.return_value = paginator
|
||||
|
||||
# Initialize service and inject mock client
|
||||
bedrock_agent_service = BedrockAgent(audit_info)
|
||||
bedrock_agent_service.regional_clients = {"us-east-1": regional_client}
|
||||
bedrock_agent_service.prompts = {} # Clear init side effects
|
||||
bedrock_agent_service.prompt_scanned_regions = set()
|
||||
|
||||
# Run method
|
||||
bedrock_agent_service._list_prompts(regional_client)
|
||||
|
||||
# Assertions
|
||||
assert len(bedrock_agent_service.prompts) == 2
|
||||
assert (
|
||||
"arn:aws:bedrock:us-east-1:123456789012:prompt/prompt-1"
|
||||
in bedrock_agent_service.prompts
|
||||
)
|
||||
assert (
|
||||
"arn:aws:bedrock:us-east-1:123456789012:prompt/prompt-2"
|
||||
in bedrock_agent_service.prompts
|
||||
)
|
||||
assert "us-east-1" in bedrock_agent_service.prompt_scanned_regions
|
||||
|
||||
# Verify paginator was used
|
||||
regional_client.get_paginator.assert_called_once_with("list_prompts")
|
||||
paginator.paginate.assert_called_once()
|
||||
|
||||
def test_list_prompts_ignores_audit_resources_filter(self):
|
||||
"""Prompt collection is region-scoped and must ignore audit_resources."""
|
||||
audit_info = MagicMock()
|
||||
audit_info.audited_partition = "aws"
|
||||
audit_info.audited_account = "123456789012"
|
||||
audit_info.audit_resources = ["arn:aws:s3:::unrelated-resource"]
|
||||
|
||||
regional_client = MagicMock()
|
||||
regional_client.region = "us-east-1"
|
||||
|
||||
paginator = MagicMock()
|
||||
paginator.paginate.return_value = [
|
||||
{
|
||||
"promptSummaries": [
|
||||
{
|
||||
"id": "prompt-1",
|
||||
"name": "prompt-name-1",
|
||||
"arn": "arn:aws:bedrock:us-east-1:123456789012:prompt/prompt-1",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
regional_client.get_paginator.return_value = paginator
|
||||
|
||||
bedrock_agent_service = BedrockAgent(audit_info)
|
||||
bedrock_agent_service.regional_clients = {"us-east-1": regional_client}
|
||||
bedrock_agent_service.prompts = {}
|
||||
bedrock_agent_service.prompt_scanned_regions = set()
|
||||
|
||||
bedrock_agent_service._list_prompts(regional_client)
|
||||
|
||||
assert len(bedrock_agent_service.prompts) == 1
|
||||
assert "us-east-1" in bedrock_agent_service.prompt_scanned_regions
|
||||
|
||||
def test_list_prompts_error_does_not_mark_region_scanned(self):
|
||||
"""If ListPrompts raises, the region must not be added to prompt_scanned_regions."""
|
||||
audit_info = MagicMock()
|
||||
audit_info.audited_partition = "aws"
|
||||
audit_info.audited_account = "123456789012"
|
||||
audit_info.audit_resources = None
|
||||
|
||||
regional_client = MagicMock()
|
||||
regional_client.region = "us-east-1"
|
||||
|
||||
paginator = MagicMock()
|
||||
paginator.paginate.side_effect = Exception("ListPrompts failed")
|
||||
regional_client.get_paginator.return_value = paginator
|
||||
|
||||
bedrock_agent_service = BedrockAgent(audit_info)
|
||||
bedrock_agent_service.regional_clients = {"us-east-1": regional_client}
|
||||
bedrock_agent_service.prompts = {}
|
||||
bedrock_agent_service.prompt_scanned_regions = set()
|
||||
|
||||
bedrock_agent_service._list_prompts(regional_client)
|
||||
|
||||
assert bedrock_agent_service.prompts == {}
|
||||
assert bedrock_agent_service.prompt_scanned_regions == set()
|
||||
|
||||
Reference in New Issue
Block a user