Claude Skill

meta-reviewing-infra-reviewing

Infrastructure code review patterns. Use when reviewing CI/CD workflows, Dockerfiles, deployment configs, and IaC. Covers supply-chain pinning, secret exposure, container hygiene, least-privilege permissions, and deployment safety.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download agents-inc-skills-dist_plugins_meta-reviewing-infra-reviewing_skills_meta-reviewing-infra-reviewing-3a51ef5.zip · 6 KB
Part of agents-inc/skills — 130 skills

Install

skills CLI npx skills add https://github.com/agents-inc/skills/tree/main/dist/plugins/meta-reviewing-infra-reviewing/skills/meta-reviewing-infra-reviewing
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install agents-inc-skills@llmmart
Git git clone https://github.com/agents-inc/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole agents-inc/skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Infrastructure Code Review Patterns

Quick Guide: When a diff touches operational code, grep it for secrets first - hardcoded credentials are always blocking. Verify third-party actions are pinned to SHAs and base images to digests or versions, containers run as non-root, workflow permissions are least-privilege, and secrets never pass through build args, logs, or artifacts. Judge deployment ceremony against what the diff actually deploys.


<critical_requirements>

CRITICAL: Before Reviewing Infrastructure Code

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST verify no secrets are hardcoded - scan the diff for tokens, API keys, passwords, and connection strings)

(You MUST verify third-party CI actions are pinned to full SHA hashes, not mutable tags like @v4 or @main)

(You MUST verify secrets never pass through build args, echo/log lines, or uploaded artifacts)

(You MUST verify production Dockerfiles the diff adds or changes set a non-root USER and pin their base image)

(You MUST verify workflow permissions are declared least-privilege, not inherited write-all)

</critical_requirements>


Auto-detection: review workflow, CI PR review, Dockerfile review, pipeline review, deployment config review, GitHub Actions review, IaC review, terraform review

When to use:

  • Reviewing diffs that touch CI/CD workflows (GitHub Actions, GitLab CI)
  • Reviewing Dockerfiles, .dockerignore, or compose files
  • Reviewing deployment configs (Kubernetes, Helm, platform configs)
  • Reviewing IaC (Terraform, Pulumi) or release/build scripts
  • Reviewing package-manager and lockfile changes with supply-chain impact

When NOT to use:

  • When implementing infrastructure (use the relevant infra implementation skill)
  • For application code in the same diff (use the web/api reviewing skills)
  • For incident response or live operations questions

Key patterns covered:

  • Supply-chain pinning: actions, base images, lockfiles
  • Secret exposure across build args, logs, artifacts, and ignore files
  • Dockerfile hygiene: non-root, multi-stage, layer order
  • CI/CD least-privilege permissions and pipeline correctness
  • Deployment safety scoped to what the diff deploys

Detailed Resources:




<decision_framework>

Decision Framework

Severity Classification for Infra Issues

Is this a security defect the diff introduces?
├─ Hardcoded secret, or secret through build arg/log/artifact → MUST FIX
├─ Third-party action on a mutable tag → MUST FIX
├─ pull_request_target executing PR head code with secrets → MUST FIX
├─ Write-all permissions on a workflow that needs read → MUST FIX
├─ Production container running as root → MUST FIX
└─ NO → Is it an operational-correctness gap?
    ├─ Base image on `latest` / installs ignoring the lockfile → SHOULD FIX
    ├─ Deploy job without concurrency guard → SHOULD FIX
    ├─ New env var missing from one environment → SHOULD FIX
    ├─ Cache-hostile Dockerfile layer order → SHOULD FIX
    ├─ New production service without health checks or limits → SHOULD FIX
    └─ NO → Is it a genuine enhancement?
        ├─ Slimmer base image where size demonstrably matters → NICE TO HAVE
        ├─ Faster caching for an already-fast job → DON'T MENTION
        ├─ K8s-grade ceremony for a workflow that deploys nothing → DON'T MENTION
        └─ Tool preferences (compose vs k8s, npm vs bun) → DON'T MENTION

