DEV Community

Cover image for Block AI-Generated Infrastructure Mistakes in CI Before They Hit Production
Siddharth Pandey
Siddharth Pandey

Posted on

Block AI-Generated Infrastructure Mistakes in CI Before They Hit Production

Last Tuesday your team merged a PR with 40 lines of clean TypeScript. Code review passed — the function was readable, typed correctly, and had a unit test. Twenty minutes after deploy, CloudWatch alerted: your Orders table was being fully scanned on every request. The merged function called .scan() without a partition key filter. Claude Code wrote it; nobody caught it because nobody — not the reviewer, not the tests, not the linter — had any way to know that Orders has 8 million items.

This is the gap infrawise check fills. It's a CI step that reads your actual DynamoDB schemas, PostgreSQL indexes, and query patterns, then fails the build when AI-generated code introduces anti-patterns against your real infrastructure.

The Gap Between Code Review and Infrastructure Reality

Static analysis tools like ESLint, TypeScript, and Semgrep analyze the code. They can't tell you that listAllOrders() is doing a full table scan, or that your PostgreSQL users table has no indexes and the new query will degrade from milliseconds to seconds as data grows.

AI assistants compound this. They write syntactically correct code that compiles and passes tests — but they're working from source files, not live infrastructure. They don't know your table's partition key distribution. They don't know you already have a GSI on status. They generate code against an imagined infrastructure and get it wrong in ways that only surface at scale.

The consequence isn't just performance. A DynamoDB full scan in a high-traffic Lambda reads capacity units proportional to table size on every invocation. A missing index causes query times to grow linearly with rows. Unit tests won't catch either of these; they show up in production.

infrawise check — a Build Step That Knows Your Tables

infrawise check runs a fresh analysis of your codebase and cloud infrastructure, then sets exit code 1 when blocking findings exist. That exit code is all a CI pipeline needs.

infrawise check
Enter fullscreen mode Exit fullscreen mode

Actual output on violations:

  Blocking findings  2 at or above high

  1.  HIGH   Full table scan detected on DynamoDB table "Orders"
             The table "Orders" is being scanned without any filter, which reads every item.
             → Replace Scan with a Query operation using a partition key or GSI.

  2.  HIGH   Full table scan detected on DynamoDB table "Sessions"
             The table "Sessions" is being scanned without any filter. Called from: cleanupExpiredSessions
             → Replace Scan with a Query operation using a partition key or GSI.

  ✗ Check failed
    2 high+ finding(s) must be resolved before deploy
Enter fullscreen mode Exit fullscreen mode

Findings reference the exact table name and caller function. The recommendation isn't generic — it points to the specific operation to replace.

Add it to GitHub Actions in one step:

- name: Infrastructure check
  run: infrawise check --fail-on high
Enter fullscreen mode Exit fullscreen mode

--fail-on high means only HIGH findings block the build. Medium and low appear in the log but don't fail the step. Use --fail-on medium for stricter enforcement.

Available options for --fail-on: high (default), medium, low.

Writing infrawise.yaml for CI

In local development, infrawise start --claude generates the config and connects your editor. In CI, commit the config and pass credentials through environment variables:

project: payments-service

aws:
  profile: default
  region: us-east-1

dynamodb:
  enabled: true
  includeTables:
    - Orders
    - Users

postgres:
  enabled: true
  connectionString: postgresql://infrawise_ro:${DB_PASSWORD}@host:5432/mydb

lambda:
  enabled: true
Enter fullscreen mode Exit fullscreen mode

The ${DB_PASSWORD} substitution keeps credentials out of the committed config — infrawise expands environment variables at runtime. Set DB_PASSWORD as a CI secret.

For AWS access, infrawise is read-only. The minimum IAM policy it needs for DynamoDB is dynamodb:ListTables and dynamodb:DescribeTable. Create an IAM role for CI with just these permissions and configure OIDC trust for your GitHub Actions runner.

What Blocks, What Warns, What Can Wait

Not every finding warrants a hard block. A starting policy:

Block on HIGH: Full table scans, hotspot patterns where multiple functions hammer the same partition key. These have immediate cost and availability impact.

Warn on MEDIUM: Tables with no GSIs queried by multiple functions, missing indexes on filterable columns in PostgreSQL. These degrade as data grows — log them and schedule remediation.

Log only for LOW: Non-critical index suggestions, rarely-queried pattern gaps. Useful signal for the next sprint.

Start with --fail-on high. Once the team has cleared existing HIGH findings, tighten to --fail-on medium. The goal is catching regressions — new findings introduced by merged code — not blocking work on pre-existing debt.

The includeTables field in infrawise.yaml lets you scope analysis to specific tables. Roll out the gate incrementally: start with the tables your AI assistant touches most.

Conclusion

The table scan that paged your on-call engineer wasn't wrong code. It was a gap in tooling — your pipeline understood TypeScript but not DynamoDB. infrawise check closes that gap by giving CI the same infrastructure context your AI assistant should have had when it wrote the query.

One step in the pipeline. One committed config file. The build fails when generated code would fail in production.

GitHub · npm

Key Takeaways

  • AI-generated code passes code review and unit tests but can introduce DynamoDB full scans and missing index queries that only appear at scale
  • infrawise check runs deterministic infrastructure analysis and exits non-zero on blocking findings — drop-in CI gate
  • --fail-on high|medium|low controls what severity blocks the build; high is the default
  • infrawise.yaml uses ${ENV_VAR} substitution so database passwords never need to be committed
  • infrawise is read-only — minimum IAM for DynamoDB is dynamodb:ListTables and dynamodb:DescribeTable

Top comments (0)