Skip to content

Conversation

@akshay-nanda-sneo
Copy link
Contributor

@akshay-nanda-sneo akshay-nanda-sneo commented Dec 18, 2025

PR Type

Enhancement, Tests


Description

  • Add Animechan API integration endpoint for random anime quotes

  • Implement comprehensive error handling for upstream API failures

  • Define Pydantic models for anime quote response validation

  • Add test coverage for success and error scenarios


Diagram Walkthrough

flowchart LR
  Client["Client Request"]
  Endpoint["/anime/quote Endpoint"]
  APICall["requests.get to Animechan"]
  ErrorHandling["Error Handling<br/>Network/Status/JSON/Schema"]
  Validation["Pydantic Validation"]
  Response["AnimechanResponse"]
  Client -- "GET" --> Endpoint
  Endpoint -- "calls" --> APICall
  APICall -- "handles exceptions" --> ErrorHandling
  APICall -- "success path" --> Validation
  Validation --> Response
  ErrorHandling --> Response
Loading

File Walkthrough

Relevant files
Enhancement
main.py
Add Animechan API integration with error handling               

src/ssdlc_demo/main.py

  • Added requests import and HTTPException to FastAPI imports
  • Created four Pydantic models: AnimeInfo, CharacterInfo, AnimechanData,
    and AnimechanResponse for API response validation
  • Implemented /anime/quote GET endpoint that fetches random anime quotes
    from Animechan API
  • Added comprehensive error handling for network failures, non-200
    status codes, invalid JSON, and schema validation errors
+68/-1   
Tests
test_anime.py
Add comprehensive tests for anime quote endpoint                 

tests/test_anime.py

  • Created new test file with three test cases for the anime quote
    endpoint
  • Test successful quote retrieval with mocked API response
  • Test upstream API error handling when status code is 500
  • Test invalid JSON response handling from upstream API
  • Used monkeypatch to mock requests.get calls and TestClient for
    endpoint testing
+72/-0   

@qodo-code-review
Copy link

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing error logging: New error handling raises generic HTTPExceptions but does not log upstream failures (and
uses a broad except Exception), reducing actionable debugging context and potentially
swallowing important exception details.

Referred Code
try:
    res = requests.get(
        "https://api.animechan.io/v1/quotes/random",
        timeout=5,
    )
except requests.RequestException as exc:  # network, DNS, timeout
    raise HTTPException(
        status_code=502,
        detail="Upstream Animechan unavailable",
    ) from exc

if res.status_code != 200:
    raise HTTPException(
        status_code=502,
        detail="Animechan returned non-200 status",
    )

try:
    payload = res.json()
