본문으로 건너뛰기
cccskills
무료GitHub에 공개

meta-reviewing-infra-reviewing

Infrastructure code review — supply-chain pinning, secret exposure, workflow triggers and untrusted input, container hygiene, deployment safety. Load when reviewing a diff that touches CI/CD workflows, Dockerfiles, deployment configs or IaC.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구KubernetesTerraform

실행 점수 미검증

설치 방법 보기

포함된 파일(3)

  • SKILL.md15.9 KB
  • examples/core.md6.8 KB
  • metadata.yaml621 B

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Infrastructure Code Review Patterns

Quick Guide: Review operational code for what it can leak and what it lets a stranger run. Secrets, mutable third-party references and outsider input reaching a privileged job block the merge in any diff, at any scale; deployment ceremony scales with what the diff actually deploys. Recent facts that change the answer: actions/checkout v7 refuses fork-PR code under pull_request_target and workflow_run unless told otherwise; since December 2025 pull_request_target always runs the default branch's copy of the workflow; an organisation can enforce SHA pinning so a tag-pinned action fails at job setup; and GitHub's workflow dependency lockfile (public preview) pins what a uses: tag resolves to.

Detailed Resources:

  • examples/core.md — a good/bad pair for each pattern below: pinned actions and installs, secret mounts and log hygiene, permissions, privileged triggers and script injection, the non-root Dockerfile, deploy ordering, signal-safe startup

<critical_requirements>

Before reviewing infrastructure code

Grep the diff for credentials before reading it for anything else. A pushed secret stays reachable through clones, forks and the pull request's own refs, so the fix to ask for is revocation, not a follow-up commit — and the check takes seconds.

Resolve every external reference to something immutable. A tag or branch on an action, base image, provider or module runs whatever its owner — or whoever holds the owner's token — points it at next, with this pipeline's secrets in scope.

Trace each secret from its store to the one process that needs it. A build arg lands in image history, a job-level env: reaches every step including third-party actions, and log masking matches only the exact registered string — each hop the diff adds is a place it leaks.

Read a workflow's trigger and permissions: before its steps. Under pull_request_target and workflow_run the job holds the base repository's secrets and token while handling fork-controlled input, and a missing permissions: block inherits a default set in settings the diff never shows.

Treat every value an outsider can set as code. A PR title, branch name or comment body written as ${{ }} inside run: is spliced into the script before the shell parses it, so a quote in that value ends the string and the rest runs as commands.

Check that a production image ends on a non-root USER. Without one the process runs as root, and an application compromise starts one container-escape bug away from the host.

</critical_requirements>


Auto-detection: .github/workflows, uses:, permissions:, pull_request_target, workflow_run, GITHUB_TOKEN, secrets., allow-unsafe-pr-checkout, concurrency:, .gitlab-ci.yml, Dockerfile, .dockerignore, compose.yaml, FROM, USER, ARG, RUN --mount=type=secret, Kubernetes manifest, Helm chart, readinessProbe, terraform, .terraform.lock.hcl, Pulumi, CI review, Dockerfile review, IaC review

Applies to:

  • Diffs touching CI/CD workflow files — triggers, permissions, pinned references, secrets, job ordering
  • Dockerfiles, .dockerignore and compose files
  • Deployment manifests and platform configs — readiness, resources, shutdown, per-environment config
  • IaC — provider and module pinning, state, plan and apply in CI
  • Release and build scripts — what they publish, sign and tag, and which credentials they read
  • Lockfile and package-manager changes with supply-chain reach

Handled elsewhere:

  • Application code in the same diff — reviewed against its own layer's conventions; this skill reviews what builds, ships and runs it.
  • Severity vocabulary, comment format and the approve-or-request-changes call — the general review practice, which this skill's severities slot into.
  • Designing or restructuring a pipeline — a review names the defect and its fix; the platform's shape belongs to whoever owns it.
  • Incident response and live operations — a review gates a diff, not a running system.

<philosophy>

Philosophy

Operational code fails in production only. No unit test catches an unpinned action's compromise or a leaked deploy key, so the review is often the one gate this code passes — and a finding costs a line before merge and a rotation after.

Ceremony scales with blast radius: a production deploy path earns strictness, a lint workflow that deploys nothing does not. Read the diff against what it reaches —

  • A new env var must exist in every environment the app runs in; a renamed job or output must change everywhere that needs or reads it.
  • Ask what the pipeline does on a fork PR, on a re-run, and on two branches at once.

