npm package: @infograb/docker-slim-advisor
Description: CLI tool to analyze Dockerfiles and recommend image size optimizations — reduce build size, catch bloat, improve layer efficiency
Latest version: 0.1.0

# docker-slim-advisor

Static Dockerfile analyzer that recommends image size optimizations — no Docker build required.

```bash
npx @infograb/docker-slim-advisor analyze ./Dockerfile
```

---

## Quick Start

```bash
npx @infograb/docker-slim-advisor ./Dockerfile
```

**Example output** (against a typical Node.js app):

```
Docker Slim Advisor
--------------------------------------------------

  File:       Dockerfile
  Base Image: node:18

Size Prediction

  Before: 1.1GB
  After:  226.6MB

  [██████░░░░░░░░░░░░░░░░░░░░░░░░]

  Estimated savings: 904.9MB (80% reduction)

Findings (2)

  [HIGH] Use node:18-slim instead of node:18 (DSA001)  Line 1
    Switching from node:18 (1.0GB) to node:18-slim (200MB) saves ~800MB (80% reduction).
    Fix: FROM node:18-slim
    Saves ~800.0MB

  [HIGH] Broad COPY/ADD without .dockerignore optimization (DSA004)  Line 5
    `COPY .` copies the entire build context. Without a comprehensive .dockerignore,
    this includes node_modules, .git, build artifacts, and other unnecessary files.
    Fix: Add node_modules, .git, dist, build, .env to .dockerignore
    Saves ~104.9MB
```

---

## Features

- **5 optimization rules** — alpine/slim base swap, RUN layer merge, apt/apk cache cleanup, `.dockerignore` detection, unnecessary package removal
- **3 output formats** — terminal (TTY-aware), JSON (versioned schema), Markdown
- **Size prediction** — before/after estimates with ±30% accuracy, no `docker build` needed
- **CI/CD ready** — structured exit codes, `NO_COLOR` support, stderr/stdout separation
- **Fast** — analysis completes in under 1 second for typical Dockerfiles

---

## Installation

**Global install:**

```bash
npm install -g @infograb/docker-slim-advisor
docker-slim-advisor ./Dockerfile
```

**One-off with npx (no install):**

```bash
npx @infograb/docker-slim-advisor ./Dockerfile
```

**Requirements:** Node.js >= 18

---

## Usage

```
docker-slim-advisor [dockerfile] [options]

Arguments:
  dockerfile            Path to Dockerfile (default: "Dockerfile")

Options:
  -f, --format <format>    Output format: terminal, json, markdown (default: "terminal")
  -s, --severity <level>   Minimum severity to report: LOW, MEDIUM, HIGH
  -V, --version            Print version
  -h, --help               Display help
```

**Examples:**

```bash
# Analyze Dockerfile in current directory
docker-slim-advisor

# Analyze a specific file
docker-slim-advisor path/to/Dockerfile

# JSON output (machine-readable)
docker-slim-advisor --format json ./Dockerfile

# Only report HIGH severity findings
docker-slim-advisor --severity HIGH ./Dockerfile

# Markdown report for documentation
docker-slim-advisor --format markdown ./Dockerfile > report.md
```

### Exit Codes

| Code | Meaning |
|------|---------|
| `0`  | No HIGH severity findings |
| `1`  | One or more HIGH findings present |
| `2`  | Error (file not found, parse failure, etc.) |

---

## Output Formats

### Terminal (default)

Color and emoji output when connected to a TTY. Plain text in pipes. Respects `NO_COLOR` environment variable.

```bash
docker-slim-advisor ./Dockerfile
```

### JSON

Versioned schema suitable for downstream tooling.

```bash
docker-slim-advisor --format json ./Dockerfile
```

```json
{
  "schemaVersion": 1,
  "dockerfilePath": "Dockerfile",
  "isMultiStage": false,
  "baseImage": "node:18",
  "estimatedBeforeSize": {
    "totalBytes": 1131500000,
    "humanReadable": "1.1GB"
  },
  "estimatedAfterSize": {
    "totalBytes": 226642400,
    "humanReadable": "227MB"
  },
  "sizeReductionPercent": 80,
  "totalFindings": 2,
  "findings": [
    {
      "ruleId": "DSA001",
      "severity": "HIGH",
      "line": 1,
      "title": "Use node:18-slim instead of node:18",
      "description": "Switching from node:18 (1.0GB) to node:18-slim (200MB) saves ~800MB.",
      "fix": "FROM node:18-slim",
      "estimatedSavingsBytes": 800000000
    }
  ]
}
```