except ValueError as exc:
    raise HTTPException(


 ... (clipped 12 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: iac-scan

Failed stage: Checkov IaC scan [❌]

Failed test name: ""

Failure summary:

The GitHub Action failed in the bridgecrewio/checkov-action@v12 step because Checkov found Terraform
security/compliance policy violations in the infra directory (31 passed, 22 failed) and reported
them as ##[error], causing the step to exit non-zero.
Key failures include:
- ECR repository
aws_ecr_repository.this is not KMS-encrypted and allows mutable tags (CKV_AWS_136, CKV_AWS_51) in
/main.tf:21-25.
- Public subnets aws_subnet.public_a and aws_subnet.public_b assign public IPs by
default (CKV_AWS_130) in /main.tf:35-40 and /main.tf:42-47.
- Security groups (e.g.,
aws_security_group.alb) allow ingress from 0.0.0.0/0 on port 80, have overly permissive egress, and
lack rule descriptions (CKV_AWS_260, CKV_AWS_382, CKV_AWS_23) in /main.tf:69-87.
- ALB and listener
are configured for HTTP without HTTPS/redirect/logging/protection settings (e.g., CKV_AWS_2,
CKV_AWS_91, CKV2_AWS_20, CKV2_AWS_28) in /main.tf:89-95 and /main.tf:112-121.
- ECS service assigns
a public IP (CKV_AWS_333) in /main.tf:181-198.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

165:  Turn off this advice by setting config variable advice.detachedHead to false
166:  HEAD is now at 9fc3cc4 Merge 06cc0ad3b5505dd3575b14247525944ef8322125 into 58106c63981e5a103cccd084002d6995503ca4c8
167:  ##[endgroup]
168:  [command]/usr/bin/git log -1 --format=%H
169:  9fc3cc48c7494b47461c09341ccb9f07de44bfe4
170:  ##[group]Run bridgecrewio/checkov-action@v12
171:  with:
172:  directory: infra
173:  quiet: true
174:  framework: terraform
175:  download_external_modules: true
176:  output_format: sarif
177:  log_level: WARNING
178:  container_user: 0
179:  ##[endgroup]
180:  ##[command]/usr/bin/docker run --name ghcriobridgecrewiocheckov32495_ead4cc --label 3ec68a --workdir /github/workspace --rm -e "INPUT_DIRECTORY" -e "INPUT_QUIET" -e "INPUT_FRAMEWORK" -e "INPUT_DOWNLOAD_EXTERNAL_MODULES" -e "INPUT_FILE" -e "INPUT_CHECK" -e "INPUT_SKIP_CHECK" -e "INPUT_COMPACT" -e "INPUT_API-KEY" -e "INPUT_OUTPUT_BC_IDS" -e "INPUT_USE_ENFORCEMENT_RULES" -e "INPUT_SKIP_RESULTS_UPLOAD" -e "INPUT_SOFT_FAIL" -e "INPUT_SKIP_FRAMEWORK" -e "INPUT_EXTERNAL_CHECKS_DIRS" -e "INPUT_EXTERNAL_CHECKS_REPOS" -e "INPUT_OUTPUT_FORMAT" -e "INPUT_OUTPUT_FILE_PATH" -e "INPUT_ENABLE_SECRETS_SCAN_ALL_FILES" -e "INPUT_LOG_LEVEL" -e "INPUT_CONFIG_FILE" -e "INPUT_BASELINE" -e "INPUT_SOFT_FAIL_ON" -e "INPUT_HARD_FAIL_ON" -e "INPUT_CONTAINER_USER" -e "INPUT_DOCKER_IMAGE" -e "INPUT_DOCKERFILE_PATH" -e "INPUT_VAR_FILE" -e "INPUT_GITHUB_PAT" -e "INPUT_TFC_TOKEN" -e "INPUT_TF_REGISTRY_TOKEN" -e "INPUT_CKV_VALIDATE_SECRETS" -e "INPUT_VCS_BASE_URL" -e "INPUT_VCS_USERNAME" -e "INPUT_VCS_TOKEN" -e "INPUT_BITBUCKET_TOKEN" -e "INPUT_BITBUCKET_APP_PASSWORD" -e "INPUT_BITBUCKET_USERNAME" -e "INPUT_REPO_ROOT_FOR_PLAN_ENRICHMENT" -e "INPUT_DEEP_ANALYSIS" -e "INPUT_POLICY_METADATA_FILTER" -e "INPUT_POLICY_METADATA_FILTER_EXCEPTION" -e "INPUT_SKIP_PATH" -e "INPUT_SKIP_CVE_PACKAGE" -e "INPUT_SKIP_DOWNLOAD" -e "INPUT_PRISMA-API-URL" -e "API_KEY_VARIABLE" -e "GITHUB_PAT" -e "TFC_TOKEN" -e "TF_REGISTRY_TOKEN" -e "VCS_USERNAME" -e "VCS_BASE_URL" -e "VCS_TOKEN" -e "BITBUCKET_TOKEN" -e "BITBUCKET_USERNAME" -e "BITBUCKET_APP_PASSWORD" -e "PRISMA_API_URL" -e "CKV_VALIDATE_SECRETS" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e "ACTIONS_RESULTS_URL" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp":"/github/runner_temp" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/ssdlc-demo/ssdlc-demo":"/github/workspace" ghcr.io/bridgecrewio/checkov:3.2.495  "" "infra" "" "" "" "true" "" "" "" "" "terraform" "" "" "" "sarif" "" "true" "" "WARNING" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "--user 0"
181:  BC_FROM_BRANCH=feat/anime_api_integration
...

188:  BC_AUTHOR_URL=https://github.com/akshay-nanda-sneo
189:  BC_RUN_ID=40
190:  BC_RUN_URL=https://github.com/StatusNeo/ssdlc-demo/actions/runs/20341079345
191:  BC_REPOSITORY_URL=https://github.com/StatusNeo/ssdlc-demo
192:  running checkov on directory: infra
193:  checkov -d infra    --quiet         --output sarif   --download-external-modules true    --framework terraform         
194:  _               _
195:  ___| |__   ___  ___| | _______   __
196:  / __| '_ \ / _ \/ __| |/ / _ \ \ / /
197:  | (__| | | |  __/ (__|   < (_) \ V /
198:  \___|_| |_|\___|\___|_|\_\___/ \_/
199:  By Prisma Cloud | version: 3.2.494 
200:  Update available 3.2.494 -> 3.2.495
201:  Run pip3 install -U checkov to update 
202:  terraform scan results:
203:  Passed checks: 31, Failed checks: 22, Skipped checks: 0
204:  Check: CKV_AWS_136: "Ensure that ECR repositories are encrypted using KMS"
205:  FAILED for resource: aws_ecr_repository.this
206:  ##[error]	File: /main.tf:21-25
207:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/ensure-that-ecr-repositories-are-encrypted
208:  21 | resource "aws_ecr_repository" "this" {
209:  22 |   name                 = local.name
210:  23 |   image_tag_mutability = "MUTABLE"
211:  24 |   image_scanning_configuration { scan_on_push = true }
212:  25 | }
213:  Check: CKV_AWS_51: "Ensure ECR Image Tags are immutable"
214:  FAILED for resource: aws_ecr_repository.this
215:  ##[error]	File: /main.tf:21-25
216:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/bc-aws-general-24
217:  21 | resource "aws_ecr_repository" "this" {
218:  22 |   name                 = local.name
219:  23 |   image_tag_mutability = "MUTABLE"
220:  24 |   image_scanning_configuration { scan_on_push = true }
221:  25 | }
222:  Check: CKV_AWS_130: "Ensure VPC subnets do not assign public IP by default"
223:  FAILED for resource: aws_subnet.public_a
224:  ##[error]	File: /main.tf:35-40
225:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-vpc-subnets-do-not-assign-public-ip-by-default
226:  35 | resource "aws_subnet" "public_a" {
227:  36 |   vpc_id                  = aws_vpc.this.id
228:  37 |   cidr_block              = "10.0.1.0/24"
229:  38 |   map_public_ip_on_launch = true
230:  39 |   availability_zone       = data.aws_availability_zones.available.names[0]
231:  40 | }
232:  Check: CKV_AWS_130: "Ensure VPC subnets do not assign public IP by default"
233:  FAILED for resource: aws_subnet.public_b
234:  ##[error]	File: /main.tf:42-47
235:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-vpc-subnets-do-not-assign-public-ip-by-default
236:  42 | resource "aws_subnet" "public_b" {
237:  43 |   vpc_id                  = aws_vpc.this.id
238:  44 |   cidr_block              = "10.0.2.0/24"
239:  45 |   map_public_ip_on_launch = true
240:  46 |   availability_zone       = data.aws_availability_zones.available.names[1]
241:  47 | }
242:  Check: CKV_AWS_260: "Ensure no security groups allow ingress from 0.0.0.0:0 to port 80"
243:  FAILED for resource: aws_security_group.alb
244:  ##[error]	File: /main.tf:69-87
245:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-aws-security-groups-do-not-allow-ingress-from-00000-to-port-80
...

251:  74 |   ingress {
252:  75 |     from_port   = 80
253:  76 |     to_port     = 80
254:  77 |     protocol    = "tcp"
255:  78 |     cidr_blocks = ["0.0.0.0/0"]
256:  79 |   }
257:  80 | 
258:  81 |   egress {
259:  82 |     from_port   = 0
260:  83 |     to_port     = 0
261:  84 |     protocol    = "-1"
262:  85 |     cidr_blocks = ["0.0.0.0/0"]
263:  86 |   }
264:  87 | }
265:  Check: CKV_AWS_23: "Ensure every security group and rule has a description"
266:  FAILED for resource: aws_security_group.alb
267:  ##[error]	File: /main.tf:69-87
268:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/networking-31
...

274:  74 |   ingress {
275:  75 |     from_port   = 80
276:  76 |     to_port     = 80
277:  77 |     protocol    = "tcp"
278:  78 |     cidr_blocks = ["0.0.0.0/0"]
279:  79 |   }
280:  80 | 
281:  81 |   egress {
282:  82 |     from_port   = 0
283:  83 |     to_port     = 0
284:  84 |     protocol    = "-1"
285:  85 |     cidr_blocks = ["0.0.0.0/0"]
286:  86 |   }
287:  87 | }
288:  Check: CKV_AWS_382: "Ensure no security groups allow egress from 0.0.0.0:0 to port -1"
289:  FAILED for resource: aws_security_group.alb
290:  ##[error]	File: /main.tf:69-87
291:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/bc-aws-382
...

297:  74 |   ingress {
298:  75 |     from_port   = 80
299:  76 |     to_port     = 80
300:  77 |     protocol    = "tcp"
301:  78 |     cidr_blocks = ["0.0.0.0/0"]
302:  79 |   }
303:  80 | 
304:  81 |   egress {
305:  82 |     from_port   = 0
306:  83 |     to_port     = 0
307:  84 |     protocol    = "-1"
308:  85 |     cidr_blocks = ["0.0.0.0/0"]
309:  86 |   }
310:  87 | }
311:  Check: CKV_AWS_150: "Ensure that Load Balancer has deletion protection enabled"
312:  FAILED for resource: aws_lb.this
313:  ##[error]	File: /main.tf:89-95
314:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/bc-aws-150
315:  89 | resource "aws_lb" "this" {
316:  90 |   name               = "${local.name}-alb"
317:  91 |   internal           = false
318:  92 |   load_balancer_type = "application"
319:  93 |   security_groups    = [aws_security_group.alb.id]
320:  94 |   subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]
321:  95 | }
322:  Check: CKV_AWS_131: "Ensure that ALB drops HTTP headers"
323:  FAILED for resource: aws_lb.this
324:  ##[error]	File: /main.tf:89-95
325:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-that-alb-drops-http-headers
326:  89 | resource "aws_lb" "this" {
327:  90 |   name               = "${local.name}-alb"
328:  91 |   internal           = false
329:  92 |   load_balancer_type = "application"
330:  93 |   security_groups    = [aws_security_group.alb.id]
331:  94 |   subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]
332:  95 | }
333:  Check: CKV_AWS_91: "Ensure the ELBv2 (Application/Network) has access logging enabled"
334:  FAILED for resource: aws_lb.this
335:  ##[error]	File: /main.tf:89-95
336:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-logging-policies/bc-aws-logging-22
337:  89 | resource "aws_lb" "this" {
338:  90 |   name               = "${local.name}-alb"
339:  91 |   internal           = false
340:  92 |   load_balancer_type = "application"
341:  93 |   security_groups    = [aws_security_group.alb.id]
342:  94 |   subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]
343:  95 | }
344:  Check: CKV_AWS_2: "Ensure ALB protocol is HTTPS"
345:  FAILED for resource: aws_lb_listener.http
346:  ##[error]	File: /main.tf:112-121
347:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/networking-29
348:  112 | resource "aws_lb_listener" "http" {
349:  113 |   load_balancer_arn = aws_lb.this.arn
350:  114 |   port              = 80
351:  115 |   protocol          = "HTTP"
352:  116 | 
353:  117 |   default_action {
354:  118 |     type             = "forward"
355:  119 |     target_group_arn = aws_lb_target_group.this.arn
356:  120 |   }
357:  121 | }
358:  Check: CKV_AWS_65: "Ensure container insights are enabled on ECS cluster"
359:  FAILED for resource: aws_ecs_cluster.this
360:  ##[error]	File: /main.tf:123-125
361:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-logging-policies/bc-aws-logging-11
362:  123 | resource "aws_ecs_cluster" "this" {
363:  124 |   name = local.name
364:  125 | }
365:  Check: CKV_AWS_23: "Ensure every security group and rule has a description"
366:  FAILED for resource: aws_security_group.service
367:  ##[error]	File: /main.tf:144-161
368:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/networking-31
...

