Skip to content

[FinServAssessments] Add 64 FinServ GenAI risk checks (FS-01 to FS-69)#23

Open
mehtadman87 wants to merge 16 commits into
aws-samples:mainfrom
mehtadman87:feature/finserv-risk-checks
Open

[FinServAssessments] Add 64 FinServ GenAI risk checks (FS-01 to FS-69)#23
mehtadman87 wants to merge 16 commits into
aws-samples:mainfrom
mehtadman87:feature/finserv-risk-checks

Conversation

@mehtadman87

Copy link
Copy Markdown

Summary

Adds 64 standalone security checks (FS-01 to FS-69) plus 5 upstream extensions to the AIML Security Assessment framework, derived from the AWS guide for Financial Services risk management of the use of Generative AI (March 2026).

The new checks are delivered as a new Lambda function (finserv_assessments/) that runs in parallel with the existing Bedrock, SageMaker, and AgentCore assessment Lambdas. The function produces a finserv_security_report_{execution_id}.csv that is loaded into the consolidated report.

Closes #22


Risk categories covered (15 total)

Range Category PDF §
FS-01..06 Unbounded Consumption §1.2.11
FS-07..11 Excessive Agency §1.2.9
FS-12..16 Supply Chain Vulnerabilities §1.2.12
FS-17..21 Training Data & Model Poisoning §1.2.14
FS-22..26 Vector & Embedding Weaknesses §1.2.15
FS-27..30 Non-Compliant Output §1.2.1
FS-31..34 Misinformation §1.2.3
FS-35..38 Abusive or Harmful Output §1.2.4
FS-39..42 Biased Output §1.2.5
FS-43..46 Sensitive Information Disclosure §1.2.6
FS-47..50 Hallucination §1.2.7
FS-51..54 Prompt Injection §1.2.8
FS-55..58 Improper Output Handling §1.2.13
FS-59..60 Off-Topic & Inappropriate Output §1.2.2
FS-61..63 Out-of-Date Training Data §1.2.10
FS-64..69 Material Gap Checks (cross-category)

Upstream extensions (5 checks merged into existing checks)

These 5 FS checks add detection/remediation depth to existing checks rather than shipping as standalone entries:

FS check Upstream check What it adds
FS-17 SM-07 Model Monitor data quality baseline cadence + CloudWatch namespace
FS-18 SM-23 Low-entropy classification monitoring as poisoning early-warning
FS-19 SM-22 PendingManualApproval default + flag auto-approved latest versions
FS-23 BR-06 Advanced event selector for AWS::Bedrock::KnowledgeBase data events
FS-64 BR-04 Guardrail trace logging verification (action/inputAssessments/outputAssessments)

Files changed

New:

  • functions/security/finserv_assessments/ — new Lambda (app.py, schema.py, requirements.txt, __init__.py)
  • docs/SECURITY_CHECKS_FINSERV_COMMON.md — shared intro, severity rubric, upstream-overlap table, compliance framework mapping
  • docs/SECURITY_CHECKS_FINSERV_PART1_INFRA_CONTROLS.md — FS-01..26
  • docs/SECURITY_CHECKS_FINSERV_PART2_GUARDRAILS_CONTENT_SAFETY.md — FS-27..46
  • docs/SECURITY_CHECKS_FINSERV_PART3_APP_LAYER_AND_GAPS.md — FS-47..69
  • docs/AIMLSecurityAssessment-MappingsTable.csv — machine-readable gap mapping
  • .ash/.ash.yaml — ASH v3.2.6 config with documented suppressions for upstream-convention findings

Modified:

  • template.yaml + template-multi-account.yaml — add FinServSecurityAssessmentFunction resource, DefinitionSubstitutions, and LambdaInvokePolicy
  • statemachine/assessments.asl.json — add FinServ branch to Run Security Assessments parallel state
  • deployment/1-aiml-security-member-roles.yaml + deployment/aiml-security-single-account.yaml — add FinServGenAIRiskAssessmentPermissions IAM statement
  • functions/security/generate_consolidated_report/app.py — load finserv_security_report_*.csv
  • functions/security/bedrock_assessments/app.py — FS-64/FS-23 extension notes
  • functions/security/sagemaker_assessments/app.py — FS-17/FS-18/FS-19 extension notes
  • docs/SECURITY_CHECKS.md — add FinServ section

Compliance frameworks mapped

SR 11-7, FFIEC CAT, NYDFS 500.06, PCI-DSS 12.3.2, DORA Art.6, MAS TRM 9, ISO 27001 A.12, ECOA, OWASP LLM Top 10

Note: Compliance mappings are preliminary and illustrative. They have not been reviewed by AWS Security Assurance Services or external auditors. Each firm should validate mappings with their own MRM/Legal/Compliance teams before relying on them as audit evidence.


Testing

Local quality gates (all passed):

Gate Result
ruff check on all changed .py files ✅ All checks passed
ruff format --check on all changed .py files ✅ All files formatted
cfn-lint on all 5 CFN templates (with .cfnlintrc) ✅ Exit 0
sam validate --lint on both SAM templates ✅ Valid SAM Template
sam build ✅ Build Succeeded
ast.parse on all new/modified Python files ✅ All parse clean

ASH v3.2.6 local scan summary:

Scanner Suppressed Actionable Result
bandit 0 2 (upstream consolidate_html_reports.py) FAILED
cdk-nag 0 51 (all pre-existing upstream patterns) FAILED
checkov 56 22 (all pre-existing upstream patterns) FAILED
detect-secrets 0 0 PASSED
semgrep 0 0 PASSED
npm-audit 0 0 PASSED

All remaining actionable findings are pre-existing upstream patterns (no-VPC Lambda, no-DLQ, wildcard IAM for list/describe operations). The CI ASH workflow uses continue-on-error: true and is informational only. The 56 Checkov suppressions are documented in .ash/.ash.yaml with justifications referencing upstream convention.


Known follow-up items

  1. HTML report renderingreport_template.py currently renders Bedrock/SageMaker/AgentCore sections. Adding a fourth FinServ section requires extending the HTML template, JavaScript filter wiring, and format-string variables. This is a non-trivial change best done in a follow-up PR to keep this one reviewable.
  2. Compliance placeholder wiring — Each check includes a COMPLIANCE_PLACEHOLDER comment listing the applicable FinServ regulatory frameworks. The prototype report owner should wire these into the HTML report's compliance-standards column.
  3. Upstream extension code changes — The 5 upstream extensions are currently added as source-code comments (extension notes). If the maintainers want the detection logic itself extended (e.g., SM-07 checking emit_metrics=Enabled), that can be done in a follow-up PR targeting those specific checks.

Implements 64 standalone security checks plus 5 upstream extensions derived
from the AWS guide for Financial Services risk management of the use of
Generative AI (March 2026):
https://d1.awsstatic.com/onedam/marketing-channels/website/public/global-FinServ-ComplianceGuide-GenAIRisks-public.pdf

Covers 15 risk categories across FS-01 to FS-69:
  FS-01..06  Unbounded Consumption (WAF/Shield, rate limiting, token quotas,
             cost monitoring)
  FS-07..11  Excessive Agency (action boundaries, AgentCore Policy,
             transaction limits, rate alarms)
  FS-12..16  Supply Chain Vulnerabilities (SCPs, model inventory, onboarding
             governance, adversarial evaluation)
  FS-17..21  Training Data & Model Poisoning (Model Monitor, data drift,
             Model Registry, Feature Store rollback)
  FS-22..26  Vector & Embedding Weaknesses (KB least privilege, CloudTrail
             logging, metadata filtering, multi-tenancy)
  FS-27..30  Non-Compliant Output (Automated Reasoning, RAG controls,
             human-in-the-loop, compliance guardrails)
  FS-31..34  Misinformation (KB data quality, source attribution, integrity
             monitoring, sync cadence)
  FS-35..38  Abusive or Harmful Output (FMEval, user reporting, allowlists,
             AI Service Cards)
  FS-39..42  Biased Output (SageMaker Clarify, Bedrock Evaluations, bias
             datasets, AI Service Cards)
  FS-43..46  Sensitive Information Disclosure (CloudWatch log masking, Macie,
             PII pre-processing, data classification)
  FS-47..50  Hallucination (contextual grounding, Automated Reasoning,
             disclaimers, RAG)
  FS-51..54  Prompt Injection (input sanitization, parameterized queries,
             pen testing, SDK currency)
  FS-55..58  Improper Output Handling (output validation, sanitization,
             encoding, XSS prevention)
  FS-59..60  Off-Topic & Inappropriate Output (contextual grounding, topic
             allowlists)
  FS-61..63  Out-of-Date Training Data (KB sync cadence, data currency
             disclaimers, FM version updates)
  FS-64..69  Material Gap Checks (guardrail trace logging, KB data-source S3
             event notifications, AgentCore end-user identity propagation,
             agent financial transaction value thresholds, API Gateway
             request body size limits, prompt input validation)

5 checks contributed as upstream extensions (not standalone entries):
  FS-17 -> SM-07  Model Monitor data quality baseline cadence
  FS-18 -> SM-23  Model drift low-entropy classification monitoring
  FS-19 -> SM-22  Model Registry PendingManualApproval default enforcement
  FS-23 -> BR-06  Knowledge Base data-plane CloudTrail event selectors
  FS-64 -> BR-04  Guardrail trace logging verification

New files:
  functions/security/finserv_assessments/app.py     (64 check functions)
  functions/security/finserv_assessments/schema.py  (Finding schema)
  functions/security/finserv_assessments/requirements.txt
  functions/security/finserv_assessments/__init__.py
  docs/SECURITY_CHECKS_FINSERV_COMMON.md
  docs/SECURITY_CHECKS_FINSERV_PART1_INFRA_CONTROLS.md
  docs/SECURITY_CHECKS_FINSERV_PART2_GUARDRAILS_CONTENT_SAFETY.md
  docs/SECURITY_CHECKS_FINSERV_PART3_APP_LAYER_AND_GAPS.md
  docs/AIMLSecurityAssessment-MappingsTable.csv
  .ash/.ash.yaml  (ASH v3.2.6 config with documented suppressions)

