Changelog
Release notes for the Docker Doctor CLI, read directly from the GitHub releases.
v0.9.0
LatestMinor Changes
- dd6fd5a`parseCompose` now returns a `ComposeValue`, and `runComposeRules` and `isAnalyzableCompose` take one. Both `ComposeValue` and `ComposeMapping` are exported. A TypeScript caller that passed these functions an `unknown` value passes the result of `parseCompose` instead. Nothing changes at run time.
v0.8.0
Minor Changes
- eb5d0c0The score now averages only over the files Docker Doctor could check. A Dockerfile with no instructions, such as an empty or comment-only file, no longer counts. Neither does a Compose file with no services, no top-level `models` and no `version` key. Such files have no findings, so they used to raise the score. When no file could be checked, there is no score. `--json` reports `score` and `label` as `null`, `--score` prints nothing, and the terminal report says why instead of showing a score box. This also applies to a directory with no Dockerfile or Compose file, which used to report 100 in `--json` and `--score`. Exit codes are unchanged.
Patch Changes
- 0e6fbc9The README and the bundled `docker-doctor` skill say which files count as analyzed and that a scan with no analyzed file has no score. The skill's `--score` row says it prints nothing in that case.
- 497266cThe README now says the score averages the penalty over the analyzed files, as it has since 0.7.0. It no longer claims the score never reaches 0. Rounding gives 0 at an average penalty of about 371 per file.
- d9b100bRule messages no longer repeat credentials from the scanned files. The user name and password in a URL such as `https://user:token@host` are shown as `***`. A URL with a user name only, such as `ssh://git@host/repo.git`, is masked the same way. The value of a secret-like `KEY=value` or `--flag value` is shown as `***` too. This applies in the terminal, `--json`, `.docker-doctor/` and the agent handoff. A Compose file that fails to parse is reported with its line and column only. The YAML source lines are left out. The agent handoff also replaces invisible Unicode with a space. That covers C1 controls, zero-width and bidi control characters, the BOM, line and paragraph separators, and tag characters.
- c76f7f3Eight rule verdicts are corrected. Some files gain findings and some lose them.
- 497266cThe bundled `docker-doctor` skill no longer treats a steady score as proof that a change is safe. Since 0.7.0 the score averages over the analyzed files, so a new error in one file of a large project can move it by a single point. The skill now compares the exit code and the number of findings per rule before and after a change, and uses the score as a coarse signal. It also says that `rules explain` prints the rule's category, default severity and description next to the same fix text as `Help:`.
- 475045eThe CLI's runtime dependencies are updated: `yaml` to `^2.9.1` and `chalk` to `^6.0.1`. Scan results and output do not change.
v0.7.0
Minor Changes
- c752e18The health score now averages the penalty over the files it analyzed. Before, it added up every finding in the scan, so a repository with many Dockerfiles or Compose files scored near 0 even when each file had only a couple of warnings. A project with one Docker file scores the same as before. A project with several files scores higher, and its score now moves when a typical file gets better or worse.
v0.6.1
Patch Changes
- d3ffd60A `docker-doctor.config.ts`, `.js`, `.mjs` or `.cjs` now loads on Windows, and from a project whose path contains `#`, `?` or `%`. The CLI imported the config by its bare path. Node rejects a drive-letter path with `ERR_UNSUPPORTED_ESM_URL_SCHEME` and misreads a path that contains URL characters. JSON and YAML configs always loaded.
- 9f98188Fix nine false positives on correct Dockerfiles. `useradd-no-log-init` accepts `-l`, the short form of `--no-log-init`, also inside a cluster such as `-rl`. `absolute-workdir` reads a quoted path such as `WORKDIR "/app"` the way BuildKit does. `clean-package-cache` recognizes any recursive `rm` that removes the apt lists or the apk cache, such as `rm -fr`, `rm -r` and `rm -rf /tmp/* /var/lib/apt/lists/*`. `sort-multiline-args` ends a package list at the newline inside a heredoc body. The pinning rules and `prefer-slim-base` treat `node:$TAG` as a variable, like `node:${TAG}`. `avoid-dev-dependencies` skips installs that run under `ENV NODE_ENV=production` and `yarn install --production=true`. `prefer-slim-base` checks only the stages that reach the final image and recognizes Chainguard, Wolfi, UBI minimal and micro, chiseled and minideb bases. `no-root-user` accepts distroless `:nonroot` images, which do not run as root. `no-add-remote` no longer reports a download verified with `ADD --checksum`.
- 1adb12aThe post-scan handoff now uses the directory you scanned. A launched agent starts in that directory instead of the shell's, the launch confirmation names it, and the prompt says which directory its file paths are relative to. `.docker-doctor/` contains its own `.gitignore`, so it stays untracked when you scan a subdirectory of a repository. docker-doctor writes the scaffolded workflow at the repository root, where GitHub runs it, and passes the scanned subdirectory as the action's `directory` input.
- 9d5a558`avoid-dev-dependencies`, `avoid-run-cd` and `use-multi-stage` now look past BuildKit flags on `RUN`. They used to take `--mount=type=cache,…` for the command and report nothing, so `RUN --mount=type=cache,target=/root/.npm npm ci` went unreported. `no-privileged-service` reports the other spellings Compose reads as true (`privileged: "true"`, `yes`, `on`), and a bind mount with `read_only: "true"` counts as read-only. The Dockerfile parser accepts any word as a heredoc delimiter, as BuildKit does. `RUN <<END-OF-SCRIPT` and `COPY <<nginx.conf …` used to fail the scan with a false "unterminated heredoc" error.
- 2930957A scan that finds no Dockerfile or Compose file now says so instead of printing "No issues found" and a 100/100 score. `--json` and `--score` keep their output and add a warning on stderr. When docker-doctor can't analyze a file, the terminal report no longer calls the project healthy or offers a share link, and it says how many files it left out. `ignore.files` accepts a trailing `/` for a whole directory, so `vendor/` means `vendor/**`, and ignores a leading `./`. The docs already used both spellings. The "Scanned N files" line no longer counts `.dockerignore` files. The bundled skill explains exit code 2 and no longer says `rules explain` needs the full rule key.
- d35a759`no-secrets-in-env` and `no-plaintext-secrets` no longer report a key that names the file a secret is stored in, such as `POSTGRES_PASSWORD_FILE=/run/secrets/pg` or `TLS_PRIVATE_KEY_PATH`. That is the Docker secrets setup both rules recommend. They also skip on/off values under a secret-shaped key, such as `AUTH_ENABLED=true` and `MYSQL_ALLOW_EMPTY_PASSWORD=yes`. Both rules still report a literal value under a credential-shaped key.
v0.6.0
Minor Changes
- f3a15f8The JSON report (`--json`, schema 4) now includes `failures[]`, one entry with the error message for every discovered file that could not be read or parsed. The GitHub Action marks those files as Unanalyzed, says so in the summary, and fails the pull request check regardless of `blocking`. Before, an unparseable Dockerfile rendered as Clean with a score of 100.
Patch Changes
- 23deed0`--config` paths now resolve from the current directory like every other flag, so the Action's `config` input is relative to the repository root, the same as `directory`. A path that only exists relative to the scanned directory still loads, with a warning. A missing scan target or a file passed as the scan target now gets a plain error instead of a raw `scandir` failure. The terminal migration notice counts files instead of findings. The scaffolded workflow grants `statuses: write`, which the Action's default commit status needs, and uses `actions/checkout@v7`. `rules explain` accepts the short rule name, such as `no-root-user`.
- 478cc64A subdirectory that cannot be read, such as a root-owned `data/` volume directory, no longer fails the whole scan. docker-doctor skips it and prints a warning on stderr. Discovery also skips well-known dependency, VCS and cache directories (`.venv`, `__pycache__`, `.yarn`, `coverage`, `.cache` and others), and it no longer walks a directory excluded by an `ignore.files` pattern ending in `/**`.
- 632961cFix ten wrong verdicts. The Dockerfile parser no longer ends a `\`-continued instruction at a blank line (BuildKit skips those lines too), so the rules see the whole instruction. `no-secrets-in-env` ignores empty quoted defaults such as `ARG TOKEN=""`. `combine-apt-update-install`, `clean-package-cache` and `sort-multiline-args` recognize `apt-get <options> install`. `avoid-dev-dependencies` checks each command for npm, yarn, pnpm or bun running a bare project install, so it skips global installs, named-package installs and production installs (`--omit=dev`, `--only=production`, `--prod`, `NODE_ENV=production`). `prefer-copy-over-add` exempts every tar format ADD auto-extracts, including `.tar.xz` and `.tar.bz2`, and reports `.zip`, which ADD copies without extracting. `sort-multiline-args` sorts only the package list, not the command text around it. `use-dockerignore` accepts BuildKit's per-Dockerfile `<name>.dockerignore`. `use-multi-stage` counts `make` and `cmake` only where a command starts, so `apk add make` is not a build step. Compose bind mounts from `${PWD}/…` are project paths, and a source that starts with any other variable with no default names no known host path. `no-plaintext-secrets` reports unquoted numeric values such as `POSTGRES_PASSWORD: 123456`.
v0.5.3
Patch Changes
- f538085Add two Compose rules for host bind mounts. `no-broad-bind-mount` (warning) reports services that bind-mount the host root, the home directory or a hidden directory under it, a parent of the project, or a system directory such as `/etc` or `/proc`. `prefer-read-only-bind-mount` (info) reports bind mounts outside the project that are not marked `:ro` / `read_only: true`. Both rules exist because a writable host mount is the foothold for VM-escape bugs like CVE-2026-77179 in Docker Desktop and Docker Sandboxes; mounting less and mounting read-only is the defense that does not depend on the hypervisor.
v0.5.2
Patch Changes
- 590ea75Fix three discovery false positives: `<name>.dockerignore` files (BuildKit's per-Dockerfile ignore convention) are no longer scanned as Dockerfiles, Dockerfiles with no instructions no longer produce `no-root-user` / `require-labels` findings, and discovered paths are always `/`-separated so the `.dockerignore` check and the JSON report behave the same on Windows.
- 66816aaThe post-scan wizard now reports a failed write (workflow scaffold, `.docker-doctor/`, `.gitignore`) and exits non-zero instead of silently pretending it succeeded; `.docker-doctor/diagnostics.json` flattens messages and paths the same way the per-rule `.txt` files already did; and every CLI error path sets the exit code instead of calling `process.exit`, so piped output is never cut short.
- 5b03d3dEvery diagnostic in the `--json` report (and in `.docker-doctor/diagnostics.json`) now carries its rule's `category`, so consumers no longer need a second `rules list` call to group findings. The report `schemaVersion` is now `3`; all existing fields are unchanged.
- 61264f3Raise the supported Node.js floor to 22.18. The CLI's dependencies already required Node 22, and `docker-doctor.config.ts` only loads on runtimes that strip TypeScript types natively (22.18+). On an older Node the CLI now explains the `.ts` config failure and points at the YAML/JSON alternatives instead of printing `Unknown file extension ".ts"`.
- d9b9a43Fix four false results from reading shell text without quote awareness: a `<<EOF` inside a quoted string no longer opens a heredoc, a heredoc that never closes now fails the file (exit 2, "scan incomplete") instead of silently dropping every instruction after it, `avoid-run-cd` only flags `cd` in command position (`/opt/cd` and `cd.tar.gz` no longer match), `use-pipefail` ignores `|` inside quoted arguments, and a `services:` written as a YAML list is treated as invalid Compose rather than as services named `0`, `1`, …
- c30dd7fThe bundled `docker-doctor` skill no longer claims that category severities other than `"off"` are ignored — `categories` entries cascade to every rule in the category unless a per-rule entry overrides them.
v0.5.1
Patch Changes
- 8bded00`no-docker-socket-mount` compared the volume source against the literal `/var/run/docker.sock`, so it caught 1 of the 5 ways agent stacks mount the socket. The rule now resolves `${VAR:-default}` interpolation to the default and matches the socket by name on any path-shaped source, which covers:
- `${DOCKER_SOCK:-/var/run/docker.sock}`, the mcp-gateway pattern
- `/run/docker.sock` on systemd hosts
- rootless and Docker Desktop sockets under a home directory
- `//var/run/docker.sock` from Git Bash on Windows
- the `\\.\pipe\docker_engine` named pipe
- fed7f98`require-resource-limits` only looked at `deploy.resources.limits`, so it warned services that set limits through the service-level `mem_limit`, `cpus`, or `cpu_quota` keys. Those keys are the older spelling of the same limits, still in the Compose specification and applied the same way by `docker compose`, and now satisfy the rule.
v0.5.0
Minor Changes
- c1218ffUnderstand the Compose `models:` element (Docker Model Runner) with two new rules: `undefined-model-reference` (error) flags service-level model references with no matching top-level declaration, and `pin-model-version` (warning) flags model artifacts with no tag or a `latest` tag. Unpinned weights change behavior with nothing visible in version control.
- 9ee6eecAdd three Compose security rules aimed at agent-era compose files: `no-privileged-service` (error) flags `privileged: true`, `no-docker-socket-mount` (error) flags bind mounts of `/var/run/docker.sock` in short or long volume syntax, and `no-plaintext-secrets` (warning) flags literal credential values in `environment`. Because new rules add findings, existing projects can score lower than on 0.4.x.
- 536d47cImplement `ignore.files`. The config key was documented, typed, and validated but consumed by nothing. Glob patterns (`vendored/**`, `**/Dockerfile.test`) now exclude matching files from discovery: they produce no diagnostics, don't affect the score, and don't appear in the report's `project` lists. `**` crosses directories; `*` and `?` stay within one path segment.
- 12c7279Add the `pin-service-image` Compose rule (warning): flags service `image:` references with no tag or with the mutable `latest` tag, mirroring `pin-image-version` for Dockerfiles. Services with a `build:` context and `${VAR}`-templated references are skipped.
- 8aedfe8`--score` now exits non-zero on the same condition as every other mode: an `error`-severity diagnostic is present. It previously exited 1 when the score was below 50, so the same project could pass with `--json` and fail with `--score`. If you relied on the old threshold as a CI gate, compare the printed score yourself (e.g. `[ "$(docker-doctor . --score)" -ge 50 ]`).
Patch Changes
- d444521Check services with an empty body. `services: { web: }` was skipped by every Compose rule, so the least-configured service in the file produced zero findings. An empty service now reports missing restart policy, resource limits, and the rest like any other service.
- 3e1e0f9Recognize Docker Hardened Images (`dhi.io/…`): `prefer-slim-base` no longer flags them as heavy bases, and `no-root-user` treats their runtime variants as nonroot by default (`-dev` variants still report). Moving to a hardened base no longer costs score points.
v0.4.4
Patch Changes
- 035da22`clean-package-cache` no longer flags `RUN` instructions that keep apt/apk caches in BuildKit cache mounts (`--mount=type=cache,target=/var/cache/apt`, the pattern Docker documents). A cache mount elsewhere, or a bind mount, still warns.
- 186801aCompose diagnostics now include the line number of the offending service or key, so terminal output and the GitHub Action's file links point to the correct line instead of the top of the file. Keys that only exist through YAML merge keys (`<<: *anchor`) fall back to the service line.
- 74eba7bComment lines inside a line continuation no longer appear in an instruction's `raw` text. They made `sort-multiline-args` misread commented package lists as unsorted. Heredoc bodies keep their `#` lines, since those are shell content.
v0.4.3
Patch Changes
- 485a1eeSanitize scanned file paths before they reach a coding agent. Rule messages were already flattened, but the paths beside them were interpolated raw into both the handoff prompt and the `.docker-doctor/*.txt` reports, so a filename containing newlines could introduce its own line into an agent's instructions. Those per-rule reports now also flatten the message, matching the prompt.
- 37b3f7dWarn when a config names a rule or category that does not exist. Keys are matched exactly, so a typo'd rule key — or a category written as `security` instead of `Security` — used to be accepted and then silently match nothing, leaving a suppression the user believed was active doing nothing. Unknown keys are reported on stderr rather than failing the scan, so a config naming a rule removed in a later release still runs.
- 1cda220Fix `use-exec-form` missing bracket-wrapped `CMD`/`ENTRYPOINT` args that are not valid JSON. `CMD [node, index.js]` was accepted as exec form because the rule only checked for a leading `[` and a trailing `]`, but Docker treats anything that is not a JSON string array as shell form and runs it under `/bin/sh -c` — exactly what the rule exists to flag. Single-quoted elements and trailing commas were missed the same way.
- 8105153Fix `use-pipefail` so its verdict reflects how Docker actually runs a `RUN`.
- **`SHELL` is honoured.** The rule's own docs prescribe `SHELL ["/bin/bash", "-o", "pipefail", "-c"]` as the fix, but applying it never cleared the warning, because only the single `RUN` line was inspected. The active shell is now tracked per stage: a stage reached `FROM <previous stage>` inherits it, while a fresh base image or `scratch` resets it, matching BuildKit.
- **Exec-form `RUN` is judged on its own argv.** `RUN ["/bin/bash", "-o", "pipefail", "-c", "…"]` no longer warns. Conversely, a `SHELL` directive no longer suppresses the warning for an exec-form `RUN` that execs a different shell — Docker runs that argv directly, so the `SHELL` prefix never applies. **This surfaces new warnings on Dockerfiles that previously passed.**
- **Interior comments no longer flip the verdict.** The check reads the instruction's args, which have comment lines stripped, rather than the raw text. A `# TODO: use set -o pipefail` comment no longer silences a real finding, and a `# avoid curl | sh` comment no longer invents one.
- **Pipefail detection requires the option adjacent to its flag.** The previous bare-substring match exempted any line merely containing the word. Lines such as `set -o errexit && echo pipefail | tee log` and `ssh -o StrictHostKeyChecking=no h | grep pipefail` now warn. The new pattern is also linear, replacing one that backtracked pathologically on long `RUN` lines.
- 77f056aReword all 25 rule summaries into one imperative voice ("Run the container as a non-root user", "Use multi-stage builds", "Add a .dockerignore file") and format code tokens in help text as backticks (`USER node`, `apk add --no-cache`). `rules list`, `rules explain`, and the docs show the new wording; rule keys, severities, and diagnostic messages are unchanged.
- 4a600a4Route every rule through one `FROM` parser. `use-pipefail` carried its own regex, which required each `--flag` to precede the base image and lost the stage name when one followed it, so `FROM base --platform=linux/amd64 AS app` never registered `app` as a stage and later stages built on it stopped inheriting its `SHELL`. It now uses the shared `parseFromArgs`, as `pin-image-version` and `prefer-slim-base` already did, and `collectStageAliases` is built on it too.
- d78d960Teach `no-root-user` and `avoid-dev-dependencies` about multi-stage inheritance. A stage built `FROM <previous stage>` inherits that stage's image config and layers, but `no-root-user` reset `USER` to root on every `FROM`, reporting a false positive when the parent stage had already dropped privileges, and `avoid-dev-dependencies` audited only the instructions after the last `FROM`, missing dev installs whose layers the final image inherits from a parent stage. Both rules now resolve the stage chain through a shared `parseFromArgs` helper in the image-ref parser.
v0.4.2
Patch Changes
- a458b4cSanitize scanned-file content before it enters agent handoff prompts, label it as untrusted data, and ask for explicit confirmation before launching an agent with its skip-approvals flag.
- d235f97`categories` severity values other than "off" now actually override rule severities (previously they were silently ignored), and category handling moved into the core runners so programmatic API consumers get the same results as the CLI.
- f2a983aResolve YAML merge keys (`<<: *anchor`) when parsing Compose files, eliminating false `require-restart-policy` / `require-resource-limits` warnings on services that inherit those settings from an extension field.
- 37cca50Discovered Dockerfiles, Compose files and `.dockerignore` files are now returned in sorted order, so repeated scans of an unchanged project produce byte-identical JSON reports (apart from the timestamp) and stable PR-comment row ordering. Previously the concurrent workspace walk emitted files in I/O-completion order.
- 34dc094Fix the Dockerfile parser treating shell `<<` (arithmetic, here-strings) as a heredoc opener, which silently swallowed the rest of the file and produced false diagnostics.
- bfde65aDeclare `engines.node >= 20.11.0`. The CLI already required Node 20.11+ at runtime (`Array.prototype.toSorted`, `import.meta.dirname`); npm now warns at install time instead of crashing at first run on older Node.
- 3a41a43Add a "What it catches" section with a before/after layer-ordering example, and correct the rule count to 25.
- bba2a18Three rule-accuracy fixes: `no-root-user` now detects `USER root:root`, `USER root:0` and other `user:group` root spellings; `prefer-slim-base` recognizes minimal images by name (`alpine`, `busybox`, distroless) instead of only by tag, removing false positives on `alpine:3.19`; `use-dockerignore` now requires a `.dockerignore` next to the Dockerfile or at the scan root, instead of accepting any `.dockerignore` anywhere in the workspace.
- fc5569dExit with status 2 when a Dockerfile or Compose file cannot be read or parsed, and list the affected files on stderr. Previously an unparseable file contributed no diagnostics and the run could report a perfect score with exit 0 — a green CI gate over a file that was never analyzed.
- a581f49The interactive wizard now scaffolds `.github/workflows/docker-doctor.yml` into the scanned directory instead of the current working directory, and asks before overwriting an existing workflow file (declining, or a non-interactive run, keeps the existing file).
v0.4.1
Patch Changes
- 152c0c8Update document the `--global` install flag and the Docker Sandboxes kit.
v0.4.0
Minor Changes
- d2a7a45Add `--global` flag to `docker-doctor install` — installs the agent skill into each agent's global skills directory (e.g. `~/.claude/skills`) instead of the current project. Groundwork for the Docker Sandboxes kit.
v0.3.4
Patch Changes
- 23be7e4Tag the shared score URL with `utm_source=cli&utm_medium=terminal` so site analytics can tell the person who ran the scan apart from the visitors who follow their shared link.
v0.3.3
Patch Changes
v0.3.2
Patch Changes
- 1d838c6Add a GitHub Action for running Docker Doctor in CI. `uses: PunGrumpy/docker-doctor@v0` scans the repository on every pull request and posts a sticky summary comment: a per-file status table, the health score linking to a shareable score card, and every finding linked to the exact line at the scanned commit. The gate is advisory by default and can be raised with `blocking: warning | error` (pull requests only — pushes never fail), and the score and per-severity counts are exposed as step outputs. The action is versioned in lockstep with the CLI: every release moves a floating major tag (`v0`, later `v1`) plus an exact `v<version>` tag for reproducible pins.
v0.3.1
Patch Changes
- 3546391Add coding-agent integration: a `docker-doctor install` command that installs the bundled agent skill for any agent-install-supported coding agent (Claude Code, Cursor, Codex, OpenCode, and more), and a post-scan handoff that replaces the old "View rules list" prompt — when a scan finds issues, the CLI now offers to launch a detected agent (`claude`, `codex`, `cursor-agent`) with the issues as its prompt, or copy that prompt to the clipboard. Handoffs write the full report to `.docker-doctor/` (auto-gitignored) and install the skill for the chosen agent.
- e6e7e88Export the `DockerDoctorConfig` type (plus `RuleCategory`) and a `defineConfig` helper for typed `docker-doctor.config.ts` files, and fix the config type's `categories` field to accept a subset of categories (`Partial<Record<…>>`) — matching the validator's actual behavior and the documented examples.
- b730028Support `docker-doctor.config.yaml` / `.yml` config files (resolved after `.json`, and via `--config`). A JSON Schema generated from the rule set is published at https://docker-doctor.vercel.app/schema.json for editor autocomplete/validation in YAML (`# yaml-language-server: $schema=…`) and JSON (`"$schema"` key) configs.
v0.3.0
Minor Changes
- 77aed82Replace the saturating score formula with a monotonic, asymptotic curve.
- Score values have changed. A given set of diagnostics will now produce a different numeric score than before (e.g. a single error used to score 90, now scores ~87; a project that used to floor at 0 will now show a small nonzero number that keeps decreasing as issues pile up).
- Existing badges, dashboards, or stored scores will show different numbers after upgrading — this is expected, not a regression.
- The `Excellent 🏆` / `Good ✅` / `Needs Work ⚠️` / `Critical 🚨` label thresholds (>=90 / >=75 / >=50 / below) are unchanged.
- The JSON report now includes a `schemaVersion` field (currently `2`) to make future score/shape changes detectable.
Patch Changes
- ff17a27The Dockerfile parser now understands heredoc (`<<EOF`) syntax — bodies are folded into the owning instruction instead of being mis-parsed as separate instructions — so content-based rules now inspect heredoc commands and phantom instructions no longer appear.
- 21fb2e8`effect` is no longer a runtime dependency of `@docker-doctor/cli`. The single `Schema.Struct` used to validate `docker-doctor.config.*` and the three `Data.TaggedError` error classes (`ConfigError`, `ParseError`, `FileNotFoundError`) have been replaced with a hand-rolled validator and plain `Error` subclasses that preserve the exact same validation rules, error `_tag` discriminants, and public API. The package's public types no longer reference `effect/Schema`, so consumers no longer pull in a pinned pre-release beta package for a tiny surface area.
- 9b855c5Fixed the "Docs:" link printed after every scan. It previously pointed at `https://github.com/PunGrumpy/docker-doctor/docs`, which 404s (there is no `docs/` directory in the repository). It now points at `https://docker-doctor.vercel.app`, the project's actual documentation site.
- 859f48cFix four rule-specificity bugs in the Dockerfile rule engine:
- `no-root-user` now resets its tracked user at each `FROM` (build stage), instead of letting a `USER` set in an earlier stage (e.g. a builder) silently satisfy the check for a later stage that never sets one. Multi-stage Dockerfiles may now surface a new diagnostic here.
- `no-add-remote`, `prefer-copy-over-add`, and `use-dockerignore` now read the first non-flag operand of `ADD`/`COPY` instead of always taking the first whitespace-separated token, so a leading flag like `--chown` or `--from` no longer silently disables the check (e.g. `ADD --chown=node:node https://...` now correctly trips `no-add-remote`). As a side effect, `use-dockerignore` now explicitly skips `COPY --from=<stage>` since that never reads the build context. These fixes may surface new diagnostics.
- `no-secrets-in-env` no longer matches secret keywords as an unanchored substring, so keys like `AUTHOR` or `OAUTH_ISSUER_URL` no longer false-positive as "potential secret found" (this is the only error-severity rule, so this previously failed CI on Dockerfiles with no secrets). Genuine segment matches like `DB_PASSWORD` still match. This removes diagnostics.
- `order-layers` now resets its copy-tracking at each build stage, so a copy-everything in an earlier stage no longer implicates an install command in a later, correctly-ordered stage, and no longer substring-matches `"src"` anywhere in a path (e.g. `/usr/src/lib`, `mysrcdir`). This removes diagnostics.
- a5641abPiped or redirected `--json`/`--score` output is no longer silently truncated. The scan action's output paths used `process.exit()` right after `console.log()`, which could abort the process before the async write to a pipe/file finished flushing. They now set `process.exitCode` and return, letting Node exit naturally once stdout has fully drained. Exit codes (`--score` below 50 exits 1; `--json`/default exit 1 on any error-severity diagnostic) are unchanged.
- b4cc9a3Fix image-reference parsing in `pin-image-version` and `prefer-slim-base`, which both used to split on the first `:` and got several common forms wrong:
- Images with a registry port (`myregistry.example.com:5000/team/app`) are no longer mistaken for pinned/tagged just because the port number looks like a tag. `pin-image-version` now correctly flags these as unpinned.
- Digest-pinned images (`node@sha256:...`) are no longer misread as an untagged full-OS image by `prefer-slim-base` — the strongest possible pin is now recognized and silently accepted by both rules.
- Multi-stage build aliases (`FROM builder`, referencing an earlier `FROM ... AS builder`) are no longer flagged as unpinned or non-slim.
- `${ARG}`-driven base images are skipped instead of producing a false diagnostic, since the actual image can't be determined statically.
v0.2.0
Minor Changes
- ccfca12Replace `readline/promises` text input with fully interactive keyboard-driven prompts.
- `askConfirm`: vertical Yes/No layout with arrow keys, vim keys (h/j/k/l), and y/n shortcuts
- `askSelect`: vertical option list with up/down / j/k navigation
- Hidden cursor during prompts; restored on exit, Ctrl+C, SIGINT, and SIGTERM
- Falls back gracefully to default values in non-TTY (CI/pipe) environments
Patch Changes
- c47c581Reduce score animation duration from 2 s to 300 ms (20 frames × 15 ms). Guard animation behind `isTTY`, `CI`, `NO_ANIMATION`, `TERM=dumb`, and `NODE_ENV=test` checks to ensure a clean experience in non-interactive environments.
- 0a04d98Fix workspace discovery to correctly track and validate `.dockerignore` files, resolving false-positive warnings in the `useDockerignore` performance rule.
- a744994Fix `no-secrets-in-env` rule to support space-separated `ENV KEY VALUE` format, ensuring hardcoded credentials in this format are correctly detected by the linter.
- 60b743dFix `FROM` and `COPY`/`ADD` instruction parsing in rules to correctly skip option flags (e.g. `--platform`, `--chown`), preventing false-positive diagnostics or layer ordering check failures.
v0.1.0
Minor Changes
- c11718bInitial release
Docker Doctor is an independent open source project. It is not affiliated with or endorsed by Docker, Inc. Docker is a trademark of Docker, Inc.