</decision_framework>


<red_flags>

RED FLAGS

High Priority Issues (Must Fix):

  • Any credential literal in the diff (grep for token, key, password, secret, connection-string shapes)
  • uses: third-party/action@v3 / @main / @master
  • ARG/ENV carrying secrets in a Dockerfile
  • Missing permissions: on workflows that handle untrusted input
  • pull_request_target + actions/checkout of the PR head
  • Production Dockerfile with no USER directive

Medium Priority Issues (Should Fix):

  • FROM node:latest or digest-less base images on deploy paths
  • npm install in CI where npm ci belongs
  • Static cache keys that never invalidate
  • Deploy steps with no concurrency group
  • Missing .dockerignore alongside a new Dockerfile
  • Debug steps that env-dump or set -x around secret use

Common Mistakes:

  • Pinning first-party actions to SHA while leaving the third-party one on a tag (backwards priority)
  • Adding a secret to one environment and assuming the others inherit it
  • Copying source before manifests and "fixing" slow builds by skipping the lockfile
  • needs: chains that let deploy start when only lint passed
  • Treating terraform apply in CI as safe because plan passed locally against different state

Gotchas & Edge Cases:

  • Docker build args persist in docker history even when unset afterwards
  • Rewritten tags pass uses: resolution - only SHAs are immutable
  • Composite actions inherit and can leak the caller's env
  • GITHUB_TOKEN default permissions differ per org setting - declaring them is the only portable truth
  • Alpine images lack glibc; native modules that built fine on debian-slim fail there at runtime
  • SIGKILL follows SIGTERM after the grace period - cleanup that takes longer than the grace period never finishes

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md

(You MUST verify no secrets are hardcoded - scan the diff for tokens, API keys, passwords, and connection strings)

(You MUST verify third-party CI actions are pinned to full SHA hashes, not mutable tags like @v4 or @main)

(You MUST verify secrets never pass through build args, echo/log lines, or uploaded artifacts)

(You MUST verify production Dockerfiles the diff adds or changes set a non-root USER and pin their base image)

(You MUST verify workflow permissions are declared least-privilege, not inherited write-all)

Failure to catch these issues will result in leaked credentials, supply-chain compromise executing in CI with secrets in scope, and deploys that fail only in production.

</critical_reminders>