Modified files:
  template.yaml + template-multi-account.yaml
    - Add FinServSecurityAssessmentFunction resource
    - Wire DefinitionSubstitutions and LambdaInvokePolicy
  statemachine/assessments.asl.json
    - Add FinServ branch to Run Security Assessments parallel state
  deployment/1-aiml-security-member-roles.yaml
  deployment/aiml-security-single-account.yaml
    - Add FinServ GenAI Risk Assessment Permissions statement
  functions/security/generate_consolidated_report/app.py
    - Load finserv_security_report_{execution_id}.csv into consolidated report
  functions/security/bedrock_assessments/app.py
    - Add FS-64 (BR-04) and FS-23 (BR-06) extension notes
  functions/security/sagemaker_assessments/app.py
    - Add FS-17 (SM-07), FS-18 (SM-23), FS-19 (SM-22) extension notes
  docs/SECURITY_CHECKS.md
    - Add FinServ section pointing to the four new reference files

Compliance frameworks mapped (preliminary, for MRM/compliance team review):
  SR 11-7, FFIEC CAT, NYDFS 500.06, PCI-DSS 12.3.2, DORA Art.6,
  MAS TRM 9, ISO 27001 A.12, ECOA, OWASP LLM Top 10

Quality gates passed locally:
  ruff check + ruff format --check: clean
  cfn-lint (with .cfnlintrc): exit 0 on all 5 CFN templates
  sam validate --lint: valid on both SAM templates
  sam build: Build Succeeded
  ASH v3.2.6 local scan: detect-secrets PASSED, semgrep PASSED,
    npm-audit PASSED; remaining Checkov/cdk-nag findings are pre-existing
    upstream patterns (CI uses continue-on-error: true for ASH)

Note: HTML report rendering for FinServ findings (fourth section in
report_template.py) is a follow-up item. The finserv_security_report_*.csv
is generated and available in S3 for downstream consumption.

Closes aws-samples#22
@mehtadman87

Copy link
Copy Markdown
Author

@vivekmittal514 @agasthik — PR is ready for review and merge. All CI checks pass (cfn-lint, python-lint, sam-validate, ASH scan). The only failing check is CodeQL Advanced, which has been failing on upstream main for 7+ days due to a pre-existing repo configuration conflict (default setup + advanced workflow both enabled) — not caused by this PR.

Happy to address any questions on the FS-XX mapping to the AWS FinServ GenAI Risk Guide (March 2026). The full check catalog is in docs/SECURITY_CHECKS_FINSERV_PART*.md.

FS-07: Wrap get_agent() in try/except ClientError so agents encrypted
with KMS keys the caller cannot decrypt are skipped rather than
crashing the entire check with ERROR status.

FS-33: Wrap get_bucket_versioning() in try/except ClientError so
deleted or cross-account KB data-source buckets are recorded as
'(access error)' and the check continues rather than returning ERROR.

Both fixes follow the defensive pattern already used in FS-65's
get_bucket_notification_configuration() call.

Discovered and verified in Phase 2 live integration testing against
account 469898429403 (us-east-1).

sim: aws-samples#22
- Bump check count from 52 to 116 (52 core + 64 FinServ) throughout README
- Add Financial Services GenAI Risk to title, key features, services covered,
  How It Works module list, member role permissions, and report structure
- Add finserv_security_report_{execution_id}.csv to individual account report
  file listing
- Update SECURITY_CHECKS.md overview table, TOC, and check ID convention
  table to include FS-XX prefix and 64-check count
- SECURITY_CHECKS.md already contains the full FinServ section (added in
  the original feat commit); this commit updates the summary tables only

sim: aws-samples#22
@mehtadman87

mehtadman87 commented May 1, 2026

Copy link
Copy Markdown
Author

PR Update — Phase 2 & 3 Testing Complete ✅