### Markdown

```bash
docker-slim-advisor --format markdown ./Dockerfile
```

Produces a GitHub-compatible report with a findings table and per-rule detail sections. Suitable for PR comments or documentation.

---

## CI/CD Integration

Use exit codes to fail pipelines on HIGH findings:

```bash
# Fail CI if any HIGH findings are found
docker-slim-advisor ./Dockerfile
if [ $? -eq 1 ]; then
  echo "Image optimization issues detected. Review the findings above."
  exit 1
fi
```

**GitHub Actions example:**

```yaml
- name: Analyze Dockerfile
  run: npx @infograb/docker-slim-advisor ./Dockerfile --severity HIGH
```

**Pipe-friendly (no color/emoji):**

```bash
# NO_COLOR disables ANSI codes; plain text is always pipe-safe
NO_COLOR=1 docker-slim-advisor ./Dockerfile | tee advisor-report.txt
```

**JSON in scripts:**

```bash
FINDINGS=$(docker-slim-advisor --format json ./Dockerfile | jq '.totalFindings')
echo "Found $FINDINGS optimization opportunities"
```

---

## How It Works

`docker-slim-advisor` performs **static analysis** — it reads and parses your Dockerfile as text, with no Docker daemon or image pull required.

1. **Parse** — Dockerfile is tokenized into a typed instruction AST (`FROM`, `RUN`, `COPY`, `ADD`, etc.). Multi-line `RUN` with backslash continuations are handled correctly.
2. **Detect** — Multi-stage builds (`multiple FROM` instructions) are detected and reported as already optimized.
3. **Evaluate rules** — Each of the 5 optimization rules inspects the AST and emits findings with line numbers, rule IDs, and estimated savings.
4. **Estimate sizes** — A bundled JSON database of 170+ image tags provides base image sizes. Layer size heuristics compute before/after predictions (±30% accuracy).
5. **Format output** — The result is rendered in the requested format with TTY detection and `NO_COLOR` support.

---

## Optimization Rules

| Rule ID | Severity | Description |
|---------|----------|-------------|
| `DSA001` | HIGH | Switch to a slimmer base image (e.g. `node:18` → `node:18-slim`, `node:18-alpine`) |
| `DSA002` | MEDIUM | Merge multiple `RUN` instructions into one to reduce image layers |
| `DSA003` | MEDIUM | Clean apt/apk cache in the same `RUN` layer (`--no-install-recommends`, `rm -rf /var/lib/apt/lists/*`) |
| `DSA004` | HIGH | Add or improve `.dockerignore` to avoid copying unnecessary files via `COPY .` |
| `DSA005` | LOW | Remove unnecessary packages installed for build-time only (e.g. `curl`, `wget`, `git`) |

---

## Supported Base Images

The bundled database covers **170+ image tags** across **53 base images**, including:

| Image | Image | Image |
|-------|-------|-------|
| `alpine` | `node` | `python` |
| `ubuntu` | `debian` | `golang` |
| `nginx` | `postgres` | `redis` |
| `rust` | `ruby` | `php` |
| `maven` | `gradle` | `eclipse-temurin` |
| `mongo` | `mysql` | `elasticsearch` |
| `gcr.io/distroless/*` | `mcr.microsoft.com/dotnet/*` | `pytorch/pytorch` |

Tag variants (e.g. `latest`, `slim`, `alpine`, `bookworm`, version-pinned) are included where available.

---

## Contributing

1. Fork the repository and create a feature branch.
2. Install dependencies: `npm install`
3. Run tests: `npm test`
4. Check types: `npm run lint`
5. Submit a pull request with a clear description of the change.

To add a new optimization rule, create `src/rules/your-rule.ts` implementing the `Rule` interface, then register it in `src/rules/index.ts`.

---

## License

MIT