pattern-reviewer-container
Skill0 starsChanged 5 months agoMITView on GitHub
Docker / compose audit: Dockerfile is multi-stage (`base`/`build`/`final`); tags pinned (no `:latest`) with `docker scout` clean of fixable MEDIUM+ CVEs; non-root user with writable paths redirected; `.dockerignore` excludes secrets/build outputs; backend entrypoint runs `alembic upgrade head` before the server; no-dep `/healthz` exists; frontend nginx puts API `location` blocks ABOVE the SPA `try_files` fallback. Activate on Dockerfile, compose, or `.dockerignore` diffs.
- Reads credentials
- Installs packages
In this repository74 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- create-bug-issueSkill
- create-enhancement-issueSkill
- create-feature-issuesSkill
- dream-summary-memorySkill
- memory-conventionSkill
- operation-gitSkill
- pattern-architect-api-endpointSkill
- pattern-architect-data-modelSkill
- pattern-architect-deep-moduleSkill
- pattern-e2e-coding-standardSkill
- pattern-engineer-apiSkill
- pattern-engineer-backend-standardSkill
- pattern-engineer-coding-standardSkill
- pattern-engineer-containerSkill
- pattern-engineer-databaseSkill
- pattern-engineer-fastapiSkill
- pattern-engineer-frontend-standardSkill
- pattern-engineer-goSkill
- pattern-engineer-javaSkill
- pattern-engineer-kotlinSkill
- pattern-engineer-nodeSkill
- pattern-engineer-non-functionalSkill
- pattern-engineer-observabilitySkill
- pattern-engineer-pythonSkill
- pattern-engineer-rustSkill
- pattern-engineer-securitySkill
- pattern-engineer-ssrSkill
- pattern-engineer-swiftSkill
- pattern-engineer-typescriptSkill
- pattern-engineer-viteSkill
- pattern-exploratory-testingSkill
- pattern-reviewer-apiSkill
- pattern-reviewer-backend-standardSkill
- pattern-reviewer-coding-standardSkill
- pattern-reviewer-contractSkill
- pattern-reviewer-databaseSkill
- pattern-reviewer-fastapiSkill
- pattern-reviewer-frontend-standardSkill
- pattern-reviewer-goSkill
- pattern-reviewer-javaSkill
- pattern-reviewer-kotlinSkill
- pattern-reviewer-nodeSkill
- pattern-reviewer-non-functionalSkill
- pattern-reviewer-observabilitySkill
- pattern-reviewer-pythonSkill
- pattern-reviewer-rustSkill
- pattern-reviewer-securitySkill
- pattern-reviewer-ssrSkill
- pattern-reviewer-swiftSkill
- pattern-reviewer-test-coverageSkill
- pattern-reviewer-typescriptSkill
- pattern-reviewer-viteSkill
- pattern-test-coverageSkill
- principle-engineer-tddSkill
- scaffold-projectSkill
- workflow-architect-interviewSkill
- workflow-designer-sample-pagesSkill
- workflow-design-interviewSkill
- workflow-e2e-authorSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 15
After loading this skill, also check $MAIN_ROOT/.claude/memory/patterns/pattern-reviewer-container.md in the consuming project (resolve …
- Very specific: line 26
Read every stage of each touched Dockerfile top-to-bottom: stage names (AS), base-image tags, USER lines, ENV/ARG values, COPY order, what …
- Very specific: line 30
Run docker scout cves (or Trivy) against the slug-tagged image when one is built.
- Very specific: line 151
Use ${VAR} in compose environment: pulling from host env / .env (gitignored).
- Very specific: line 173
Use the shape in templates/review-comment.md.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pattern-reviewer-container
When to activate
- Reviewing a diff that touches
Dockerfile,docker-compose.yaml/.yml,compose.yaml/.yml,.dockerignore, or backend entrypoint scripts. - A user says "review the Docker setup / image build / compose wiring".
Project memory overlay
After loading this skill, also check $MAIN_ROOT/.claude/memory/patterns/pattern-reviewer-container.md in the consuming project (resolve MAIN_ROOT="$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"). If present, load it as an additive overlay to the rules below; if absent, skip silently. See memory-convention for the full contract (additivity, severity floor, conflict surfacing).
Iron rules
- >80% confidence filter. Report only when you are >80% confident. Consolidate similar findings.
- Cite
path/to/file.ext:line. Quote the offending snippet in a BAD block; show the fix in a GOOD block. - Severity is load-bearing. CRITICAL / HIGH block the gate; MEDIUM / LOW are informational. Use the per-pattern severity assigned below. The banding: CRITICAL = secret exposure; HIGH = the container fails, races, or leaks in production; MEDIUM = drift that bites later (lost SIGTERM, LAN-exposed port); LOW = build-cache / ergonomics advice that never blocks.
- Never refer to a finding as
#N— GitHub auto-links those to issues. Use a non-numeric handle (quoted title,F1/F2,Finding 1).
Where to look
- Read every stage of each touched
Dockerfiletop-to-bottom: stage names (AS), base-image tags,USERlines,ENV/ARGvalues,COPYorder, what lands infinal. lsnext to the Dockerfile for.dockerignore; open it and diff against the exclusion list below.- In compose files scan
ports:,environment:,volumes:, and themigrateservice wiring. - Open the entrypoint script (whatever
ENTRYPOINTnames): migration step,execon the server line. - Run
docker scout cves(or Trivy) against the slug-tagged image when one is built; quote counts in the finding. - For frontend images, open the nginx config and check
locationorder against the BAD/GOOD below.
Patterns to review
Multi-stage build (HIGH)
- Dockerfile has at least three stages:
base,build,final(useASaliases). - Single-stage Dockerfile → flag.
finalstage carries build tools / dev deps → flag (ship a minimal runtime).
Pinned tags + docker scout (HIGH)
:latestanywhere → flag.- Pinned major-only tag (
node:20) → flag; use full immutable tag (node:20.11.1-alpine). docker scout cves <image>reports MEDIUM+ CVEs that have a fix available → flag; bump to the fixed tag.- Production base images can additionally use digest pinning (
@sha256:...) — informational.
Non-root user (HIGH)
finalstage ends withUSER <name>(notUSER rootor noUSER) → flag.- Process tries to write to root-owned paths (
/run/nginx.pid,/var/cache/nginx,/var/run/...) → HIGH. Fixes:- Redirect writable paths to
/tmp/...via server config — for nginx,pid /tmp/nginx.pid;+client_body_temp_path /tmp/client_body, etc. - Recursive
chown -R app:app /usr/share/nginx/html(or equivalent) in the build stage BEFOREUSER.
- Redirect writable paths to
- The container starts but dies on first write attempt (
[emerg] open() "/run/nginx.pid" failed (13: Permission denied)or equivalent) → flag.
No in-image virtualenvs (MEDIUM)
RUN uv venvorpython -m venv .venvinside a Dockerfile → flag.uv pip install --system -r requirements.txt(system site-packages) → correct.
.dockerignore mandatory (HIGH)
- No
.dockerignorenext to the Dockerfile → flag. .dockerignoredoesn't exclude:.git,node_modules,.env*,dist/,build/,coverage/,*.log,.vscode,.idea→ MEDIUM..envaccidentally in the build context (not excluded) → CRITICAL (potential secret leak into image history).
Layer ordering (LOW)
COPY . .beforeCOPY package*.json + npm ci→ flag (dep layer cache never hits on source edits).
# BAD — any source edit invalidates the npm ci layer
COPY . .
RUN npm ci
# GOOD — dep layer cached until the manifests change
COPY package*.json ./
RUN npm ci
COPY . .Backend entrypoint (HIGH)
- Backend image owns its DB schema but no migration step in entrypoint → flag.
- Migration step in
CMDinstead ofENTRYPOINT→ flag (CMD is the server). - Migration step in a FastAPI
startuphook instead of the entrypoint → flag (the app accepts traffic against a stale schema; N replicas race). - Migration CLI (
alembic) missing fromfinalstage even though entrypoint calls it (command not found: alembic) → flag; copy the CLI from the build stage or install it infinal. - Missing
execon the server line in the entrypoint (uvicorn ...instead ofexec uvicorn ...) → MEDIUM (SIGTERM doesn't forward to the server).
# BAD — server runs as a child of the shell; SIGTERM stops at the shell
#!/bin/sh
alembic upgrade head
uvicorn app.main:app --host 0.0.0.0
# GOOD — migrations first, then the server replaces the shell
#!/bin/sh
set -e
alembic upgrade head
exec uvicorn app.main:app --host 0.0.0.0/healthz endpoint (HIGH)
- Backend exposes no
/healthzroute → flag; the pre-push hook'scontainer:smoke-healthprobe can't pass. /healthzrequires auth → flag./healthztouches the DB or an external API → flag; move that to/readyz./healthztakes >100ms → flag.
Frontend nginx ordering (HIGH)
# BAD — try_files catches /api/* too; backend POSTs receive index.html
server {
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend:8000;
}
}
# GOOD — API location blocks ABOVE the SPA fallback
server {
location = /healthz {
proxy_pass http://backend:8000/healthz;
}
location /api/ {
proxy_pass http://backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}try_files $uri $uri/ /index.htmlmissing → flag (any SPA route 404s on direct load).try_fileswithout$uri/→ flag (directory-path requests 404).- The pre-push hook's
container:smoke-api-proxyprobe detects this exact misconfig byContent-Type(text/htmlon an API probe = SPA catch-all intercepted).
Secrets in image (CRITICAL)
ENV API_KEY=.../ARG API_KEY=.../COPY .env ./in Dockerfile → CRITICAL.- Hardcoded values in
docker-compose.yamlenvironment:(committed) → CRITICAL. - Use
${VAR}in composeenvironment:pulling from host env /.env(gitignored).
Networking (MEDIUM)
ports:on internal services (DB, cache, queue) that the host doesn't need → flag; useexpose:(or omit, since compose networks allow all ports between services).- Publishing a dev-only port without binding to
127.0.0.1(e.g."5432:5432"instead of"127.0.0.1:5432:5432") → flag (reachable on the LAN).
Volumes (LOW)
- Named volume for persistent state present and declared at top level → correct.
- Bind mount over an in-image path that has generated content (e.g.
node_modules) without an anonymous-volume shield → flag.
Templates
| Asset | Purpose |
templates/Dockerfile | Three-stage Node Dockerfile reference; compare the project's Dockerfile against this. |
templates/docker-compose.yaml | app + db services with healthcheck + named volume reference. |
templates/.dockerignore | Exclusions reference for .dockerignore audits. |
Constructing the finding
Use the shape in templates/review-comment.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

