# docker-doctor — Static linter for Docker build hygiene

Sibling to `gitea-doctor` (`scripts/gitea/doctor.sh`). Detects Dockerfile, compose, and
`.npmrc.docker` drift from the invariants established by
[`docker-build-optimization-roadmap.md`](../../../learning_ai_devops_tools/docs/docker-build-optimization-roadmap.md)
Phase A.

## When to run

- **Before every Docker build** (alongside `gitea-doctor`)
- **In CI** on PRs touching `Dockerfile`, `docker-compose*.yml`, `.dockerignore`, `.npmrc.docker`
- **In pre-commit hook** (warning-only at first, error after stabilization)

## Quick start

```bash
# Canonical (run from common-plat)
bash scripts/docker-doctor.sh --repo /path/to/repo

# Per-repo wrapper (preferred)
bash scripts/docker-doctor.sh

# CI / scripting
bash scripts/docker-doctor.sh --quiet            # only print failures
bash scripts/docker-doctor.sh --warn-only        # always exit 0
```

## Checks performed

| #   | Check                                                                                         | Severity | Roadmap ref       |
| --- | --------------------------------------------------------------------------------------------- | -------- | ----------------- |
| 1   | `.npmrc.docker` uses `${GITEA_NPM_HOST}` placeholder                                          | Error    | F4                |
| 2   | `.npmrc.docker` uses `${GITEA_NPM_OWNER}` placeholder                                         | Error    | F14               |
| 3   | `.npmrc.docker` uses `${GITEA_NPM_TOKEN}` for `_authToken`                                    | Error    | F4                |
| 4   | `.gitignore` covers `.docker-deps/*`                                                          | Error    | B3                |
| 5   | `.gitignore` covers `*.bak`                                                                   | Warn     | B3                |
| 6   | Dockerfile has `# syntax=docker/dockerfile:1.7` directive                                     | Warn     | A2                |
| 7   | Dockerfile base image is approved (`node:22-alpine`/`-slim` or `${BASE_IMAGE}`)               | Error    | canonical         |
| 8   | Dockerfile uses corepack (no `npm install -g pnpm`)                                           | Error    | A1                |
| 9   | If Dockerfile COPYs `.npmrc.docker`, it declares `ARG GITEA_NPM_OWNER` + `ARG GITEA_NPM_HOST` | Error    | F14               |
| 10  | `.docker-deps/` COPY uses wildcard `COPY .docker-deps* ...`                                   | Error    | A5-2, B3          |
| 11  | Web Dockerfile uses glob `COPY web/*.{json,ts,...}` (not enumerated configs)                  | Error    | F11, F13          |
| 12  | Compose healthcheck uses `127.0.0.1`, not `localhost`                                         | Error    | F12               |
| 13  | Compose healthcheck has `start_period`                                                        | Warn     | A9-3              |
| 14  | Compose passes `GITEA_NPM_OWNER` build arg                                                    | Warn     | F14               |
| 15  | `.dockerignore` does NOT exclude `pnpm-lock.yaml`                                             | Warn     | F1 (per ADR-0001) |

## Exit codes

- `0` — all checks pass (warnings allowed)
- `1` — one or more error-level checks failed
- `2` — bad invocation / repo not found

## Sibling: gitea-doctor

`docker-doctor` and `gitea-doctor` are intentionally separate:

| Tool            | Scope                                        | When to run                      |
| --------------- | -------------------------------------------- | -------------------------------- |
| `gitea-doctor`  | runtime env, token, registry HTTP 200        | Before every build / deploy      |
| `docker-doctor` | static analysis of Dockerfile + compose YAML | On every PR touching those files |

Run both via `make doctor` in repos that have it wired up.

## Related

- Roadmap: [`docker-build-optimization-roadmap.md`](../../../learning_ai_devops_tools/docs/docker-build-optimization-roadmap.md) §Phase E
- ADR-0001: [`0001-docker-build-lockfile-policy.md`](../../../learning_ai_devops_tools/docs/adr/0001-docker-build-lockfile-policy.md)
- Sibling script: `learning_ai_common_plat/scripts/gitea/doctor.sh`