Don't flag:

  • Probes, resource limits or rollback strategy on a docs site or a workflow that deploys nothing
  • A multi-stage build for a CI-only image whose size nothing depends on
  • Missing caching in a job that runs in seconds
  • A vault migration in a diff that consumes an existing secret the established way
</philosophy>

<decision_framework>

Severity for infrastructure findings

Must Fix blocks approval. Should Fix travels with the approval, for the author to fix before merging, and needs a cost concrete in this diff. Nice to Have is the author's to take or leave.

Does the diff introduce a security defect?
├─ Credential literal, or a secret through ARG/ENV, a log line or an artifact → MUST FIX
├─ Third-party action on a tag, or any action on a branch (@v3, @main) → MUST FIX
├─ ${{ }} of outsider-controlled input inside run: → MUST FIX
├─ pull_request_target / workflow_run that checks out or runs PR head code → MUST FIX
├─ Write scopes a job doesn't use, or no permissions: on a workflow fed untrusted input → MUST FIX
├─ Production image without a non-root USER → MUST FIX
└─ NO → Is it an operational-correctness gap?
    ├─ GitHub's own action (actions/*) on a version tag instead of a full SHA → SHOULD FIX
    ├─ Base image on latest or untagged, or without a digest on a deploy path; CI install that ignores the lockfile → SHOULD FIX
    ├─ No permissions: block on any other workflow → SHOULD FIX
    ├─ Debug output beside secret use (set -x, env dumps) → SHOULD FIX
    ├─ Deploy job without a concurrency group, or not waiting on the tests → SHOULD FIX
    ├─ New env var missing from one environment → SHOULD FIX
    ├─ Cache key that never changes; cache-hostile Dockerfile layer order → SHOULD FIX
    ├─ New Dockerfile without .dockerignore; shell-form CMD or CMD via npm → SHOULD FIX
    ├─ New production service without a readiness check, resource requests 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 write it
        ├─ Production ceremony on a workflow that deploys nothing → don't write it
        └─ Tool preference (compose vs Kubernetes, one package manager over another) → don't write it

</decision_framework>


<patterns>

Core patterns

Pattern 1: Supply-Chain Pinning