373:  148 |   ingress {
374:  149 |     from_port       = 8000
375:  150 |     to_port         = 8000
376:  151 |     protocol        = "tcp"
377:  152 |     security_groups = [aws_security_group.alb.id]
378:  153 |   }
379:  154 | 
380:  155 |   egress {
381:  156 |     from_port   = 0
382:  157 |     to_port     = 0
383:  158 |     protocol    = "-1"
384:  159 |     cidr_blocks = ["0.0.0.0/0"]
385:  160 |   }
386:  161 | }
387:  Check: CKV_AWS_382: "Ensure no security groups allow egress from 0.0.0.0:0 to port -1"
388:  FAILED for resource: aws_security_group.service
389:  ##[error]	File: /main.tf:144-161
390:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/bc-aws-382
...

395:  148 |   ingress {
396:  149 |     from_port       = 8000
397:  150 |     to_port         = 8000
398:  151 |     protocol        = "tcp"
399:  152 |     security_groups = [aws_security_group.alb.id]
400:  153 |   }
401:  154 | 
402:  155 |   egress {
403:  156 |     from_port   = 0
404:  157 |     to_port     = 0
405:  158 |     protocol    = "-1"
406:  159 |     cidr_blocks = ["0.0.0.0/0"]
407:  160 |   }
408:  161 | }
409:  Check: CKV_AWS_336: "Ensure ECS containers are limited to read-only access to root filesystems"
410:  FAILED for resource: aws_ecs_task_definition.this
411:  ##[error]	File: /main.tf:163-179
412:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/bc-aws-336
...

