🩺 yaml-doctor
YAML Linter & Security Scanner for DevOps Engineers
Validate and lint Kubernetes manifests, Docker Compose files, GitHub Actions workflows, GitLab CI pipelines, and generic YAML with 60+ built-in rules covering security, reliability, and best practices.
✨ Features
- 🔍 60+ Lint Rules — Security, reliability, and best practice checks
- 🎯 Auto-Detection — Automatically identifies Kubernetes, Docker Compose, GitHub Actions, GitLab CI, and Helm files
- 📊 Grading System — A+ to F grades with detailed scoring
- 🌐 HTML Dashboard — Beautiful dark-theme HTML reports with severity charts
- 📋 JSON Export — Machine-readable reports for CI/CD integration
- 🔧 Fix Suggestions — Actionable remediation for every finding
- 🎮 Demo Mode — Try it instantly with built-in sample files
- 🚀 Zero Config — Works out of the box, no configuration needed
📦 Installation
pip install yaml-doctor
🚀 Quick Start
# Lint a single file
yaml-doctor lint deployment.yaml
# Scan a directory recursively
yaml-doctor scan ./k8s/
# Run demo with sample files
yaml-doctor demo
# Show all 60 rules
yaml-doctor rules
# Get fix suggestions
yaml-doctor fix deployment.yaml
# Export HTML dashboard
yaml-doctor scan . --html report.html
# Export JSON report
yaml-doctor lint config.yaml -j report.json
🎯 Supported File Types
| Type | Detection | Rules |
|---|---|---|
| Kubernetes | apiVersion + kind |
20 rules (K8S001-K8S020) |
| Docker Compose | services + image/build |
12 rules (DC001-DC012) |
| GitHub Actions | .github/workflows/ + on/jobs |
10 rules (GHA001-GHA010) |
| GitLab CI | .gitlab-ci.yml + stages/script |
10 rules (GL001-GL010) |
| Helm | Chart.yaml / values.yaml |
K8s rules applied |
| Generic YAML | Any .yml/.yaml file |
8 rules (YML001-YML008) |
🔒 Security Rules
Kubernetes (20 rules)
| Rule | Severity | Description |
|---|---|---|
| K8S001 | 🔴 CRITICAL | Container running as root |
| K8S004 | 🔴 CRITICAL | Privileged container |
| K8S002 | 🟠 HIGH | Missing resource limits |
| K8S003 | 🟠 HIGH | Missing resource requests |
| K8S005 | 🟠 HIGH | Using :latest image tag |
| K8S006 | 🟠 HIGH | Missing liveness probe |
| K8S011 | 🟠 HIGH | Host network enabled |
| K8S012 | 🟠 HIGH | Host PID enabled |
| K8S016 | 🟠 HIGH | Secrets in environment variables |
| K8S007 | 🟡 MEDIUM | Missing readiness probe |
| K8S008 | 🟡 MEDIUM | Read-only filesystem not set |
| K8S013 | 🟡 MEDIUM | Single replica deployment |
| K8S014 | 🟡 MEDIUM | Privilege escalation allowed |
| K8S017 | 🟡 MEDIUM | Missing update strategy |
| K8S018 | 🟡 MEDIUM | Capabilities not dropped |
| K8S020 | 🟡 MEDIUM | Missing restart policy |
| K8S009 | 🔵 LOW | Missing recommended labels |
| K8S015 | 🔵 LOW | Missing PodDisruptionBudget |
| K8S019 | 🔵 LOW | No anti-affinity rules |
| K8S010 | ⚪ INFO | Missing namespace |
Docker Compose (12 rules)
| Rule | Severity | Description |
|---|---|---|
| DC002 | 🔴 CRITICAL | Privileged container |
| DC001 | 🟠 HIGH | Using :latest tag |
| DC005 | 🟠 HIGH | Secrets in environment |
| DC009 | 🟠 HIGH | Host volume with write access |
| DC012 | 🟡 MEDIUM | Host network mode |
| DC003 | 🟡 MEDIUM | No restart policy |
| DC004 | 🟡 MEDIUM | No healthcheck defined |
| DC007 | 🟡 MEDIUM | Exposed to all interfaces |
| DC011 | 🟡 MEDIUM | No depends_on |
| DC006 | 🔵 LOW | No resource limits |
| DC010 | 🔵 LOW | No logging configuration |
| DC008 | ⚪ INFO | Deprecated version key |
GitHub Actions (10 rules)
| Rule | Severity | Description |
|---|---|---|
| GHA001 | 🔴 CRITICAL | Mutable action reference (using @main) |
| GHA002 | 🟠 HIGH | Persist credentials enabled |
| GHA003 | 🟠 HIGH | Secrets in run commands |
| GHA009 | 🟠 HIGH | Script injection risk |
| GHA004 | 🟡 MEDIUM | Overly broad permissions |
| GHA005 | 🟡 MEDIUM | No job timeout |
| GHA006 | 🟡 MEDIUM | pull_request_target trigger |
| GHA007 | 🔵 LOW | No concurrency control |
| GHA008 | 🔵 LOW | Unversioned runner image |
| GHA010 | ⚪ INFO | Missing workflow name |
GitLab CI (10 rules)
| Rule | Severity | Description |
|---|---|---|
| GL001 | 🟠 HIGH | Secrets in script blocks |
| GL007 | 🟠 HIGH | allow_failure on security jobs |
| GL002 | 🟡 MEDIUM | No retry configuration |
| GL004 | 🟡 MEDIUM | Using :latest image |
| GL005 | 🟡 MEDIUM | No timeout set |
| GL009 | 🟡 MEDIUM | No rules/conditions |
| GL003 | 🔵 LOW | No cache defined |
| GL008 | 🔵 LOW | No artifacts defined |
| GL010 | 🔵 LOW | Missing job description |
| GL006 | ⚪ INFO | No stages defined |
Generic YAML (8 rules)
| Rule | Severity | Description |
|---|---|---|
| YML005 | 🟠 HIGH | Hardcoded credentials |
| YML001 | 🟡 MEDIUM | Inconsistent indentation |
| YML006 | 🟡 MEDIUM | Duplicate keys |
| YML002 | 🔵 LOW | Trailing whitespace |
| YML003 | 🔵 LOW | Line too long (>200 chars) |
| YML007 | 🔵 LOW | Empty values |
| YML004 | ⚪ INFO | Missing document start marker |
| YML008 | ⚪ INFO | File too long (>1000 lines) |
📊 Grading System
| Grade | Score | Description |
|---|---|---|
| A+ | 95-100 | Excellent — production ready |
| A | 85-94 | Great — minor improvements possible |
| B | 75-84 | Good — some issues to address |
| C | 65-74 | Fair — significant improvements needed |
| D | 50-64 | Poor — many issues found |
| F | 0-49 | Failing — critical issues present |
Score deductions per finding:
- 🔴 Critical: -15 points
- 🟠 High: -8 points
- 🟡 Medium: -3 points
- 🔵 Low: -1 point
- ⚪ Info: 0 points
🖥️ CLI Commands
yaml-doctor lint <file>
Lint a single YAML file with auto-detection.
yaml-doctor lint deployment.yaml
yaml-doctor lint docker-compose.yml --html report.html
yaml-doctor lint .github/workflows/ci.yml -j report.json
yaml-doctor scan <directory>
Scan all YAML files in a directory.
yaml-doctor scan ./k8s/
yaml-doctor scan . --html dashboard.html
yaml-doctor scan ./configs --no-recursive
yaml-doctor demo
Run a demo with built-in sample files.
yaml-doctor demo
yaml-doctor demo --type kubernetes
yaml-doctor demo --type compose
yaml-doctor demo --html demo-report.html
yaml-doctor rules
Display all 60 available lint rules.
yaml-doctor rules
yaml-doctor fix <file>
Show fix suggestions for all findings.
yaml-doctor fix deployment.yaml
🔌 CI/CD Integration
GitHub Actions
- name: YAML Lint
run: |
pip install yaml-doctor
yaml-doctor scan . --html report.html -j report.json
- name: Upload Report
uses: actions/upload-artifact@v4
with:
name: yaml-doctor-report
path: report.html
GitLab CI
yaml-lint:
stage: test
script:
- pip install yaml-doctor
- yaml-doctor scan . --html report.html -j report.json
artifacts:
paths:
- report.html
- report.json
Pre-commit Hook
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: yaml-doctor
name: yaml-doctor
entry: yaml-doctor lint
language: python
types: [yaml]
additional_dependencies: [yaml-doctor]
📁 Project Structure
yaml-doctor/
├── yaml_doctor/
│ ├── __init__.py # Package version
│ ├── __main__.py # python -m support
│ ├── cli.py # Click CLI commands
│ ├── scanner.py # Core scanning engine
│ ├── models.py # Data models & enums
│ ├── rules.py # Rule registry (60 rules)
│ ├── utils.py # Helper utilities
│ ├── demo.py # Demo sample data
│ ├── analyzers/
│ │ ├── __init__.py # File type detection
│ │ ├── kubernetes.py # 20 K8s rules
│ │ ├── compose.py # 12 Docker Compose rules
│ │ ├── github_actions.py # 10 GitHub Actions rules
│ │ ├── gitlab_ci.py # 10 GitLab CI rules
│ │ └── yaml_lint.py # 8 generic YAML rules
│ └── output/
│ ├── console.py # Rich terminal output
│ └── html_report.py # HTML dashboard reports
├── tests/ # 188 tests
├── pyproject.toml
├── LICENSE
└── README.md
🧪 Development
git clone https://github.com/SanjaySundarMurthy/yaml-doctor.git
cd yaml-doctor
pip install -e ".[dev]"
pytest
ruff check .
📄 License
MIT License — see LICENSE for details.
👨💻 Author
Metadata
Release files for yaml-doctor-cli 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| yaml_doctor_cli-1.0.0.tar.gz | 34.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yaml_doctor_cli-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.7 kB
Release files / yaml_doctor_cli-1.0.0.tar.gz
| Download URL | yaml_doctor_cli-1.0.0.tar.gz |
|---|---|
| Size | 34.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6810d9692893c89d5ce19c136907539510ac59e0ca13842ebb21036e4b18c3bf
|
|
BLAKE2b-256 checksum How to use checksums |
2bbfb9b981f41cb4e32c99e07d6db15e0b100dbaf346086497da8b385000b506
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Release files / yaml_doctor_cli-1.0.0-py3-none-any.whl
| Download URL | yaml_doctor_cli-1.0.0-py3-none-any.whl |
|---|---|
| Size | 33.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d22c4d915e409a1b2bef7593f7bc8bf01858542b717d9546e6d4c0c7408b976
|
|
BLAKE2b-256 checksum How to use checksums |
cf46039cad81487025c49b8d6427df689dafebb70fcfba41c3cf0e108f386948
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.9
|
Security for yaml-doctor-cli 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.