Metadata-Version: 2.4
Name: compose-auditor
Version: 0.2.0
Summary: Docker Compose security and best-practice linter
Author: Fred Wojo
License: MIT
Keywords: docker,compose,security,lint,devops
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Requires-Dist: pyyaml>=6.0
Requires-Dist: colorama>=0.4
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Dynamic: license-file

# compose-auditor

Docker Compose security and best-practice linter. Catches common misconfigs, security issues, and operational gaps before they reach production.

## Install

```bash
# From source (recommended for local use)
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

# Or directly into a venv
pip install compose-auditor
```

## Usage

```bash
# Basic lint — colored text output, exits 1 on CRITICAL
compose-auditor lint docker-compose.yml

# Lint a specific path
compose-auditor lint ~/Media/docker-compose.yml

# JSON output (for CI pipelines)
compose-auditor lint docker-compose.yml --format json

# Control exit behavior
compose-auditor lint docker-compose.yml --fail-on warning   # exit 1 on WARNING+
compose-auditor lint docker-compose.yml --fail-on never     # always exit 0

# No color (for logs)
compose-auditor lint docker-compose.yml --no-color

# Homelab profile — suppresses noisy rules irrelevant to personal stacks
compose-auditor lint docker-compose.yml --profile homelab

# Ignore specific rules (repeatable)
compose-auditor lint docker-compose.yml --ignore SEC002 --ignore VOL001

# Use a config file explicitly
compose-auditor lint docker-compose.yml --config .compose-auditor.yml
```

## Profiles

Profiles adjust severity for context. The `homelab` profile is built-in and tuned for personal self-hosted stacks.

| Rule   | Default  | homelab  |
|--------|----------|----------|
| VOL001 | INFO     | suppressed |
| RES002 | INFO     | suppressed |
| OPS003 | INFO     | suppressed |
| NET002 | WARNING  | INFO     |
| IMG001 | WARNING  | INFO     |
| RES001 | WARNING  | INFO     |

## Config File

Auto-discovered from `.compose-auditor.yml` in the current directory, then the home directory. Override with `--config`.

```yaml
# .compose-auditor.yml
profile: homelab

ignore:
  - OPS003      # global — suppressed for all services

rules:
  NET002: INFO  # downgrade globally

services:
  traefik:
    ignore:
      - NET001  # traefik legitimately uses host networking
  db:
    ignore:
      - SEC002  # postgres image sets its own user
```

Supported keys:
- `profile` — apply a named profile (`homelab`)
- `ignore` — list of rule IDs to suppress globally
- `rules` — map of rule ID → new severity (`CRITICAL`, `WARNING`, `INFO`)
- `services.<name>.ignore` — per-service rule suppression

## LSIO Auto-Detection

SEC002 (running as root / no user directive) is automatically suppressed for LinuxServer.io images. These images manage their own user mapping via `PUID`/`PGID` environment variables.

Matched prefixes:
- `lscr.io/linuxserver/`
- `linuxserver/`
- `ghcr.io/linuxserver/`

## Rules

| Rule ID  | Severity | Description |
|----------|----------|-------------|
| SEC001   | CRITICAL | Privileged container |
| SEC002   | CRITICAL/WARNING | Running as root or no user directive |
| SEC003   | CRITICAL | Docker socket mounted |
| SEC004   | WARNING  | Bind mount to sensitive host path (/etc, /proc, /sys, etc.) |
| SEC005   | CRITICAL | Plain-text secrets in environment variables |
| NET001   | CRITICAL | Host network mode |
| NET002   | WARNING  | Port bound to 0.0.0.0 (all interfaces) |
| NET003   | CRITICAL | Duplicate host port binding across services |
| OPS001   | INFO     | No restart policy |
| OPS002   | INFO/WARNING | No healthcheck or healthcheck disabled |
| OPS003   | INFO     | No logging configuration |
| RES001   | WARNING  | No memory limit |
| RES002   | INFO     | No CPU limit |
| IMG001   | WARNING  | Using :latest (or untagged) image |
| VOL001   | INFO     | Volume mounted read-write (consider :ro) |
| DEP001   | INFO     | Service referenced in env/links without depends_on |

NET003 is protocol-aware — TCP and UDP bindings on the same port number are treated as distinct and do not trigger a false positive.

## Exit Codes

| Code | Meaning |
|------|---------|
| 0    | No issues at or above --fail-on threshold |
| 1    | One or more findings at or above threshold |
| 2    | Parse error (invalid YAML or not a compose file) |

## JSON Output Schema

```json
{
  "file": "/path/to/docker-compose.yml",
  "summary": {
    "CRITICAL": 3,
    "WARNING": 7,
    "INFO": 12
  },
  "findings": [
    {
      "severity": "CRITICAL",
      "rule_id": "SEC001",
      "service": "web",
      "message": "Container runs in privileged mode",
      "detail": "..."
    }
  ]
}
```