416:  166 |   cpu                      = "256"
417:  167 |   memory                   = "512"
418:  168 |   requires_compatibilities = ["FARGATE"]
419:  169 |   execution_role_arn       = aws_iam_role.task_execution.arn
420:  170 |   container_definitions = jsonencode([
421:  171 |     {
422:  172 |       name  = local.name
423:  173 |       image = "${aws_ecr_repository.this.repository_url}:${var.image_tag}"
424:  174 |       portMappings = [{ containerPort = 8000, hostPort = 8000, protocol = "tcp" }]
425:  175 |       essential = true
426:  176 |       environment = [{ name = "PORT", value = "8000" }]
427:  177 |     }
428:  178 |   ])
429:  179 | }
430:  Check: CKV_AWS_333: "Ensure ECS services do not have public IP addresses assigned to them automatically"
431:  FAILED for resource: aws_ecs_service.this
432:  ##[error]	File: /main.tf:181-198
433:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-logging-policies/bc-aws-333
...

438:  185 |   desired_count   = 1
439:  186 |   launch_type     = "FARGATE"
440:  187 |   network_configuration {
441:  188 |     subnets          = [aws_subnet.public_a.id, aws_subnet.public_b.id]
442:  189 |     security_groups  = [aws_security_group.service.id]
443:  190 |     assign_public_ip = true
444:  191 |   }
445:  192 |   load_balancer {
446:  193 |     target_group_arn = aws_lb_target_group.this.arn
447:  194 |     container_name   = local.name
448:  195 |     container_port   = 8000
449:  196 |   }
450:  197 |   depends_on = [aws_lb_listener.http]
451:  198 | } 
452:  Check: CKV_AWS_378: "Ensure AWS Load Balancer doesn't use HTTP protocol"
453:  FAILED for resource: aws_lb_target_group.this
454:  ##[error]	File: /main.tf:97-110
455:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/bc-aws-378
456:  97  | resource "aws_lb_target_group" "this" {
457:  98  |   name     = "${local.name}-tg"
458:  99  |   port     = 8000
459:  100 |   protocol = "HTTP"
460:  101 |   vpc_id   = aws_vpc.this.id
461:  102 |   health_check {
462:  103 |     path                = "/health"
463:  104 |     healthy_threshold   = 2
464:  105 |     unhealthy_threshold = 3
465:  106 |     timeout             = 5
466:  107 |     interval            = 30
467:  108 |     matcher             = "200"
468:  109 |   }
469:  110 | }
470:  Check: CKV2_AWS_28: "Ensure public facing ALB are protected by WAF"
471:  FAILED for resource: aws_lb.this
472:  ##[error]	File: /main.tf:89-95
473:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-public-facing-alb-are-protected-by-waf
474:  89 | resource "aws_lb" "this" {
475:  90 |   name               = "${local.name}-alb"
476:  91 |   internal           = false
477:  92 |   load_balancer_type = "application"
478:  93 |   security_groups    = [aws_security_group.alb.id]
479:  94 |   subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]
480:  95 | }
481:  Check: CKV2_AWS_12: "Ensure the default security group of every VPC restricts all traffic"
482:  FAILED for resource: aws_vpc.this
483:  ##[error]	File: /main.tf:27-29
484:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/networking-4
485:  27 | resource "aws_vpc" "this" {
486:  28 |   cidr_block = "10.0.0.0/16"
487:  29 | }
488:  Check: CKV2_AWS_11: "Ensure VPC flow logging is enabled in all VPCs"
489:  FAILED for resource: aws_vpc.this
490:  ##[error]	File: /main.tf:27-29
491:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-logging-policies/logging-9-enable-vpc-flow-logging
492:  27 | resource "aws_vpc" "this" {
493:  28 |   cidr_block = "10.0.0.0/16"
494:  29 | }
495:  Check: CKV2_AWS_20: "Ensure that ALB redirects HTTP requests into HTTPS ones"
496:  FAILED for resource: aws_lb.this
497:  ##[error]	File: /main.tf:89-95
498:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-networking-policies/ensure-that-alb-redirects-http-requests-into-https-ones
499:  89 | resource "aws_lb" "this" {
500:  90 |   name               = "${local.name}-alb"
501:  91 |   internal           = false
502:  92 |   load_balancer_type = "application"
503:  93 |   security_groups    = [aws_security_group.alb.id]
504:  94 |   subnets            = [aws_subnet.public_a.id, aws_subnet.public_b.id]
505:  95 | }
506:  Check: CKV_AWS_103: "Ensure that load balancer is using at least TLS 1.2"
507:  FAILED for resource: aws_lb_listener.http
508:  ##[error]	File: /main.tf:112-121
509:  Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/bc-aws-general-43