Author: @mehtadman87 (self-assigned to issue #22)

What's new in this update (2 commits since initial PR)

fix(finserv): Handle per-agent and per-bucket ClientErrors gracefully

  • FS-07 (check_bedrock_agent_action_boundaries): get_agent() now catches ClientError per-agent so KMS-encrypted agents that the caller cannot decrypt are skipped gracefully instead of crashing the entire check with ERROR status.
  • FS-33 (check_knowledge_base_integrity_monitoring): get_bucket_versioning() now catches ClientError per-bucket so deleted or cross-account KB data-source buckets are recorded as (access error) and the check continues.

Both bugs were discovered during Phase 2 live integration testing against an AWS account in us-east-1.

docs: Update README and SECURITY_CHECKS for FinServ addition

  • README: title, check count (52 → 116), key features, services covered, How It Works, member role permissions, report structure, documentation table.
  • SECURITY_CHECKS.md: overview table, TOC, and check ID convention table updated to include FS-XX prefix and 64-check count.

Testing completed

Phase Status Details
Phase 1 — Unit tests ✅ 315 tests, 99% coverage pytest tests/ — all passing
Phase 2 — Live boto3 ✅ 64/64 checks ran, 0 ERRORs Direct Python invocation against account 469898429403
Phase 2 — sam local invoke ✅ statusCode 200, 65 CSV rows Finch container, real AWS credentials
Phase 3 — Full stack deploy ✅ Step Functions SUCCEEDED Stack aiml-sec-finserv, all 4 parallel branches completed
ASH scan ✅ 0 Critical, 0 High, 0 Medium bandit, checkov, detect-secrets, semgrep all PASSED

Requesting review

@vivekmittal514 @agasthik — ready for your review. Happy to address any feedback.

@mehtadman87

mehtadman87 commented May 1, 2026

Copy link
Copy Markdown
Author

PR Update — Phase 2 & 3 Testing Complete ✅

Author: @mehtadman87 (self-assigned to issue #22)

What's new in this update (2 commits since initial PR)

fix(finserv): Handle per-agent and per-bucket ClientErrors gracefully

  • FS-07 (check_bedrock_agent_action_boundaries): get_agent() now catches ClientError per-agent so KMS-encrypted agents that the caller cannot decrypt are skipped gracefully instead of crashing the entire check with ERROR status.
  • FS-33 (check_knowledge_base_integrity_monitoring): get_bucket_versioning() now catches ClientError per-bucket so deleted or cross-account KB data-source buckets are recorded as (access error) and the check continues.

Both bugs were discovered during Phase 2 live integration testing against an aws account in us-east-1.

docs: Update README and SECURITY_CHECKS for FinServ addition

  • README: title, check count (52 → 116), key features, services covered, How It Works, member role permissions, report structure, documentation table.
  • SECURITY_CHECKS.md: overview table, TOC, and check ID convention table updated to include FS-XX prefix and 64-check count.

Testing completed

Phase Status Details
Phase 1 — Unit tests ✅ 315 tests, 99% coverage pytest tests/ — all passing
Phase 2 — Live boto3 ✅ 64/64 checks ran, 0 ERRORs Direct Python invocation against account 469898429403
Phase 2 — sam local invoke ✅ statusCode 200, 65 CSV rows Finch container, real AWS credentials
Phase 3 — Full stack deploy ✅ Step Functions SUCCEEDED Stack aiml-sec-finserv, all 4 parallel branches completed
ASH scan ✅ 0 Critical, 0 High, 0 Medium bandit, checkov, detect-secrets, semgrep all PASSED

CI status

5/6 checks pass. The CodeQL Advanced check fails — this is a pre-existing failure on main (confirmed by checking the main branch CI history). It is not caused by this PR.

Requesting review

@vivekmittal514 @agasthik — ready for your review. Happy to address any feedback.

@vivekmittal514

Copy link
Copy Markdown
Contributor

PR #23 Review: FinServ GenAI Risk Checks against the AWS FinServ Guide

Overall verdict: Strong PR. The 64 checks map faithfully to the guide's 15 risk categories, the consolidation logic is sound, and the documentation is thorough. There are a handful of code bugs and design gaps worth addressing before merge.


Coverage vs. the PDF Guide

The PDF defines 15 risk categories (§1.2.1–§1.2.15) with explicit mitigations. The PR covers all 15. Traceability is clearly marked [PDF §x.y.z] vs [PDF §x.y.z, extension] throughout the docs. The 5 consolidations (FS-17→SM-07, FS-18→SM-23, FS-19→SM-22, FS-23→BR-06, FS-64→BR-04) are well-reasoned and documented. No PDF risk category is missing.

One gap: the PDF's §1.2.1 (Non-Compliant Output) "Practical guidance" callout explicitly says to use existing compliance materials (employee policies, training materials, procedure documents, incident reports) to author Bedrock guardrail denied-topic policies. FS-28 checks for FinServ denied topics but the remediation doesn't mention using these internal materials as the source — a minor doc-only gap.


Code Issues

Bug 1 — FS-03: Wrong proxy for "quota reviewed" (app.py:287)

default_only = all(not q.get("Adjustable") for q in tpm_quotas + rpm_quotas)

Adjustable means the quota can be increased, not that it has been. All Bedrock TPM/RPM quotas are adjustable by nature, so default_only will almost always be True, causing the check to always report Failed. The doc correctly says to compare applied quota value against the default via ListAWSDefaultServiceQuotas — but that API call isn't in the implementation. The code needs to call list_aws_default_service_quotas(ServiceCode="bedrock") and compare Value against the applied value.

Bug 2 — FS-06: Only checks deprecated CostFilters, misses new-style budgets (app.py:451)

svc in json.dumps(b.get("CostFilters", {})).lower()

The doc correctly notes that new budgets use FilterExpression. The code only checks CostFilters. Any budget created after AWS deprecated that field will be missed, producing false WARN results on modern accounts.

Bug 3 — FS-04: Overly broad DIMENSIONAL monitor match (app.py:327)

or m.get("MonitorType") == "DIMENSIONAL"

This treats any DIMENSIONAL monitor as covering Bedrock (e.g., MonitorDimension=LINKED_ACCOUNT). The doc correctly says only MonitorDimension=SERVICE provides coverage. The code should check m.get("MonitorDimension") == "SERVICE".

Bug 4 — logger level set to ERROR suppresses all operational info (app.py:67)

logger.setLevel(logging.ERROR)

All logger.warning() calls throughout the file (e.g., "Could not describe agent") are silently dropped. Lambda logs will be nearly empty on auth/permission errors during partial-access runs. This should be logging.WARNING or logging.INFO for a diagnostic Lambda.

Bug 5 — FS-03: Empty list corner case causes misleading PASS

When tpm_quotas + rpm_quotas is empty (e.g., if the list_service_quotas call returns nothing), all(...) on an empty iterable returns True, so default_only = True → status "Failed". That part is correct. But details will say "Found 0 token-based and 0 request-based Bedrock quotas" with no explanation — the caller sees a Failed finding with no actionable context about why the quota list was empty (API throttle? Wrong region? Permission issue?). Worth adding an explicit branch.


Design Concerns

D1 — Advisory checks mixed into the pass/fail report without a distinct status

Checks like check_hallucination_disclaimer_advisory(), check_compliance_disclaimer_in_outputs(), check_output_encoding_advisory(), and check_data_currency_disclaimer_advisory() always return N/A status because "no AWS API can verify application-level disclaimers." These are valuable but they will show up in the consolidated report alongside real pass/fail results. The severity rubric defines an "Advisory" severity tier, but the StatusEnum in schema.py only has Failed, Passed, N/A — it doesn't include Advisory. Consumers of the CSV won't be able to filter advisory guidance from actionable findings. Consider either adding Advisory to StatusEnum or using a consistent N/A + Informational severity combination with a standard finding name prefix (e.g., "ADVISORY — ") so report consumers can filter.

D2 — Known follow-up: HTML report rendering is incomplete

The PR body explicitly flags this: the HTML report template doesn't render the FinServ section. For a sample repo used in customer demos, shipping a Lambda that writes a CSV but produces no visible output in the HTML report is a UX regression. Worth either blocking merge on this or very prominently documenting it in the README.

D3 — COMPLIANCE_PLACEHOLDER comments are not wired to the report

The doc disclaimer is clear. However, the placeholder text appears in Python docstrings, not in the Finding or CSV output. If someone ingests the CSV expecting compliance mappings, they won't find them. The docs/AIMLSecurityAssessment-MappingsTable.csv helps, but the gap between the code comment and the delivered report artifact may confuse integrators.


IAM Permissions

The FinServGenAIRiskAssessmentPermissions IAM statement in deployment/1-aiml-security-member-roles.yaml is well-scoped and read-only. All actions are list/describe/get variants. Resource: "*" is appropriate for inventory-style checks where ARNs aren't known in advance. One omission: bedrock-agentcore:ListGateways, bedrock-agentcore:GetGateway, and bedrock-agentcore:ListAgentRuntimes are called by check_agentcore_policy_engine() (FS-08) but are not in the IAM statement — those calls will fail with AccessDenied at runtime.


Documentation Quality

The three-part doc split is sensible. The PDF traceability tagging ([PDF §x.y.z] vs extension) is rigorous and reviewer-friendly. The upstream-overlap consolidation table is the strongest part of the PR — the 5-factor analysis for each overlap is methodical and will save future maintainers significant effort.

The compliance disclaimer in SECURITY_CHECKS_FINSERV_COMMON.md is appropriately conservative. One small doc issue: two places in the common doc say "Add this content to docs/SECURITY_CHECKS.md in the forked repository" — these look like stale copy-paste from a planning document and should be removed before merge.


Summary of actionable items

Priority | Item -- | -- Must fix | Bug 1: FS-03 quota detection uses wrong field — add ListAWSDefaultServiceQuotas comparison Must fix | Bug 3: FS-04 DIMENSIONAL monitor match too broad — check MonitorDimension=SERVICE Must fix | Missing IAM perms: bedrock-agentcore:ListGateways/GetGateway/ListAgentRuntimes not in member role Should fix | Bug 2: FS-06 only checks deprecated CostFilters, not FilterExpression Should fix | Bug 4: logger.setLevel(logging.ERROR) drops warnings — set to WARNING Should fix | D1: Add Advisory to StatusEnum or establish a filter convention for advisory checks Nice to have | HTML report rendering for FinServ section (tracked as known follow-up) Cleanup | Remove two stale "Add this content to SECURITY_CHECKS.md" lines from the common doc

PR #23 Review: FinServ GenAI Risk Checks against the AWS FinServ Guide
Overall verdict: Strong PR. The 64 checks map faithfully to the guide's 15 risk categories, the consolidation logic is sound, and the documentation is thorough. There are a handful of code bugs and design gaps worth addressing before merge.

Coverage vs. the PDF Guide
The PDF defines 15 risk categories (§1.2.1–§1.2.15) with explicit mitigations. The PR covers all 15. Traceability is clearly marked [PDF §x.y.z] vs [PDF §x.y.z, extension] throughout the docs. The 5 consolidations (FS-17→SM-07, FS-18→SM-23, FS-19→SM-22, FS-23→BR-06, FS-64→BR-04) are well-reasoned and documented. No PDF risk category is missing.

One gap: the PDF's §1.2.1 (Non-Compliant Output) "Practical guidance" callout explicitly says to use existing compliance materials (employee policies, training materials, procedure documents, incident reports) to author Bedrock guardrail denied-topic policies. FS-28 checks for FinServ denied topics but the remediation doesn't mention using these internal materials as the source — a minor doc-only gap.

Code Issues
Bug 1 — FS-03: Wrong proxy for "quota reviewed" (app.py:287)

default_only = all(not q.get("Adjustable") for q in tpm_quotas + rpm_quotas)
Adjustable means the quota can be increased, not that it has been. All Bedrock TPM/RPM quotas are adjustable by nature, so default_only will almost always be True, causing the check to always report Failed. The doc correctly says to compare applied quota value against the default via ListAWSDefaultServiceQuotas — but that API call isn't in the implementation. The code needs to call list_aws_default_service_quotas(ServiceCode="bedrock") and compare Value against the applied value.

Bug 2 — FS-06: Only checks deprecated CostFilters, misses new-style budgets (app.py:451)

svc in json.dumps(b.get("CostFilters", {})).lower()
The doc correctly notes that new budgets use FilterExpression. The code only checks CostFilters. Any budget created after AWS deprecated that field will be missed, producing false WARN results on modern accounts.

Bug 3 — FS-04: Overly broad DIMENSIONAL monitor match (app.py:327)

or m.get("MonitorType") == "DIMENSIONAL"
This treats any DIMENSIONAL monitor as covering Bedrock (e.g., MonitorDimension=LINKED_ACCOUNT). The doc correctly says only MonitorDimension=SERVICE provides coverage. The code should check m.get("MonitorDimension") == "SERVICE".

Bug 4 — logger level set to ERROR suppresses all operational info (app.py:67)

logger.setLevel(logging.ERROR)
All logger.warning() calls throughout the file (e.g., "Could not describe agent") are silently dropped. Lambda logs will be nearly empty on auth/permission errors during partial-access runs. This should be logging.WARNING or logging.INFO for a diagnostic Lambda.

Bug 5 — FS-03: Empty list corner case causes misleading PASS

When tpm_quotas + rpm_quotas is empty (e.g., if the list_service_quotas call returns nothing), all(...) on an empty iterable returns True, so default_only = True → status "Failed". That part is correct. But details will say "Found 0 token-based and 0 request-based Bedrock quotas" with no explanation — the caller sees a Failed finding with no actionable context about why the quota list was empty (API throttle? Wrong region? Permission issue?). Worth adding an explicit branch.

Design Concerns
D1 — Advisory checks mixed into the pass/fail report without a distinct status

Checks like check_hallucination_disclaimer_advisory(), check_compliance_disclaimer_in_outputs(), check_output_encoding_advisory(), and check_data_currency_disclaimer_advisory() always return N/A status because "no AWS API can verify application-level disclaimers." These are valuable but they will show up in the consolidated report alongside real pass/fail results. The severity rubric defines an "Advisory" severity tier, but the StatusEnum in schema.py only has Failed, Passed, N/A — it doesn't include Advisory. Consumers of the CSV won't be able to filter advisory guidance from actionable findings. Consider either adding Advisory to StatusEnum or using a consistent N/A + Informational severity combination with a standard finding name prefix (e.g., "ADVISORY — ") so report consumers can filter.

D2 — Known follow-up: HTML report rendering is incomplete

The PR body explicitly flags this: the HTML report template doesn't render the FinServ section. For a sample repo used in customer demos, shipping a Lambda that writes a CSV but produces no visible output in the HTML report is a UX regression. Worth either blocking merge on this or very prominently documenting it in the README.

D3 — COMPLIANCE_PLACEHOLDER comments are not wired to the report

The doc disclaimer is clear. However, the placeholder text appears in Python docstrings, not in the Finding or CSV output. If someone ingests the CSV expecting compliance mappings, they won't find them. The docs/AIMLSecurityAssessment-MappingsTable.csv helps, but the gap between the code comment and the delivered report artifact may confuse integrators.

IAM Permissions
The FinServGenAIRiskAssessmentPermissions IAM statement in deployment/1-aiml-security-member-roles.yaml is well-scoped and read-only. All actions are list/describe/get variants. Resource: "*" is appropriate for inventory-style checks where ARNs aren't known in advance. One omission: bedrock-agentcore:ListGateways, bedrock-agentcore:GetGateway, and bedrock-agentcore:ListAgentRuntimes are called by check_agentcore_policy_engine() (FS-08) but are not in the IAM statement — those calls will fail with AccessDenied at runtime.

Documentation Quality
The three-part doc split is sensible. The PDF traceability tagging ([PDF §x.y.z] vs extension) is rigorous and reviewer-friendly. The upstream-overlap consolidation table is the strongest part of the PR — the 5-factor analysis for each overlap is methodical and will save future maintainers significant effort.

The compliance disclaimer in SECURITY_CHECKS_FINSERV_COMMON.md is appropriately conservative. One small doc issue: two places in the common doc say "Add this content to docs/SECURITY_CHECKS.md in the forked repository" — these look like stale copy-paste from a planning document and should be removed before merge.

Summary of actionable items

Priority Item
Must fix Bug 1: FS-03 quota detection uses wrong field — add ListAWSDefaultServiceQuotas comparison
Must fix Bug 3: FS-04 DIMENSIONAL monitor match too broad — check MonitorDimension=SERVICE
Must fix Missing IAM perms: bedrock-agentcore:ListGateways/GetGateway/ListAgentRuntimes not in member role
Should fix Bug 2: FS-06 only checks deprecated CostFilters, not FilterExpression
Should fix Bug 4: logger.setLevel(logging.ERROR) drops warnings — set to WARNING
Should fix D1: Add Advisory to StatusEnum or establish a filter convention for advisory checks
Nice to have HTML report rendering for FinServ section (tracked as known follow-up)
Cleanup Remove two stale "Add this content to SECURITY_CHECKS.md" lines from the common doc###

Python Lint Error - Must Fix:
aiml-security-assessment/functions/security/sagemaker_assessments/app.py
Error: aiml-security-assessment/functions/security/finserv_assessments/app.py:4022:9: F841 Local variable apigwv2 is assigned to but never used
help: Remove assignment to unused variable apigwv2
Error: Process completed with exit code 1.

CodeQL Error - Must Fix
It looks like when you forked the PR, at that time you had following file .github/workflows/codeql.yml. This is removed from the main gitub repo but since it's in your fork, GitHub runs workflows from the fork's .github/workflows/ directory and hence this error is coming. Please perform following steps on your fork repo to remove this error -

git checkout main
git rm .github/workflows/codeql.yml
git commit -m "chore: remove codeql.yml — upstream uses default CodeQL setup"
git push

@vivekmittal514 vivekmittal514 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of actionable items

Must fix Bug 1: FS-03 quota detection uses wrong field — add ListAWSDefaultServiceQuotas comparison
Must fix Bug 3: FS-04 DIMENSIONAL monitor match too broad — check MonitorDimension=SERVICE
Must fix Missing IAM perms: bedrock-agentcore:ListGateways/GetGateway/ListAgentRuntimes not in member role
Should fix Bug 2: FS-06 only checks deprecated CostFilters, not FilterExpression
Should fix Bug 4: logger.setLevel(logging.ERROR) drops warnings — set to WARNING
Should fix D1: Add Advisory to StatusEnum or establish a filter convention for advisory checks
Nice to have HTML report rendering for FinServ section (tracked as known follow-up)
Cleanup Remove two stale "Add this content to SECURITY_CHECKS.md" lines from the common doc###

Python Lint Error - Must Fix:
aiml-security-assessment/functions/security/sagemaker_assessments/app.py
Error: aiml-security-assessment/functions/security/finserv_assessments/app.py:4022:9: F841 Local variable apigwv2 is assigned to but never used
help: Remove assignment to unused variable apigwv2
Error: Process completed with exit code 1.

CodeQL Error - Must Fix
It looks like when you forked the PR, at that time you had following file .github/workflows/codeql.yml. This is removed from the main gitub repo but since it's in your fork, GitHub runs workflows from the fork's .github/workflows/ directory and hence this error is coming. Please perform following steps on your fork repo to remove this error -

git checkout main
git rm .github/workflows/codeql.yml
git commit -m "chore: remove codeql.yml — upstream uses default CodeQL setup"
git push

Review Details

Overall verdict: Strong PR. The 64 checks map faithfully to the guide's 15 risk categories, the consolidation logic is sound, and the documentation is thorough. There are a handful of code bugs and design gaps worth addressing before merge.


Coverage vs. the PDF Guide

The PDF defines 15 risk categories (§1.2.1–§1.2.15) with explicit mitigations. The PR covers all 15. Traceability is clearly marked [PDF §x.y.z] vs [PDF §x.y.z, extension] throughout the docs. The 5 consolidations (FS-17→SM-07, FS-18→SM-23, FS-19→SM-22, FS-23→BR-06, FS-64→BR-04) are well-reasoned and documented. No PDF risk category is missing.

One gap: the PDF's §1.2.1 (Non-Compliant Output) "Practical guidance" callout explicitly says to use existing compliance materials (employee policies, training materials, procedure documents, incident reports) to author Bedrock guardrail denied-topic policies. FS-28 checks for FinServ denied topics but the remediation doesn't mention using these internal materials as the source — a minor doc-only gap.


Code Issues

Bug 1 — FS-03: Wrong proxy for "quota reviewed" (app.py:287)

default_only = all(not q.get("Adjustable") for q in tpm_quotas + rpm_quotas)

Adjustable means the quota can be increased, not that it has been. All Bedrock TPM/RPM quotas are adjustable by nature, so default_only will almost always be True, causing the check to always report Failed. The doc correctly says to compare applied quota value against the default via ListAWSDefaultServiceQuotas — but that API call isn't in the implementation. The code needs to call list_aws_default_service_quotas(ServiceCode="bedrock") and compare Value against the applied value.

Bug 2 — FS-06: Only checks deprecated CostFilters, misses new-style budgets (app.py:451)

svc in json.dumps(b.get("CostFilters", {})).lower()

The doc correctly notes that new budgets use FilterExpression. The code only checks CostFilters. Any budget created after AWS deprecated that field will be missed, producing false WARN results on modern accounts.

Bug 3 — FS-04: Overly broad DIMENSIONAL monitor match (app.py:327)

or m.get("MonitorType") == "DIMENSIONAL"

This treats any DIMENSIONAL monitor as covering Bedrock (e.g., MonitorDimension=LINKED_ACCOUNT). The doc correctly says only MonitorDimension=SERVICE provides coverage. The code should check m.get("MonitorDimension") == "SERVICE".

Bug 4 — logger level set to ERROR suppresses all operational info (app.py:67)

logger.setLevel(logging.ERROR)

All logger.warning() calls throughout the file (e.g., "Could not describe agent") are silently dropped. Lambda logs will be nearly empty on auth/permission errors during partial-access runs. This should be logging.WARNING or logging.INFO for a diagnostic Lambda.

Bug 5 — FS-03: Empty list corner case causes misleading PASS

When tpm_quotas + rpm_quotas is empty (e.g., if the list_service_quotas call returns nothing), all(...) on an empty iterable returns True, so default_only = True → status "Failed". That part is correct. But details will say "Found 0 token-based and 0 request-based Bedrock quotas" with no explanation — the caller sees a Failed finding with no actionable context about why the quota list was empty (API throttle? Wrong region? Permission issue?). Worth adding an explicit branch.


Design Concerns

D1 — Advisory checks mixed into the pass/fail report without a distinct status

Checks like check_hallucination_disclaimer_advisory(), check_compliance_disclaimer_in_outputs(), check_output_encoding_advisory(), and check_data_currency_disclaimer_advisory() always return N/A status because "no AWS API can verify application-level disclaimers." These are valuable but they will show up in the consolidated report alongside real pass/fail results. The severity rubric defines an "Advisory" severity tier, but the StatusEnum in schema.py only has Failed, Passed, N/A — it doesn't include Advisory. Consumers of the CSV won't be able to filter advisory guidance from actionable findings. Consider either adding Advisory to StatusEnum or using a consistent N/A + Informational severity combination with a standard finding name prefix (e.g., "ADVISORY — ") so report consumers can filter.

D2 — Known follow-up: HTML report rendering is incomplete

The PR body explicitly flags this: the HTML report template doesn't render the FinServ section. For a sample repo used in customer demos, shipping a Lambda that writes a CSV but produces no visible output in the HTML report is a UX regression. Worth either blocking merge on this or very prominently documenting it in the README.

D3 — COMPLIANCE_PLACEHOLDER comments are not wired to the report

The doc disclaimer is clear. However, the placeholder text appears in Python docstrings, not in the Finding or CSV output. If someone ingests the CSV expecting compliance mappings, they won't find them. The docs/AIMLSecurityAssessment-MappingsTable.csv helps, but the gap between the code comment and the delivered report artifact may confuse integrators.


IAM Permissions

The FinServGenAIRiskAssessmentPermissions IAM statement in deployment/1-aiml-security-member-roles.yaml is well-scoped and read-only. All actions are list/describe/get variants. Resource: "*" is appropriate for inventory-style checks where ARNs aren't known in advance. One omission: bedrock-agentcore:ListGateways, bedrock-agentcore:GetGateway, and bedrock-agentcore:ListAgentRuntimes are called by check_agentcore_policy_engine() (FS-08) but are not in the IAM statement — those calls will fail with AccessDenied at runtime.


Documentation Quality

The three-part doc split is sensible. The PDF traceability tagging ([PDF §x.y.z] vs extension) is rigorous and reviewer-friendly. The upstream-overlap consolidation table is the strongest part of the PR — the 5-factor analysis for each overlap is methodical and will save future maintainers significant effort.

The compliance disclaimer in SECURITY_CHECKS_FINSERV_COMMON.md is appropriately conservative. One small doc issue: two places in the common doc say "Add this content to docs/SECURITY_CHECKS.md in the forked repository" — these look like stale copy-paste from a planning document and should be removed before merge.


Summary of actionable items

Priority | Item -- | -- Must fix | Bug 1: FS-03 quota detection uses wrong field — add ListAWSDefaultServiceQuotas comparison Must fix | Bug 3: FS-04 DIMENSIONAL monitor match too broad — check MonitorDimension=SERVICE Must fix | Missing IAM perms: bedrock-agentcore:ListGateways/GetGateway/ListAgentRuntimes not in member role Should fix | Bug 2: FS-06 only checks deprecated CostFilters, not FilterExpression Should fix | Bug 4: logger.setLevel(logging.ERROR) drops warnings — set to WARNING Should fix | D1: Add Advisory to StatusEnum or establish a filter convention for advisory checks Nice to have | HTML report rendering for FinServ section (tracked as known follow-up) Cleanup | Remove two stale "Add this content to SECURITY_CHECKS.md" lines from the common doc

PR #23 Review: FinServ GenAI Risk Checks against the AWS FinServ Guide
Overall verdict: Strong PR. The 64 checks map faithfully to the guide's 15 risk categories, the consolidation logic is sound, and the documentation is thorough. There are a handful of code bugs and design gaps worth addressing before merge.

Coverage vs. the PDF Guide
The PDF defines 15 risk categories (§1.2.1–§1.2.15) with explicit mitigations. The PR covers all 15. Traceability is clearly marked [PDF §x.y.z] vs [PDF §x.y.z, extension] throughout the docs. The 5 consolidations (FS-17→SM-07, FS-18→SM-23, FS-19→SM-22, FS-23→BR-06, FS-64→BR-04) are well-reasoned and documented. No PDF risk category is missing.

One gap: the PDF's §1.2.1 (Non-Compliant Output) "Practical guidance" callout explicitly says to use existing compliance materials (employee policies, training materials, procedure documents, incident reports) to author Bedrock guardrail denied-topic policies. FS-28 checks for FinServ denied topics but the remediation doesn't mention using these internal materials as the source — a minor doc-only gap.

Code Issues
Bug 1 — FS-03: Wrong proxy for "quota reviewed" (app.py:287)

default_only = all(not q.get("Adjustable") for q in tpm_quotas + rpm_quotas)
Adjustable means the quota can be increased, not that it has been. All Bedrock TPM/RPM quotas are adjustable by nature, so default_only will almost always be True, causing the check to always report Failed. The doc correctly says to compare applied quota value against the default via ListAWSDefaultServiceQuotas — but that API call isn't in the implementation. The code needs to call list_aws_default_service_quotas(ServiceCode="bedrock") and compare Value against the applied value.

Bug 2 — FS-06: Only checks deprecated CostFilters, misses new-style budgets (app.py:451)

svc in json.dumps(b.get("CostFilters", {})).lower()
The doc correctly notes that new budgets use FilterExpression. The code only checks CostFilters. Any budget created after AWS deprecated that field will be missed, producing false WARN results on modern accounts.

Bug 3 — FS-04: Overly broad DIMENSIONAL monitor match (app.py:327)

or m.get("MonitorType") == "DIMENSIONAL"
This treats any DIMENSIONAL monitor as covering Bedrock (e.g., MonitorDimension=LINKED_ACCOUNT). The doc correctly says only MonitorDimension=SERVICE provides coverage. The code should check m.get("MonitorDimension") == "SERVICE".

Bug 4 — logger level set to ERROR suppresses all operational info (app.py:67)

logger.setLevel(logging.ERROR)
All logger.warning() calls throughout the file (e.g., "Could not describe agent") are silently dropped. Lambda logs will be nearly empty on auth/permission errors during partial-access runs. This should be logging.WARNING or logging.INFO for a diagnostic Lambda.

Bug 5 — FS-03: Empty list corner case causes misleading PASS

When tpm_quotas + rpm_quotas is empty (e.g., if the list_service_quotas call returns nothing), all(...) on an empty iterable returns True, so default_only = True → status "Failed". That part is correct. But details will say "Found 0 token-based and 0 request-based Bedrock quotas" with no explanation — the caller sees a Failed finding with no actionable context about why the quota list was empty (API throttle? Wrong region? Permission issue?). Worth adding an explicit branch.

Design Concerns
D1 — Advisory checks mixed into the pass/fail report without a distinct status

Checks like check_hallucination_disclaimer_advisory(), check_compliance_disclaimer_in_outputs(), check_output_encoding_advisory(), and check_data_currency_disclaimer_advisory() always return N/A status because "no AWS API can verify application-level disclaimers." These are valuable but they will show up in the consolidated report alongside real pass/fail results. The severity rubric defines an "Advisory" severity tier, but the StatusEnum in schema.py only has Failed, Passed, N/A — it doesn't include Advisory. Consumers of the CSV won't be able to filter advisory guidance from actionable findings. Consider either adding Advisory to StatusEnum or using a consistent N/A + Informational severity combination with a standard finding name prefix (e.g., "ADVISORY — ") so report consumers can filter.

D2 — Known follow-up: HTML report rendering is incomplete

The PR body explicitly flags this: the HTML report template doesn't render the FinServ section. For a sample repo used in customer demos, shipping a Lambda that writes a CSV but produces no visible output in the HTML report is a UX regression. Worth either blocking merge on this or very prominently documenting it in the README.

D3 — COMPLIANCE_PLACEHOLDER comments are not wired to the report

The doc disclaimer is clear. However, the placeholder text appears in Python docstrings, not in the Finding or CSV output. If someone ingests the CSV expecting compliance mappings, they won't find them. The docs/AIMLSecurityAssessment-MappingsTable.csv helps, but the gap between the code comment and the delivered report artifact may confuse integrators.

IAM Permissions
The FinServGenAIRiskAssessmentPermissions IAM statement in deployment/1-aiml-security-member-roles.yaml is well-scoped and read-only. All actions are list/describe/get variants. Resource: "*" is appropriate for inventory-style checks where ARNs aren't known in advance. One omission: bedrock-agentcore:ListGateways, bedrock-agentcore:GetGateway, and bedrock-agentcore:ListAgentRuntimes are called by check_agentcore_policy_engine() (FS-08) but are not in the IAM statement — those calls will fail with AccessDenied at runtime.

Documentation Quality
The three-part doc split is sensible. The PDF traceability tagging ([PDF §x.y.z] vs extension) is rigorous and reviewer-friendly. The upstream-overlap consolidation table is the strongest part of the PR — the 5-factor analysis for each overlap is methodical and will save future maintainers significant effort.

The compliance disclaimer in SECURITY_CHECKS_FINSERV_COMMON.md is appropriately conservative. One small doc issue: two places in the common doc say "Add this content to docs/SECURITY_CHECKS.md in the forked repository" — these look like stale copy-paste from a planning document and should be removed before merge.

…otice

- Fix tagline subtitle to include Financial Services GenAI Risk alongside
  Bedrock, SageMaker AI, and Bedrock AgentCore
- Add prominent Known Limitation callout in Report Structure section
  documenting that FinServ findings appear in CSV only and are not yet
  rendered in the HTML report dashboard (follow-up enhancement)
- Add all 5 FinServ documentation files to the Documentation table:
  SECURITY_CHECKS_FINSERV_COMMON.md, PART1/PART2/PART3 check references,
  and AIMLSecurityAssessment-MappingsTable.csv with compliance mappings
…oyment YAMLs

Add the FinServGenAIRiskAssessmentPermissions IAM statement to both
deployment/1-aiml-security-member-roles.yaml and
deployment/aiml-security-single-account.yaml.

The FinServ checks (FS-01 to FS-69) require 51 read-only actions that were
present in member_role_permissions_addition.yaml (the workspace snippet) and
template_additions.yaml (the SAM template inline policy) but missing from the
two CloudFormation deployment templates that govern actual role creation.

Actions added (all read-only list/describe/get variants):
  WAF/Shield (FS-01): wafv2:ListWebACLs, wafv2:GetWebACL,
    shield:DescribeSubscription
  API Gateway (FS-02, FS-68, FS-69): apigateway:GET
  Cost/Budgets (FS-04, FS-06): ce:GetAnomalyMonitors, budgets:DescribeBudgets
  CloudWatch (FS-05, FS-11): cloudwatch:DescribeAlarms
  CloudWatch Logs (FS-43): logs:DescribeAccountPolicies
  Lambda (FS-09, FS-67, FS-69): lambda:GetFunctionConcurrency
  Step Functions (FS-10, FS-11): states:ListStateMachines,
    states:DescribeStateMachine
  Organizations (FS-12): organizations:ListPolicies, organizations:DescribePolicy
  SageMaker (FS-13, FS-42): sagemaker:ListModelCards, sagemaker:ListTags
  Bedrock (FS-15, FS-30, FS-34, FS-40): bedrock:ListEvaluationJobs,
    bedrock:ListFoundationModels, bedrock:ListModelPackageGroups
  Macie (FS-44): macie2:GetMacieSession
  OpenSearch Serverless (FS-25, FS-26): aoss:ListSecurityPolicies
  EventBridge (FS-33, FS-65): events:ListRules
  Config (FS-14): config:DescribeConfigRules
  S3 (FS-21, FS-44): s3:ListAllMyBuckets
  Resource: "*" — appropriate for inventory-style checks where ARNs are not
  known in advance; consistent with all other assessment statements.

The bedrock-agentcore:ListAgentRuntimes/GetAgentRuntime/ListGateways/GetGateway
actions were already present in both files from a prior commit.
…RV_COMMON.md

Remove two instances of the planning-artifact instruction:
  'Add this content to docs/SECURITY_CHECKS.md in the forked repository.'

These lines were carry-overs from the original planning document and were
flagged by the PR reviewer as stale before merge. They appeared after the
region-availability disclaimer paragraph and after the upstream-overlap
consolidation summary, and have no relevance to the shipped document.
Syncs the fork's finserv_assessments/ package with the workspace staging
area, applying all fixes from the PR review (TASK-1 through TASK-15):

FS-03 (Bug 1 — TASK-1): Replace adjustability-based quota check with
  value-based comparison. Call list_aws_default_service_quotas(ServiceCode=
  'bedrock') and paginate both applied and default quota lists. Compare
  applied Value > default Value for token-based quotas only. Remove
  rpm_quotas and default_only = all(not q.get('Adjustable') ...) which
  incorrectly evaluated whether quotas were adjustable (always True for
  Bedrock) rather than whether they had been customised. Add explicit
  branches for empty applied-quota list and unavailable defaults.

FS-04 (Bug 2 — TASK-2): Fix monitor filter to require MonitorDimension=
  'SERVICE' for DIMENSIONAL monitors. A LINKED_ACCOUNT monitor no longer
  counts as Bedrock coverage.

FS-06 (Bug 3 — TASK-6): Add ShowFilterExpression=True and pagination to
  describe_budgets. Check both CostFilters and FilterExpression fields.
  Add ParamValidationError fallback for older SDK versions.

Logger (TASK-7): Lower logger level from ERROR to WARNING so all
  logger.warning() calls emit to CloudWatch Logs.

Advisory checks (TASK-8): Retag 8 advisory checks with Status=N/A,
  Severity=Informational, and 'ADVISORY: ' finding-name prefix. Checks
  that make real API calls (FS-24, FS-34, FS-42, FS-52) are unchanged.

Dead variable (TASK-4): Remove unused apigwv2 variable from
  check_api_gateway_request_body_size_limits (F841 lint error).

Check registry + could-not-assess (TASK-13): Add COULD_NOT_ASSESS_PREFIX
  constant, _could_not_assess_row() helper, and build_finserv_checks()
  registry of 64 (check_id, callable) tuples. Drive lambda_handler from
  the registry; synthesise a visible N/A/Medium row for any check that
  errors out with an empty csv_data list.

Compliance_Frameworks column (TASK-15/D3): Add COMPLIANCE_MAP dict
  mapping all 64 FS IDs to pipe-separated regulatory framework strings.
  Add Compliance_Frameworks field to schema.py Finding model and
  create_finding() signature. Inject compliance_frameworks=COMPLIANCE_MAP
  ['FS-XX'] into all 153 create_finding() call sites. Add
  Compliance_Frameworks as 8th column in generate_csv_report fieldnames.

requirements.txt (TASK-14): Bump boto3>=1.43.21, botocore>=1.43.21;
  add pydantic>=2.0.0 with version floor; add explanatory header.
Apply the second-round, solution-wide audit fixes to the FinServ package,
deployment IAM, and docs.

Checks (app.py):
- Stop conflating IAM AccessDenied with real findings in FS-21/33/46/65 via a
  shared _is_access_error() helper (access errors now surface as
  could-not-assess instead of false non-compliant findings).
- Remove the silent kbs[:10] cap in FS-33 so all knowledge bases are assessed.
- Add a _paginate() helper and apply it to ~35 previously single-page reads
  (list_functions, list_guardrails, list_evaluation_jobs, list_data_sources,
  list_knowledge_bases, ECR/Config/Events/SageMaker/API Gateway/Organizations),
  handling NextToken/nextToken/Marker/position token conventions.
- Fix FS-25 status logic: "no policies" is N/A; encryption policies with no
  customer-managed key now correctly WARN/Failed (was always Passed).
- FS-34: report legacy models as "available in region" (availability != usage)
  and soften the verdict to N/A.
- FS-67: disclose the env-var threshold check is a best-effort heuristic.
- Harden bucket-ARN parsing via _bucket_name_from_arn().

Schema/deps:
- Migrate schema.py to Pydantic v2 @field_validator; cap pydantic<3.0.0.

IAM (deployment YAMLs):
- Collapse two divergent, partial FinServ statements into one authoritative
  45-action statement per file.
- Replace invalid actions: bedrock-agent:* -> bedrock:*,
  budgets:DescribeBudgets -> budgets:ViewBudget; drop bedrock:ListModelPackageGroups.
- Add servicequotas:ListAWSDefaultServiceQuotas, bedrock-agentcore Gateways,
  s3:GetBucketVersioning/Tagging/Notification; remove dead cloudtrail:* and
  sagemaker:ListModelPackage(Groups). Validated with cfn-lint (no unrecognized
  actions in the FinServ statement).

Docs:
- FS-21 detection text corrected (it verifies S3 versioning, not CloudTrail).
- Remove stale blank lines in SECURITY_CHECKS_FINSERV_COMMON.md.

Verification: ruff clean; 350 unit tests pass; app.py 99% / schema.py 100%
coverage; live lambda_handler run against a real account returns 64 findings
with zero silent drops.
…nd NoSuchBucket refinement

This commit incorporates three rounds of systematic solution-wide audit
improvements to the FinServ GenAI risk assessment (TASK-17 through TASK-19).

== Code quality and correctness (app.py) ==

FS-27 — Split into two checks sharing the FS-27 check_id:
  1. check_guardrail_contextual_grounding() verifies contextualGroundingPolicy
     (threshold-based, per-inference).
  2. check_automated_reasoning_policies() verifies Bedrock Automated Reasoning
     policies (formal verification, GA August 2025; bedrock:ListAutomatedReasoning
     Policies). Handles access-denied / unsupported-region gracefully.

FS-28 / FS-59 — Denied-topics Standard tier advisory: both checks now surface a
  Low-severity advisory when denied topics exist but use the CLASSIC tier,
  consistent with the FS-36 content-filter tier advisory (June 2025 GA).

FS-31 — Hardcoded 7-day staleness threshold promoted to a named STALE_AFTER_DAYS
  constant with a docstring note that it is a configurable review prompt, not an
  AWS-mandated limit.

FS-34 / FS-63 — list_foundation_models() byOutputModality='TEXT' filter removed
  from both checks; now fetches all modalities (TEXT, EMBEDDING, IMAGE) so legacy
  embedding models used in FinServ RAG pipelines are not silently missed.

FS-47 — False-pass fixed: guardrails that exist but have no GROUNDING filter at
  all (only RELEVANCE) now correctly WARN/Failed instead of silently Passing.
  Reference URL updated to guardrails-contextual-grounding-check.html.

FS-50 — Renamed check_automated_reasoning_checks_hallucination() to
  check_guardrail_relevance_grounding() for accurate labeling.

FS-52 — Deprecated-runtime check inverted from denylist to allowlist
  (SUPPORTED_RUNTIMES) sourced from the live AWS Lambda runtimes page
  (June 2026); catches python3.9, python3.10, nodejs18.x, nodejs20.x, and all
  other deprecated runtimes the old 4-entry denylist missed.

FS-54 — Resolution text updated to reference AWS Security Agent (GA March 2026,
  6 regions, cross-account shared-VPC via RAM) for on-demand GenAI pen testing.

FS-61 — EventBridge Scheduler detection added alongside legacy EventBridge rules:
  customers following the AWS-recommended scheduler:ListSchedules approach no
  longer get a false WARN. Access-denied on Scheduler degrades gracefully.

FS-63 — byOutputModality='TEXT' filter removed (same fix as FS-34).

FS-33 / FS-65 — NoSuchBucket distinguished from other errors via a new
  _is_missing_bucket_error() helper. A KB data-source pointing to a deleted
  bucket now produces a distinct 'KB Data Source References a Deleted S3 Bucket'
  finding (Severity: High) instead of the misleading 'without versioning' /
  'missing notifications' / '(error)' mislabel. Verified against a real dangling
  reference in the test account.

== IAM permissions ==

Added to both deployment YAMLs (FinServGenAIRiskAssessmentPermissions statement):
  - scheduler:ListSchedules (FS-61 EventBridge Scheduler check)
  - bedrock:ListAutomatedReasoningPolicies (FS-27 ARC policies check)

== Schema ==

Pydantic v2 migration already in prior commit; requirements.txt floor unchanged.

== Docs ==

GIT_WORKFLOW.md: corrected '11 steps' to '9 steps'.
scripts/*.py + convert_to_pdf.py: ruff format applied (cosmetic only — confirmed
  byte-identical build output before and after).

== Verification ==

  - ruff check + ruff format --check: all 16 real Python files pass.
  - Unit tests: 368 pass (up from 350; covers all new branches including
    scheduler fallback, FS-47 no-GROUNDING-filter, FS-28/FS-59 CLASSIC tier,
    FS-33/FS-65 deleted-bucket, _is_missing_bucket_error helper).
  - Live full handler run (account 469898429403): 65 checks, 0 ERROR,
    0 EXCEPTION. New ARC-policies check and scheduler path execute cleanly.
  - Sample report regenerated; FS-33/FS-65 now show the High-severity
    deleted-bucket finding for the real dangling reference in the test account.
@mehtadman87

Copy link
Copy Markdown
Author

Update: Solution-wide audit improvements (TASK-17 → TASK-19)

This push () incorporates three rounds of systematic deep-audit improvements since the original submission. Summary of key changes:

New feature: Automated Reasoning Policies check (FS-27b)

  • Added check_automated_reasoning_policies() using bedrock:ListAutomatedReasoningPolicies (GA August 2025) — formal policy-based verification of factual claims, distinct from contextual grounding.
  • FS-27 now emits two rows: one for contextual grounding (threshold-based) and one for ARC policies.
  • Added bedrock:ListAutomatedReasoningPolicies to both deployment IAM YAMLs.

New feature: EventBridge Scheduler detection (FS-61)

  • Added scheduler:ListSchedules check alongside legacy EventBridge rules — customers using the AWS-recommended Scheduler approach no longer get a false WARN.
  • Added scheduler:ListSchedules IAM action to both deployment YAMLs.

Bug fixes

  • FS-34 / FS-63: Removed byOutputModality='TEXT' filter from list_foundation_models() in both checks — legacy EMBEDDING models (used in FinServ RAG pipelines) were silently missed.
  • FS-47: Fixed a false-pass when guardrails exist but have no GROUNDING filter at all (only RELEVANCE). Now correctly WARN/Failed.
  • FS-52: Inverted deprecated-runtime check from a 4-entry denylist to an allowlist of all currently-supported runtimes (sourced from the live AWS Lambda runtimes page, June 2026). Previously missed python3.9, python3.10, nodejs18.x, nodejs20.x.
  • FS-33 / FS-65: Added _is_missing_bucket_error() helper to distinguish a deleted data-source bucket (NoSuchBucket/404) from 'versioning absent' / 'notifications absent'. Deleted buckets now emit a distinct High-severity 'KB Data Source References a Deleted S3 Bucket' finding instead of a misleading '(error)' mislabel.

Tier awareness (FS-28, FS-59)

  • Both denied-topics checks now surface a Low-severity advisory when denied topics use the CLASSIC tier, consistent with the FS-36 content-filter tier advisory.

Quality

  • FS-27/FS-50 renamed: check_automated_reasoning_checkscheck_guardrail_contextual_grounding; check_automated_reasoning_checks_hallucinationcheck_guardrail_relevance_grounding — accurately reflects what the functions check (contextual grounding, not ARC).
  • All scripts and utility files now pass ruff check + ruff format --check.
  • 368 unit tests pass (up from 350). Validated live against account 469898429403: 65 checks, 0 ERROR, 0 EXCEPTION.
  • Sample report regenerated with the refined findings.

@mehtadman87

Copy link
Copy Markdown
Author

Review response: all items from @vivekmittal514's June 1 review addressed

@vivekmittal514 @agasthik — working through each item from the June 1 review in order:


Must fix

Bug 1 — FS-03 quota detection (wrong Adjustable proxy)
Fixed in commit 02461b6. Replaced the Adjustable-based check entirely. check_bedrock_token_quotas() now paginates list_service_quotas(ServiceCode="bedrock") to get applied values, paginates list_aws_default_service_quotas(ServiceCode="bedrock") to get defaults, and compares Value directly. Verdict: applied > default → Passed; all at default → N/A (soft warn); empty applied list → explicit Failed with diagnostic message; defaults unretrievable → explicit Failed with "undetermined" message.

Bug 3 — FS-04 DIMENSIONAL monitor match too broad
Fixed in commit 02461b6. The bedrock_monitors comprehension now requires m.get("MonitorDimension") == "SERVICE" for DIMENSIONAL monitors. A MonitorDimension=LINKED_ACCOUNT monitor no longer yields Passed.

Missing IAM perms — bedrock-agentcore:ListGateways/GetGateway/ListAgentRuntimes
Fixed in commit 6ae99a1 (deployment YAMLs) and further hardened in de487a6 and 3b05f7c. All three actions added to FinServGenAIRiskAssessmentPermissions in both deployment/1-aiml-security-member-roles.yaml and deployment/aiml-security-single-account.yaml. Also added bedrock:ListAutomatedReasoningPolicies and scheduler:ListSchedules in 3b05f7c for the new FS-27b and FS-61 checks.

Python lint — unused apigwv2 variable (F841)
Fixed in commit 02461b6. The apigwv2 = boto3.client("apigatewayv2", ...) assignment in check_api_gateway_request_body_size_limits() is removed. ruff check exits 0.

CodeQL — stale codeql.yml in fork
Fixed in commit fd29cee on mehtadman87/sample-aiml-security-assessment main branch. File removed, committed with message chore: remove codeql.yml — upstream uses default CodeQL setup.


Should fix

Bug 2 — FS-06 only checks deprecated CostFilters
Fixed in commit 02461b6. Added a _paginate_budgets(show_filter_expression) helper that calls DescribeBudgets with ShowFilterExpression=True. The aiml_budgets comprehension now checks both CostFilters and FilterExpression. Defensive degradation: if the installed botocore is too old to accept ShowFilterExpression, a ParamValidationError is caught and the check falls back to CostFilters-only with a logged warning rather than erroring out.

Bug 4 — logger.setLevel(logging.ERROR) drops warnings
Fixed in commit 02461b6. Changed to logging.WARNING at line 68 (now line 75 after additions). All logger.warning() calls throughout the file are now emitted to CloudWatch Logs.

D1 — Advisory checks not distinguishable in report
Addressed in commit 02461b6 using the N/A + Informational + "ADVISORY: " prefix convention (Option B — no StatusEnum change). All 8 advisory checks (FS-29, FS-32, FS-37, FS-49, FS-54, FS-57, FS-60, FS-62) now return Status="N/A", Severity="Informational", and a Finding name starting with "ADVISORY: ". Report consumers can filter on any of those three signals. COULD NOT ASSESS rows use N/A + Medium so the two N/A categories don't collide.


Nice to have

D2 — HTML report rendering for FinServ section
Documented rather than blocking merge, per commit 05637ad. A prominent ⚠️ Known Limitation blockquote was added to the README Report Structure section directly under the finserv_security_report_*.csv entry, clearly stating that FinServ findings are CSV-only and not yet rendered in the HTML dashboard. Tracked as a follow-up PR.


Cleanup

Stale "Add this content to SECURITY_CHECKS.md" lines
Removed in commit 8dd9faa from docs/SECURITY_CHECKS_FINSERV_COMMON.md in the fork. Both instances confirmed gone.


Coverage gap (PDF §1.2.1 — FS-28 remediation)

Updated in commit 02461b6. The check_guardrail_denied_topics_financial() resolution now explicitly references using existing compliance materials (employee policies, training materials, procedure documents, incident reports) as the source for authoring Bedrock guardrail denied-topic policies, per the PDF §1.2.1 Practical guidance callout.


D3 — Compliance frameworks wired to CSV output

Addressed in commit 02461b6. Added a COMPLIANCE_MAP dict in app.py mapping all 64 FS check IDs to pipe-separated regulatory framework strings (e.g., "FFIEC CAT | SR 11-7 | NYDFS 500"). Added Compliance_Frameworks as an 8th column in the CSV output and injected compliance_frameworks=COMPLIANCE_MAP["FS-XX"] into all 152 create_finding() call sites. Every finding row now carries its framework mapping inline.


Additional improvements since original submission (commits de487a6, 3b05f7c)

Beyond the review items, three rounds of systematic deep-audit hardening have been applied — new ARC check (FS-27b), EventBridge Scheduler detection (FS-61), FS-34/63 embedding model fix, FS-47 false-pass fix, FS-52 inverted to allowlist, FS-33/65 deleted-bucket distinction, tier-awareness advisories for FS-28/59, and IAM reconciliation. Full details in the June 4 update comment above.

368 unit tests pass (up from 315 at original submission). Validated live against a real AWS account: 65 checks, 0 ERROR, 0 EXCEPTION.

Ready for re-review. Happy to answer any questions.

…x and review improvements

Merges upstream/main (37a9db4..8b381a4) into feature/finserv-risk-checks to bring
in all fixes that landed on main after the PR branch diverged.

Key upstream changes absorbed:
- 1bfa472: Fix 0% pass rate by retaining check severity on passed findings
  bedrock/sagemaker/agentcore passed findings now carry documented severity
  (High/Medium/Low) instead of being downgraded to Informational. Report
  pass-rate calculations exclude Informational, so the prior behavior caused
  artificially low pass rates.
- 80f9864: Fix review issues — credentials in memory, cleanup pagination,
  configurable timeout, error handlers, ASH enforcement, SECURITY_CHECKS BR-14
- 1c34b7f: Add unit tests for all 51 core security checks (213 tests) with
  GitHub Actions CI workflow
- ef404e9: Fix ruff lint errors in test files
- 6543961: Remove CodeQL workflow (default setup enabled on upstream repo)
- d861fae: Documentation updates (aws-samples#24)
- 63a25ae: Document local test instructions in CONTRIBUTING.md and Developer Guide
- ca2b34c / 878a168 / 6244074: Consolidate sample reports; scrub real account
  numbers and access keys from sample HTML reports
- 741bcbc: Fix broken navigation links in sample HTML reports

Conflict resolution (2 doc conflicts):
- README.md (3 hunks): Kept FinServ-inclusive title and 116-check count;
  adopted upstream full AWS service names (Amazon SageMaker AI, Amazon Bedrock
  AgentCore).
- docs/SECURITY_CHECKS.md (1 hunk): Kept 116-check intro sentence (52 core +
  64 FinServ). Also corrected stale Bedrock section header from 13 to 14
  (BR-14 was added in 80f9864 but section header was not updated).

Auto-merge verification (all pass):
- bedrock Informational count: 26 -> 12 (severity fix absorbed) ✓
- sagemaker Informational count: 49 -> 20 (severity fix absorbed) ✓
- agentcore SeverityEnum.INFORMATIONAL count: -> 27 (severity fix absorbed) ✓
- FS-17/18/19 extension comments in sagemaker: preserved ✓
- FS-23/64 extension comments in bedrock: preserved ✓

NOTE: FinServ app.py has the SAME severity-on-passed regression independently
(~55 passed findings hardcoded to Informational). This is NOT fixed by this
merge — it requires a dedicated follow-up commit (Phase 2 of the fix plan).
…rors 1bfa472)

FinServ app.py independently introduced the same bug fixed upstream in commit
1bfa472 ("Fix 0% pass rate by retaining check severity on passed findings").
All ~60 Passed findings in finserv_assessments/app.py were hardcoded to
severity="Informational", which the report template excludes from both the
actionable-findings denominator and the passed-count numerator — producing
artificially low pass rates in the generated reports.

This commit applies the same fix pattern as 1bfa472: Passed findings now carry
the check's documented severity (High/Medium/Low) instead of Informational.

Changes:
- 55 create_finding(status="Passed", severity="Informational") call sites
  updated to severity=<documented_severity> across 53 unique FS check IDs.
- N/A findings (Informational, "no resources found") — UNCHANGED (21 total).
- Advisory checks (FS-29/32/37/49/54/57/60/62, ADVISORY: prefix, N/A+Info)
  — UNCHANGED (correct by design, D1 advisory convention from pr-review-fixes).
- 5 already-correct Passed findings (FS-24/51/56/58/59) — UNCHANGED.

Severity map derived from each check's own Failed/WARN branch (primary source)
and cross-checked against docs/SECURITY_CHECKS_FINSERV_PART1-3.md.
6 checks with all-Informational non-Passed branches (FS-31/34/52/61/68/69)
resolved to Medium via direct Failed-branch code inspection.

Verification (post-fix):
- Passed+Informational remaining: 0 (was 55)
- Passed severity distribution: High=22, Medium=35, Low=3
- N/A+Informational unchanged: 21
- ruff check: All checks passed
- ruff format --check: 1 file already formatted
- sam build: Build Succeeded (all 7 Lambda functions)
- sam validate --lint (both templates): valid SAM Template
- cfn-lint (all 4 templates): exit 0
- pytest tests/ -q: 368 passed in 0.70s

Fixes feedback from Vivek Mittal (2026-06-05):
  "Informational severity are coming as status Passed instead of N/A.
   Several existing checks which were earlier Medium/Low/High seems to be
   changed to Informational as well."
@mehtadman87

Copy link
Copy Markdown
Author

Fix: severity regression on Passed findings (addresses Vivek report feedback)

@vivekmittal514 @agasthik — following up on the Slack feedback about Informational severity on Passed findings causing low pass rates. Root cause confirmed and both issues fixed.

Root cause (two independent issues)

Issue 1 — Missing upstream fix in bedrock/sagemaker/agentcore (commit 9971d7c):
PR #23 branched before commit 1bfa472 (Fix 0% pass rate) landed on main. That fix changed passed findings in all three service Lambdas from Informational to documented severity. Without it the PR would regress main on merge.

Fix: merged upstream/main (16 commits) into the branch. All three service files auto-merged cleanly.

  • bedrock Informational: 26 → 12 (matches main)
  • sagemaker Informational: 49 → 20 (matches main)
  • agentcore: absorbed cleanly

Issue 2 — FinServ has the same bug independently (commit 5c17c6f):
finserv_assessments/app.py copied the same buggy pattern — 55 of 60 Passed findings were hardcoded to severity=Informational, which the report template excludes from pass-rate calculations entirely.

Fix: applied the same pattern as 1bfa472 to all 55 call sites. N/A findings and the 8 ADVISORY-prefixed checks are unchanged.

Post-fix FinServ Passed severity: High=22, Medium=35, Low=3, Informational=0 (was 55).

Verification

All gates green: ruff check, sam build (7 Lambdas), sam validate (both templates), cfn-lint (4 templates), 368 workspace tests + 213 upstream tests passed.

Passed+Informational in all live CSVs: 0 (was 55+).

Live report results (re-generated 2026-06-08)

Single-account overall pass rate: 2.8% → 15.2% (+12.4pp). The delta is the 55 previously invisible Passed findings now correctly counted.

Branch is mergeable (no conflicts). No force push — new commits only.

@vivekmittal514 vivekmittal514 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Neil for providing the fixes.
I went through your changes and ran single and mulit account report with my accounts as well. It fixed the issue related to pass rate and severity updates.
These are the findings -

  1. Single account report didn't had any FinServ finding at all. When I ran in my single account, I saw a csv file generated in the S3 but those findings not included in the html file.
  2. FS-58 Check (finserv_assessments/app.py) -> It looks like this is always defaulting to Passed. Check if it is supposed to be informational?
  3. FS-22: Python crash on accounts that have Knowledge Bases
    File: finserv_assessments/app.py:1899-1902
    Observed in report: Account 469898429403 (which has Knowledge Bases) shows:
    COULD NOT ASSESS: Knowledge Base IAM Least Privilege Check — error: 'str' object has no attribute 'get'
    The other two accounts (no Knowledge Bases) produce a normal finding.
  4. FS-68: Emits Passed when zero REST APIs and zero WAF ACLs exist
    File: finservassessments/app.py:5348-5396
    Observed in report:
  • Accounts 056263463550 and 588344796265: "Found 0 REST API(s) with validators and 0 WAF ACL(s) with body-size rules" → Medium / Passed
  • Account 469898429403: Has REST APIs but none with validators → correctly shows Medium / Failed
    So the check works correctly when REST APIs _exist but aren't configured. It breaks only when there are no REST APIs at all.
  1. FS-27: IAM permission present in templates but still access-denied at runtime
    File: deployment/1-aiml-security-member-roles.yaml:280
    Observed in report: All 3 accounts show Low / N/A with:
    "Unable to list Automated Reasoning policies (access denied or service unavailable in this region)"
    The bedrock:ListAutomatedReasoningPolicies action is correctly present at line 280 of 1-aiml-security-member-roles.yaml and line 306 of aiml-security-single-account.yaml. The templates are right.

…ed-inventory refactor

Addresses PR aws-samples#23 round-3 review findings plus the pre-publish audit (REQ-2..REQ-15)
in the FinServ assessment Lambda, and bundles the behavior-preserving shared-inventory
refactor (the two live in the same regions of app.py, e.g. FS-68/FS-61, so they cannot
be cleanly separated into independent commits).

Correctness:
- FS-58: retag to advisory (N/A / Informational) instead of hardcoded Passed.
- FS-22: normalize single-statement-dict IAM policies (crash fix) and widen
  over-permissive detection (partial wildcards, Resource:"*", NotAction).
- FS-68: evidence-based body-size disposition (WAF SizeConstraint that can fire,
  or a validator model with maxLength) — validator presence alone no longer Passes.
- FS-61: AccessDenied on scheduler/events now yields COULD_NOT_ASSESS, not a false Failed.
- FS-27: clearer ARC access-denied guidance (re-deploy role / SCP / region); region
  text adds AWS GovCloud (US) and points to current AWS docs.
- FS-15 fails when no eval jobs exist; FS-30/35/40 become advisory; FS-56 gains a
  real XSS FAIL path; CLASSIC-tier guardrails stay Passed at control severity.

Severity methodology (REQ-6):
- SEVERITY_REGISTER keyed by finding-name; disposition rules (N/A->Informational,
  COULD_NOT_ASSESS->Low); FS-01 Shield->Low, WAF->Medium.
- Drift-guard test asserts emitted severity == register and no Critical.

Shared-inventory refactor (REQ-13 C3 / FU-3):
- collect_resource_inventory() gathers buckets/functions/guardrails/KBs/web-ACLs once
  per run, injected like permission_cache; collapses the 4x/6x/9x duplicate sweeps.
- Fixes latent WAFv2 (NextMarker) and S3 (ContinuationToken) pagination truncation —
  the only sanctioned finding-set change (accounts with >1 page now fully assessed).
- Golden-equivalence baseline + at-most-once + resilience + large-estate tests.

Tests: ported the full suite to functions/security/finserv_tests/ (CI-discoverable);
568 passing including the drift-guard. No new IAM actions introduced.

sim: aws-samples#23
…ti-account reports

REQ-1: FinServ findings were parsed but dropped before rendering (single-account)
and mislabeled as Bedrock (multi-account). Make FinServ first-class end to end:

- generate_consolidated_report/app.py: include "finserv" in service_stats,
  service_findings, and the service loop; thread FinServ kwargs into the template.
- report_template.py: FinServ nav item, #finserv section with its own filters and
  table, Findings-by-Service card, and global Service-filter option; the section is
  omitted when finserv_total == 0 (supports the disabled/REQ-7 case).
- consolidate_html_reports.py: categorize FS-* check IDs to "finserv" before the
  name fallback (fixes the multi-account Bedrock mislabeling). Make the account-files
  base path overridable via ACCOUNT_FILES_DIR (default /tmp/account-files unchanged)
  so the consolidator can be tested hermetically.
- Tests: test_generate_report.py asserts FinServ renders/omits; new
  test_consolidate_finserv.py asserts FS-* categorize to finserv (hermetic temp dir).

sim: aws-samples#23
…SL resilience

REQ-7 (optional FinServ):
- EnableFinServAssessment parameter (default "false") in the CodeBuild deployment
  templates; buildspec threads ENABLE_FINSERV into every start-execution input as
  enableFinServ. ASL FinServ branch starts with a Choice on $.enableFinServ
  (true -> invoke; default -> Skip Pass). Single ASL, Lambda always deployed.

REQ-12 (IAM):
- Add bedrock:ListTagsForResource to all three grant sources;
  bedrock:ListAutomatedReasoningPolicies + scheduler:ListSchedules to the SAM role;
  remove the dangling ecr:DescribeImageScanFindings.
- Remove invalid/redundant bedrock-agent:* actions across all five templates
  (Bedrock KB/DataSource/Flow use the bedrock: prefix; the correct grants were
  already present). cfn-lint clean x5.
- tests/test_iam_coverage.py: required-action coverage guard + a guard that fails on
  the invalid bedrock-agent: prefix (positive typo guard, since W3037 is suppressed).
- .cfnlintrc: scope/document the W3037 suppression now that no invalid actions remain.

REQ-13 C2 (resilience):
- Add Catch [States.ALL] -> "<svc> Assessment Incomplete" (Pass) to the Bedrock,
  SageMaker and AgentCore branches (FinServ already had one) so an uncaught failure
  in any branch no longer prevents the consolidated report. validate-state-machine-
  definition: OK, 0 diagnostics.

sim: aws-samples#23
…ciliation

- README: "How finding severities are determined" (methodology + ASFF mapping),
  the optional EnableFinServAssessment section incl. direct-sam-deploy behavior,
  single-region scope, and removal of the stale "FinServ CSV-only" limitation note.
- Reconcile severity columns in SECURITY_CHECKS_FINSERV_PART1/2/3 and the COMMON
  rubric against the register (legacy "Advisory" -> Informational disposition).
- REQ-15 hygiene: sanitize the real account ID in the tracked sample report CSV to
  a placeholder.

sim: aws-samples#23
The FinServ suite, severity drift-guard, and report-generator tests previously
lived outside tests/ and never ran in CI. Run them as separate pytest invocations
(the FinServ suite imports its app as top-level `app`, which collides with the
other assessment modules in a single session):
- upstream tests/ (coverage)
- functions/security/finserv_tests/ (coverage --cov-append)
- report-pipeline: test_consolidate_finserv.py + generate_consolidated_report
Allowlist the dummy AWS_SECRET_ACCESS_KEY test values for detect-secrets and drop
-x so all failures surface. Trigger paths updated for the root report files.

sim: aws-samples#23
@mehtadman87

Copy link
Copy Markdown
Author

Round 3 review fixes + shared-inventory refactor + pre-publish hardening

Pushed 5c17c6f..fcad42b (5 commits). This addresses all six round-3 findings, the three product/UX items, the pulled-in check-logic fixes, the pre-publish audit (A–E), and bundles the behavior-preserving shared-inventory refactor. Summary below; happy to walk through any item.

Round 3 findings

  1. FinServ not rendered (single-account) / mislabeled as Bedrock (multi-account). FinServ is now a first-class service across both generators — nav item, #finserv section with its own filters + table, Findings-by-Service card, global filter — and FS-* check IDs categorize to finserv (not Bedrock). The section is omitted when there are no FinServ findings.
  2. FS-58 always Passed. Retagged to advisory (N/A / Informational / ADVISORY:), with a sweep confirming no other FS check emits an unsubstantiated Passed.
  3. FS-22 crash on single-statement IAM policies. Statement is normalized to a list and non-dict entries are skipped; validated against a permission cache built from 250 live roles plus the exact crash repro.
  4. FS-68 Passed with nothing to assess. Added the N/A branch (no REST APIs and no WAF) and corrected the counts.
  5. FS-27 ARC access-denied. Reworded to name the real causes in order (re-deploy member role → SCP/permission boundary → region/feature availability); README documents re-deploying roles after IAM changes. Region text now includes AWS GovCloud (US) and links to current AWS docs.
  6. Severity methodology. Added a documented Likelihood × Impact model mapped to ASFF (docs/SECURITY_CHECKS_FINSERV_SEVERITY_METHODOLOGY.md), a per-finding SEVERITY_REGISTER (single source of truth) with a CI drift-guard, and applied the re-score — including FS-01 Shield High → Low and WAF → Medium. Four levels retained (no Critical this round). Before/after: High 58→51, High-N/A 7→0, Medium-N/A 13→1, Informational 22→43.

Check-logic fixes (REQ-10)

  • FS-15 fails when no evaluation jobs exist; FS-30/35/40 are advisory (API can't inspect dataset content); FS-56 gains a real XSS FAIL path (Common Rule Set inspection); FS-28/36/51/59 CLASSIC tier stays Passed at control severity (investigated — CLASSIC is not deprecated).

Pre-publish audit (A–E)

  • A — no unsubstantiated dispositions: FS-68 only Passed on an evidenced size control (a WAF body SizeConstraint that can actually fire given the inspection window / OversizeHandling, or a validator model with maxLength); FS-61 AccessDeniedCOULD_NOT_ASSESS, not a false Failed.
  • B — IAM completeness/parity: added bedrock:ListTagsForResource (all three sources), bedrock:ListAutomatedReasoningPolicies + scheduler:ListSchedules (SAM role), removed the dangling ecr:DescribeImageScanFindings, and removed invalid/redundant bedrock-agent:* actions (KB/DataSource/Flow use the bedrock: prefix; the correct grants were already present). New tests/test_iam_coverage.py guards both coverage and invalid prefixes.
  • C — enterprise scale: single-region scope documented; ASL Catch added to all four branches so one assessment's failure can't sink the consolidated report; the shared-inventory refactor (below) is the perf mitigation.
  • D — FS-22 detection widened (partial wildcards, Resource:"*", NotAction).
  • E — release hygiene: sample report account IDs sanitized to placeholders; no real account IDs in tracked files.

Shared-inventory refactor (behavior-preserving)

  • collect_resource_inventory() gathers buckets / Lambda functions / guardrails(+detail) / knowledge bases(+data sources) / web ACLs(+detail) once per run and injects them like permission_cache, collapsing the prior 4×/6×/9× duplicate enumerations and per-resource N+1 calls. An "at-most-once" harness enforces this.
  • Only sanctioned finding-set change: fixing latent WAFv2 (NextMarker) and S3 (ContinuationToken) pagination — accounts with >1 page of Web ACLs or >1 page / >10k buckets were previously truncated/under-assessed and are now fully covered. Everything else is guaranteed identical by a frozen golden-equivalence baseline + the unchanged severity drift-guard.
  • No new IAM actions (the collector calls the same List*/Get* the checks already used).

Verification

  • Tests now run in CI (previously the FinServ suite, drift-guard, and report tests lived outside tests/ and never executed): workspace 568 pass; fork CI-equivalent — upstream tests/ 221, finserv_tests/ 568, report-pipeline 7.
  • cfn-lint clean ×5; sam validate --lint valid ×2; sam build succeeds; validate-state-machine-definition OK (0 diagnostics); git defender no secrets; ASH reviewed.
  • Live (Wave 5, 3 accounts): FS-68 N/A/Failed/Passed across regions, FS-01 Low/Medium split, multi-account consolidation attributes all FS rows to finserv with zero mislabeling; all test resources torn down.

Optional FinServ is opt-in (EnableFinServAssessment, default false). Report UI re-design (REQ-8) and a few low-priority items are tracked in FOLLOWUPS.md.

@vivekmittal514 @agasthik — re-requesting review. Thanks both!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FinServAssessments] Add 69 FinServ GenAI risk checks (FS-01 to FS-69)

2 participants