Files (skills)
  • examples
    • core.md 3 KB
      # Infra Reviewing - Core Examples
      
      > Good/bad infrastructure patterns to look for during review. See [../SKILL.md](../SKILL.md) for checklists and the severity framework.
      
      ---
      
      ## SHA-Pinned Actions
      
      ```yaml
      # Must Fix: both mutable - the tag can be rewritten to point at hostile code
      - uses: actions/checkout@main
      - uses: cool-org/setup-thing@v2
      
      # Good: immutable SHAs; the comment keeps the version readable and bumpable
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      - uses: cool-org/setup-thing@5c1f9e1a1c9436c9e73d29b3a1a8d9d5f7f0e2ab # v2.3.0
      ```
      
      ---
      
      ## Least-Privilege Workflow Permissions
      
      ```yaml
      # Must Fix: no permissions block - the job inherits whatever the org default grants,
      # often contents: write, on a workflow that only reads
      name: test
      on: pull_request
      jobs:
        test:
          runs-on: ubuntu-latest
      
      # Good: read by default, write scopes named one by one where a job needs them
      name: test
      on: pull_request
      permissions:
        contents: read
      jobs:
        test:
          runs-on: ubuntu-latest
        comment:
          permissions:
            contents: read
            pull-requests: write
      ```
      
      ---
      
      ## Secrets Out of Build Args and Logs
      
      ```dockerfile
      # Must Fix: `docker history` on the pushed image prints the token forever
      ARG API_TOKEN
      RUN curl -H "Authorization: Bearer ${API_TOKEN}" https://registry.example.com/setup
      
      # Good: BuildKit secret mount - present during the RUN, absent from every layer
      RUN --mount=type=secret,id=api_token \
          curl -H "Authorization: Bearer $(cat /run/secrets/api_token)" https://registry.example.com/setup
      ```
      
      ```yaml
      # Must Fix: debug line ships the secret to the log archive
      - run: echo "deploying with key ${{ secrets.DEPLOY_KEY }}"
      
      # Good: log the fact, never the value
      - run: echo "deploying to ${ENVIRONMENT}"
      ```
      
      ---
      
      ## Non-Root, Cache-Friendly Dockerfile
      
      ```dockerfile
      # Should Fix x3: root user, cache busted by every source change, build tools shipped to prod
      FROM node:22
      COPY . .
      RUN npm install && npm run build
      CMD ["node", "dist/server.js"]
      
      # Good: staged, manifest-first, unprivileged runtime
      FROM node:22.12-slim AS build
      WORKDIR /app
      COPY package.json package-lock.json ./
      RUN npm ci
      COPY . .
      RUN npm run build
      
      FROM node:22.12-slim
      WORKDIR /app
      COPY package.json package-lock.json ./
      RUN npm ci --omit=dev
      COPY --from=build /app/dist ./dist
      USER node
      CMD ["node", "dist/server.js"]
      ```
      
      ---
      
      ## Deploy Concurrency and Job Ordering
      
      ```yaml
      # Should Fix: two merges in quick succession deploy in whichever order the runners finish
      jobs:
        deploy:
          runs-on: ubuntu-latest
      
      # Good: one deploy at a time, later run supersedes; and deploy waits for the suite
      concurrency:
        group: deploy-production
        cancel-in-progress: false
      jobs:
        deploy:
          needs: [lint, test, e2e]
          runs-on: ubuntu-latest
      ```
      
      ---
      
      ## Lockfile-Faithful Installs
      
      ```yaml
      # Should Fix: npm install may resolve different versions than the lockfile CI just checked out
      - run: npm install && npm test
      
      # Good: exactly the committed dependency tree, or fail
      - run: npm ci
      - run: npm test
      ```
      
  • SKILL.md 13.5 KB
    ---
    name: meta-reviewing-infra-reviewing
    description: Infrastructure code review patterns. Use when reviewing CI/CD workflows, Dockerfiles, deployment configs, and IaC. Covers supply-chain pinning, secret exposure, container hygiene, least-privilege permissions, and deployment safety.
    ---
    
    # Infrastructure Code Review Patterns
    
    > **Quick Guide:** When a diff touches operational code, grep it for secrets first - hardcoded credentials are always blocking. Verify third-party actions are pinned to SHAs and base images to digests or versions, containers run as non-root, workflow permissions are least-privilege, and secrets never pass through build args, logs, or artifacts. Judge deployment ceremony against what the diff actually deploys.
    
    ---
    
    <critical_requirements>
    
    ## CRITICAL: Before Reviewing Infrastructure Code
    
    > **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
    
    **(You MUST verify no secrets are hardcoded - scan the diff for tokens, API keys, passwords, and connection strings)**
    
    **(You MUST verify third-party CI actions are pinned to full SHA hashes, not mutable tags like `@v4` or `@main`)**
    
    **(You MUST verify secrets never pass through build args, echo/log lines, or uploaded artifacts)**
    
    **(You MUST verify production Dockerfiles the diff adds or changes set a non-root USER and pin their base image)**
    
    **(You MUST verify workflow permissions are declared least-privilege, not inherited write-all)**
    
    </critical_requirements>
    
    ---
    
    **Auto-detection:** review workflow, CI PR review, Dockerfile review, pipeline review, deployment config review, GitHub Actions review, IaC review, terraform review
    
    **When to use:**
    
    - Reviewing diffs that touch CI/CD workflows (GitHub Actions, GitLab CI)
    - Reviewing Dockerfiles, .dockerignore, or compose files
    - Reviewing deployment configs (Kubernetes, Helm, platform configs)
    - Reviewing IaC (Terraform, Pulumi) or release/build scripts
    - Reviewing package-manager and lockfile changes with supply-chain impact
    
    **When NOT to use:**
    
    - When implementing infrastructure (use the relevant infra implementation skill)
    - For application code in the same diff (use the web/api reviewing skills)
    - For incident response or live operations questions
    
    **Key patterns covered:**
    
    - Supply-chain pinning: actions, base images, lockfiles
    - Secret exposure across build args, logs, artifacts, and ignore files
    - Dockerfile hygiene: non-root, multi-stage, layer order
    - CI/CD least-privilege permissions and pipeline correctness
    - Deployment safety scoped to what the diff deploys
    
    **Detailed Resources:**
    
    - [examples/core.md](examples/core.md) - Good/bad infrastructure patterns to look for during review
    
    ---
    
    <philosophy>
    
    ## Philosophy
    
    **Operational code fails in production only.** No unit test catches an unpinned action's supply-chain compromise or a leaked deploy key; the review is frequently the only gate this code passes through. Security findings here are cheap to fix pre-merge and brutally expensive after.
    
    **When reviewing infrastructure code:**
    
    - Scan for secrets before reading for style - the highest-severity class takes seconds to check
    - Treat every third-party reference (action, image, module) as an attack surface: is it pinned to something immutable?
    - Cross-reference the diff's blast radius: a new env var must exist everywhere the app runs; a renamed job must update everything that `needs` it
    - Ask what happens when this pipeline runs on a fork PR, on a re-run, and on two branches at once
    
    **When NOT to flag:**
    
    - Don't demand k8s-grade ceremony (probes, resource limits, rollback strategy) for a docs site or an internal workflow that deploys nothing
    - Don't demand multi-stage builds for a CI-only image where size is irrelevant
    - Don't flag missing caching in a job that runs in seconds
    - Don't require a vault migration in a diff that just consumes an existing secret the established way
    
    **Core principles:**
    
    - **Secrets and supply chain are non-negotiable**: always blocking, in any diff, at any scale
    - **Pin everything external**: mutable references delegate your security to strangers
    - **Least privilege by default**: a workflow gets the permissions it needs, not the ones it inherits
    - **Ceremony proportional to blast radius**: production deployment paths earn strictness; a lint workflow does not
    
    </philosophy>
    
    ---
    
    <patterns>
    
    ## Core Patterns
    
    ### Pattern 1: Supply-Chain Pinning
    
    Every external reference resolves to something immutable.
    
    ```markdown
    ## Pinning Review
    
    For EACH external reference the diff adds or changes:
    
    - [ ] Third-party GitHub Actions pinned to a full commit SHA (comment may carry the version)
    - [ ] First-party actions (actions/\*) at minimum major-version pinned
    - [ ] Base images pinned to a digest or a specific version tag - never `latest`
    - [ ] Dependency installs in CI use the lockfile (`npm ci`, `bun install --frozen-lockfile`), and the lockfile is committed
    - [ ] Terraform/Pulumi providers and modules carry version constraints
    ```
    
    ```yaml
    # Must Fix: mutable tag - the action's owner (or their attacker) can rewrite v4 tomorrow
    - uses: some-org/deploy-action@v4
    
    # Good: immutable SHA, human-readable version alongside
    - uses: some-org/deploy-action@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v4.1.2
    ```
    
    **Why this matters:** A mutable tag is remote code execution deferred: whoever controls that ref controls your CI, with your secrets in scope. Tag-rewriting attacks on popular actions are documented, recurring events.
    
    ---
    
    ### Pattern 2: Secret Exposure
    
    Secrets reach the process that needs them and nothing else.
    
    ```markdown
    ## Secret Review
    
    - [ ] No literal tokens, keys, passwords, or connection strings anywhere in the diff
    - [ ] Secrets arrive via the platform's secret store (secrets context, env from vault) - not committed files
    - [ ] No secret passes through a Docker build arg (build args persist in image history)
    - [ ] No echo/printf/debug line prints a secret; secret-bearing env is not dumped wholesale (`env | sort`)
    - [ ] Uploaded artifacts and caches cannot contain secret-bearing files (.env, credentials)
    - [ ] .gitignore / .dockerignore cover .env files and credential paths the diff introduces
    ```
    
    ```dockerfile
    # Must Fix: the token is baked into image history - docker history shows it
    ARG NPM_TOKEN
    RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && npm ci
    
    # Good: secret mount exists only for the one RUN
    RUN --mount=type=secret,id=npm_token \
        NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
    ```
    
    **Why this matters:** A leaked secret is a full compromise of whatever it guards, and build-arg/log leaks are invisible until someone pulls the image or reads the log archive.
    
    ---
    
    ### Pattern 3: Dockerfile Hygiene
    
    The image is minimal, cache-friendly, and unprivileged.
    
    ```markdown
    ## Dockerfile Review
    
    When the diff adds or changes a Dockerfile:
    
    - [ ] Production stage sets a non-root USER
    - [ ] Multi-stage build separates build tooling from the runtime image (when the image ships to production)
    - [ ] Dependency manifests are COPYed and installed BEFORE the source copy (layer caching)
    - [ ] .dockerignore exists and excludes node_modules, .git, .env
    - [ ] Base image is minimal for the job (slim/alpine/distroless where compatible)
    ```
    
    ```dockerfile
    # Should Fix: source copy first - every code change busts the dependency cache
    COPY . .
    RUN npm ci && npm run build
    
    # Good: manifest layer caches until dependencies actually change
    COPY package.json package-lock.json ./
    RUN npm ci
    COPY . .
    RUN npm run build
    ```
    
    **Why this matters:** Root containers turn any app compromise into a container-escape attempt; bad layer order turns every commit into a full rebuild, which teams then "fix" by caching less safely.
    
    ---
    
    ### Pattern 4: CI/CD Permissions and Pipeline Correctness
    
    The workflow can do its job and nothing more, and its jobs compose correctly.
    
    ```markdown
    ## Workflow Review
    
    - [ ] `permissions:` is declared at workflow or job level - read-all default, write scopes named individually
    - [ ] `pull_request_target` (if present) does not check out and execute PR head code with secrets in scope
    - [ ] Job `needs:` ordering matches real dependencies - deploy waits for test
    - [ ] Concurrency groups guard deploy jobs against overlapping runs
    - [ ] Cache keys include the lockfile hash - not a static string that never invalidates
    - [ ] When the diff renames jobs/outputs, everything that references them is updated in the same diff
    ```
    
    ```yaml
    # Must Fix: inherited write-all - a compromised step can push code and rewrite releases
    on: pull_request
    
    # Good: the job names exactly what it may touch
    permissions:
      contents: read
      pull-requests: write
    ```
    
    **Why this matters:** Default token permissions turn "a test step got compromised" into "the repository got compromised". `pull_request_target` with a head checkout is the classic secrets-exfiltration footgun.
    
    ---
    
    ### Pattern 5: Deployment Safety - Scoped to the Diff
    
    When the diff touches how production runs, verify it can fail safely.
    
    ```markdown
    ## Deployment Review (when the diff touches deployment config)
    
    - [ ] Health/readiness checks exist for services behind a load balancer or orchestrator
    - [ ] Resource limits accompany new containers on shared clusters
    - [ ] The app handles SIGTERM (finish in-flight work, then exit) when the platform does rolling restarts
    - [ ] New env vars/secrets the diff introduces exist in EVERY environment the app deploys to
    - [ ] IaC state changes (backend, locking) are deliberate; `terraform plan` output accompanies risky changes
    ```
    
    **Why this matters:** A missing readiness check means the balancer routes traffic to a booting container; a missing env var in one environment is the deploy that fails only in production, at deploy time.
    
    </patterns>
    
    ---
    
    <decision_framework>
    
    ## Decision Framework
    
    ### Severity Classification for Infra Issues
    
    ```
    Is this a security defect the diff introduces?
    ├─ Hardcoded secret, or secret through build arg/log/artifact → MUST FIX
    ├─ Third-party action on a mutable tag → MUST FIX
    ├─ pull_request_target executing PR head code with secrets → MUST FIX
    ├─ Write-all permissions on a workflow that needs read → MUST FIX
    ├─ Production container running as root → MUST FIX
    └─ NO → Is it an operational-correctness gap?
        ├─ Base image on `latest` / installs ignoring the lockfile → SHOULD FIX
        ├─ Deploy job without concurrency guard → SHOULD FIX
        ├─ New env var missing from one environment → SHOULD FIX
        ├─ Cache-hostile Dockerfile layer order → SHOULD FIX
        ├─ New production service without health checks or limits → SHOULD FIX
        └─ NO → Is it a genuine enhancement?
            ├─ Slimmer base image where size demonstrably matters → NICE TO HAVE
            ├─ Faster caching for an already-fast job → DON'T MENTION
            ├─ K8s-grade ceremony for a workflow that deploys nothing → DON'T MENTION
            └─ Tool preferences (compose vs k8s, npm vs bun) → DON'T MENTION
    ```
    
    </decision_framework>
    
    ---
    
    <red_flags>
    
    ## RED FLAGS
    
    **High Priority Issues (Must Fix):**
    
    - Any credential literal in the diff (grep for `token`, `key`, `password`, `secret`, connection-string shapes)
    - `uses: third-party/action@v3` / `@main` / `@master`
    - `ARG`/`ENV` carrying secrets in a Dockerfile
    - Missing `permissions:` on workflows that handle untrusted input
    - `pull_request_target` + `actions/checkout` of the PR head
    - Production Dockerfile with no `USER` directive
    
    **Medium Priority Issues (Should Fix):**
    
    - `FROM node:latest` or digest-less base images on deploy paths
    - `npm install` in CI where `npm ci` belongs
    - Static cache keys that never invalidate
    - Deploy steps with no concurrency group
    - Missing .dockerignore alongside a new Dockerfile
    - Debug steps that `env`-dump or `set -x` around secret use
    
    **Common Mistakes:**
    
    - Pinning first-party actions to SHA while leaving the third-party one on a tag (backwards priority)
    - Adding a secret to one environment and assuming the others inherit it
    - Copying source before manifests and "fixing" slow builds by skipping the lockfile
    - `needs:` chains that let deploy start when only lint passed
    - Treating `terraform apply` in CI as safe because plan passed locally against different state
    
    **Gotchas & Edge Cases:**
    
    - Docker build args persist in `docker history` even when unset afterwards
    - Rewritten tags pass `uses:` resolution - only SHAs are immutable
    - Composite actions inherit and can leak the caller's env
    - GITHUB_TOKEN default permissions differ per org setting - declaring them is the only portable truth
    - Alpine images lack glibc; native modules that built fine on debian-slim fail there at runtime
    - SIGKILL follows SIGTERM after the grace period - cleanup that takes longer than the grace period never finishes
    
    </red_flags>
    
    ---
    
    <critical_reminders>
    
    ## CRITICAL REMINDERS
    
    > **All code must follow project conventions in CLAUDE.md**
    
    **(You MUST verify no secrets are hardcoded - scan the diff for tokens, API keys, passwords, and connection strings)**
    
    **(You MUST verify third-party CI actions are pinned to full SHA hashes, not mutable tags like `@v4` or `@main`)**
    
    **(You MUST verify secrets never pass through build args, echo/log lines, or uploaded artifacts)**
    
    **(You MUST verify production Dockerfiles the diff adds or changes set a non-root USER and pin their base image)**
    
    **(You MUST verify workflow permissions are declared least-privilege, not inherited write-all)**
    
    **Failure to catch these issues will result in leaked credentials, supply-chain compromise executing in CI with secrets in scope, and deploys that fail only in production.**
    
    </critical_reminders>
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related