@qodo-code-review
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect API response model

Correct the Pydantic models to match the actual flat JSON structure returned by
the Animechan API, which includes id, quote, anime, and character fields.

src/ssdlc_demo/main.py [31-39]

-class AnimechanData(BaseModel):
-    content: str
-    anime: AnimeInfo
-    character: CharacterInfo
+class AnimechanResponse(BaseModel):
+    id: int
+    quote: str
+    anime: str
+    character: str
 
-
-class AnimechanResponse(BaseModel):
-    status: str
-    data: AnimechanData
-
  • Apply / Chat
Suggestion importance[1-10]: 10

__

Why: This suggestion correctly identifies a critical bug where the Pydantic models do not match the actual external API schema, which would cause the endpoint to fail on every real request.

High
High-level
Abstract external API logic from endpoint

Abstract the Animechan API interaction logic from the FastAPI endpoint into a
dedicated service or client module. This improves separation of concerns, making
the code more reusable and easier to test.

Examples:

src/ssdlc_demo/main.py [54-94]
def get_random_anime_quote() -> AnimechanResponse:
    """Fetch a random anime quote from Animechan and return it.

    Docs: https://animechan.io/
    Endpoint used: https://api.animechan.io/v1/quotes/random
    """
    try:
        res = requests.get(
            "https://api.animechan.io/v1/quotes/random",
            timeout=5,

 ... (clipped 31 lines)

Solution Walkthrough:

Before:

# src/ssdlc_demo/main.py

@app.get("/anime/quote", response_model=AnimechanResponse)
def get_random_anime_quote() -> AnimechanResponse:
    try:
        res = requests.get("https://api.animechan.io/v1/quotes/random")
    except requests.RequestException as exc:
        raise HTTPException(status_code=502, detail="Upstream unavailable")

    if res.status_code != 200:
        raise HTTPException(status_code=502, detail="Non-200 status")

    try:
        payload = res.json()
        validated = AnimechanResponse.model_validate(payload)
    except (ValueError, Exception) as exc:
        raise HTTPException(status_code=502, detail="Invalid response from upstream")

    return validated

After:

# services/animechan_client.py (new file)
def get_random_quote():
    try:
        res = requests.get("https://api.animechan.io/v1/quotes/random")
        res.raise_for_status()
        return AnimechanResponse.model_validate(res.json())
    except (requests.RequestException, ValueError, Exception) as e:
        raise ServiceError("Failed to fetch quote from Animechan") from e

# src/ssdlc_demo/main.py (modified)
@app.get("/anime/quote", response_model=AnimechanResponse)
def get_random_anime_quote() -> AnimechanResponse:
    try:
        return animechan_client.get_random_quote()
    except ServiceError as e:
        raise HTTPException(status_code=502, detail=str(e))
Suggestion importance[1-10]: 7

__

Why: This is a strong architectural suggestion that correctly identifies tight coupling and proposes a standard design pattern to improve modularity, testability, and reusability.

Medium
General
use async http client

Replace the synchronous requests.get call with an asynchronous client like httpx
to prevent blocking FastAPI's event loop during the external API call.

src/ssdlc_demo/main.py [61-64]

-res = requests.get(
-    "https://api.animechan.io/v1/quotes/random",
-    timeout=5,
-)
+import httpx
 
+async with httpx.AsyncClient() as client:
+    res = await client.get(
+        "https://api.animechan.io/v1/quotes/random",
+        timeout=5,
+    )
+
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that using a synchronous library like requests in an async framework like FastAPI is not ideal and can block the event loop, proposing a valid performance improvement.

Medium
catch specific validation error

Refine the error handling by catching the specific pydantic.ValidationError
instead of a broad Exception to make schema validation failures more precise.

src/ssdlc_demo/main.py [86-92]

+from pydantic import ValidationError
+
 try:
     validated = AnimechanResponse.model_validate(payload)
-except Exception as exc:
+except ValidationError as exc:
     raise HTTPException(
         status_code=502,
         detail="Unexpected Animechan schema",
     ) from exc
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This is a valid and important improvement for error handling, making the code more robust by catching the specific ValidationError from Pydantic instead of a generic Exception.

Medium
  • More

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.

2 participants