Every external reference resolves to something immutable, and the record of it is committed.

  • Third-party actions on a full 40-character commit SHA from the action's own repository, not a fork; a trailing # vX.Y.Z comment keeps it readable
  • GitHub's own actions/* on a full SHA as well — GitHub's secure-use guidance makes no first-party exception, and an organisation's SHA-pinning policy fails any unpinned action at job setup. A version tag here is Should Fix rather than Must Fix, because GitHub is a smaller trust grant than a third party
  • Base images on a version tag at minimum, and on a digest on deploy paths — latest changes the build with no diff to review, and a publisher can re-point any tag; a digest is the only immutable form
  • CI installs from the committed lockfile and fails on drift (npm ci, or the package manager's frozen-lockfile mode)
  • Terraform providers and modules carry version constraints, and .terraform.lock.hcl is committed
# Must Fix: whoever controls this repository's tags decides what runs next
- uses: some-org/deploy-action@v4

# Good: immutable; the comment keeps it readable
- uses: some-org/deploy-action@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v4.1.2

Full code: examples/core.md

Pattern 2: Secret Exposure

Secrets reach the process that needs them and nothing else.

  • No literal tokens, keys, passwords or connection strings — grep for token, key, secret, password and ://user:pass@ shapes
  • Secrets come from the platform's secret store, never a committed file
  • No secret in a Dockerfile ARG or ENV — a secret mount exists for one RUN and in no layer
  • No secret in workflow- or job-level env: when one step uses it — scope it to that step
  • No line prints a secret or a value derived from one; derived values are registered with ::add-mask::
  • Artifacts and caches cannot contain .env files, credentials, Terraform state or saved plans
  • .gitignore and .dockerignore cover the .env and credential paths the diff introduces
# Must Fix: the token is in `docker history` and in the .npmrc layer
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && npm ci

# Good: the credentials file is mounted for this one RUN
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci

Full code: examples/core.md

Pattern 3: Workflow Trust Boundaries

What a workflow can reach is set by its trigger and its permissions:; what an outsider can make it do is set by where their input lands.

  • permissions: read-only (or {}) at workflow level, write scopes granted per job
  • pull_request_target and workflow_run only where the job needs the base repository's secrets or write token, and never checking out or running PR head code
  • Under those triggers: no allow-unsafe-pr-checkout: true, no actions/checkout older than v7, no manual fetch of the PR head — v7's refusal guards only its own default path
  • Outsider-set values — github context fields ending in title, body, head_ref, label, message, name, email or ref — reach run: through env:, never as ${{ }} in the script
# Must Fix: the title is pasted into the script before bash parses it
- run: echo "Checking ${{ github.event.pull_request.title }}"

# Good: the shell receives data, not script
- env:
    PR_TITLE: ${{ github.event.pull_request.title }}
  run: echo "Checking $PR_TITLE"

Full code: examples/core.md

Pattern 4: Dockerfile Hygiene

The image is minimal, cache-friendly and unprivileged.

  • Production stage ends on a non-root USER
  • A multi-stage build keeps compilers and dev dependencies out of the image that ships
  • Dependency manifests are copied and installed before the source, or every code change reinstalls everything
  • .dockerignore excludes .git, .env and local dependency folders — COPY . . copies whatever the context holds
  • Base image minimal for the job (slim, alpine, distroless) where the app's native dependencies allow
# Should Fix: every source change busts the dependency layer
COPY . .
RUN npm ci && npm run build

# Good: the install layer is reused until a manifest changes
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

Full code: examples/core.md

Pattern 5: Pipeline Correctness

The jobs compose the way the author thinks they do.

  • needs: matches real dependencies — deploy waits for every test job, not only lint
  • Deploy jobs share a concurrency group, so two quick merges cannot deploy out of order
  • Cache keys include a lockfile hash (hashFiles(...)); a static key never invalidates
  • A renamed job, output or env var is renamed at every reference in the same diff
concurrency:
  group: deploy-production
  cancel-in-progress: false
jobs:
  deploy:
    needs: [lint, test, e2e]

Full code: examples/core.md

Pattern 6: Deployment Safety, Scoped to the Diff

When the diff changes how production runs, check it can fail safely.

  • Services behind a load balancer or orchestrator have a readiness check — without one, traffic reaches a container still booting
  • New containers on a shared cluster declare resource requests and limits — requests are what the scheduler places by, and a memory limit makes a leak kill its own container rather than starve its neighbours
  • The app receives SIGTERM and finishes in-flight work inside the grace period: exec-form CMD, not shell form or npm start, and a handler or an init process, because PID 1 gets no default signal behaviour
  • Every env var and secret the diff introduces exists in every environment the app deploys to
  • IaC backend and locking changes are deliberate, a risky change (a backend move, a destroy or a replace) comes with its terraform plan output so the reviewer sees what the apply will do, and apply in CI runs the plan CI produced against the real state
# Should Fix: /bin/sh -c is PID 1 and does not pass SIGTERM on
CMD node dist/server.js

# Good: the app receives the signal itself
CMD ["node", "dist/server.js"]

Full code: examples/core.md

</patterns>

<red_flags>

Red flags

Common mistakes:

  • SHA-pinning actions/* while a third-party action stays on a tag — backwards, since the third party is the larger trust grant
  • Asking only for a leaked secret's removal from the diff — it is already pushed, so ask for revocation
  • "Fixing" a slow image build by dropping the lockfile instead of reordering the layers
  • Approving an apply in CI because a plan passed locally — against different state it proves nothing about this run

Surprising behaviour:

  • Build-arg values appear in docker history and in max-mode provenance attestations.
  • Log masking redacts the exact registered value; a base64, URL-encoded or substring form prints in clear, and a secret stored as a JSON blob is not reliably masked.
  • Every step in a job sees workflow- and job-level env:, third-party actions included.
  • A job's permissions: block is that job's whole grant: every scope it omits is none, whatever the workflow level said.
  • GITHUB_TOKEN's default comes from organisation and repository settings the diff doesn't show; fork PRs get read-only unless the repository sends write tokens to forks.
  • Since 8 December 2025, pull_request_target runs the default branch's copy of the workflow, so a PR editing that workflow is not exercised by its own run.
  • In a repository with a workflow dependency lockfile, the run executes the commit the lockfile records, so a uses: tag is not mutable there; review the lockfile's changed commit entries instead.
  • In image:tag@sha256:… the digest decides and the tag is a label.
  • .terraform.lock.hcl locks providers only; a module floats within its version constraint unless the constraint is exact.
  • sensitive = true hides a Terraform value from CLI output, not from state or plan files, which hold it in plaintext — a plan uploaded as an artifact ships the secret.
  • Alpine uses musl: a native module compiled in a glibc build stage fails to load in an Alpine runtime stage.
  • Cleanup that outlasts the grace period never finishes — the platform sends SIGKILL (Kubernetes' default is 30 seconds, preStop time included).

</red_flags>

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 23일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고