{"id":51043658,"url":"https://github.com/axeforging/yamlspec","last_synced_at":"2026-06-22T12:02:06.482Z","repository":{"id":359388967,"uuid":"1192944409","full_name":"AxeForging/yamlspec","owner":"AxeForging","description":"YAML test framework with RSpec-like assertions","archived":false,"fork":false,"pushed_at":"2026-05-21T16:45:56.000Z","size":294,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T01:35:23.951Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AxeForging.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-26T18:04:05.000Z","updated_at":"2026-05-21T16:43:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/AxeForging/yamlspec","commit_stats":null,"previous_names":["axeforging/yamlspec"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/AxeForging/yamlspec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxeForging%2Fyamlspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxeForging%2Fyamlspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxeForging%2Fyamlspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxeForging%2Fyamlspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AxeForging","download_url":"https://codeload.github.com/AxeForging/yamlspec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxeForging%2Fyamlspec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34647750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-22T12:02:02.404Z","updated_at":"2026-06-22T12:02:06.477Z","avatar_url":"https://github.com/AxeForging.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yamlspec\n\n[![CI](https://github.com/AxeForging/yamlspec/actions/workflows/pr.yml/badge.svg)](https://github.com/AxeForging/yamlspec/actions/workflows/pr.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/AxeForging/yamlspec.svg)](https://pkg.go.dev/github.com/AxeForging/yamlspec)\n[![Go Report Card](https://goreportcard.com/badge/github.com/AxeForging/yamlspec)](https://goreportcard.com/report/github.com/AxeForging/yamlspec)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nYAML test framework with RSpec-like assertions. Validate any YAML manifests — Kubernetes, Helm, Kustomize, or plain files — with a clean, readable syntax.\n\n![yamlspec demo](docs/demo.gif)\n\n**Documentation:** [docs index](docs/index.md) · [spec.yaml format](docs/spec-format.md) · [recipes](docs/recipes.md) · [troubleshooting](docs/troubleshooting.md) · [CI workflow](docs/reusable-workflow.md)\n\n## Why yamlspec?\n\n- **RSpec-like syntax** — `describe`/`it`/`should` vocabulary developers already know\n- **20+ assertion operators** — equality, comparisons, strings, regex, existence, arrays, sets\n- **Engine agnostic** — test plain YAML, Helm charts, Kustomize overlays, or anything that outputs YAML\n- **7 output formats** — console, JSON, YAML, Markdown, enriched Markdown (GitHub PRs), HTML, JUnit XML\n- **Single-file HTML reports** — searchable, filterable standards reports with specs and rendered manifests embedded\n- **Reusable CI workflow** — one-line GitHub Actions setup with PR commenting\n- **Zero YAML dependencies** — no Helm or Kustomize libraries; rendering happens via `pre_run` shell commands\n- **5 direct Go dependencies** — minimal, fast, easy to build\n\n## Install\n\n```bash\n# Go install (any platform with Go 1.25+)\ngo install github.com/AxeForging/yamlspec@latest\n\n# Linux (amd64)\ncurl -sSL https://github.com/AxeForging/yamlspec/releases/latest/download/yamlspec-linux-amd64.tar.gz | tar xz\nsudo mv yamlspec /usr/local/bin/\n\n# macOS (Apple Silicon)\ncurl -sSL https://github.com/AxeForging/yamlspec/releases/latest/download/yamlspec-darwin-arm64.tar.gz | tar xz\nsudo mv yamlspec /usr/local/bin/\n```\n\nOther platforms (linux/arm64, darwin/amd64, windows/{amd64,arm64}) on the [releases page](https://github.com/AxeForging/yamlspec/releases/latest).\n\n### From source\n\n```bash\ngit clone https://github.com/AxeForging/yamlspec.git\ncd yamlspec\nmake install        # builds and installs to /usr/local/bin\n```\n\n## Quick Start\n\n```bash\n# Scaffold a test\nyamlspec init my-feature --test-dir tests\n\n# Run tests\nyamlspec validate --test-dir tests\n\n# Filter by tag\nyamlspec validate --tag deployment\n\n# Multiple output formats\nyamlspec validate --json-output results.json --junit-output results.xml\nyamlspec report --output yamlspec-report.html\nyamlspec serve --file yamlspec-report.html\n\n# Parallel execution\nyamlspec validate --workers 4\n```\n\n## Sample output\n\n```\n  ✓ Production deployment\n    Deployment configuration\n      [select: select(.kind == \"Deployment\")]\n      ✓ have 3 replicas\n      ✓ use a pinned image tag\n      ✓ have resource limits\n      ✓ be in production namespace\n\n  ✗ Staging overlay\n    Deployment\n      [select: select(.kind == \"Deployment\")]\n      ✓ be in staging namespace\n      ✗ have 2 replicas\n\nFailures:\n\n  1) Staging overlay \u003e Deployment \u003e have 2 replicas\n     expected 2, got 1\n\n26 assertions, 25 passed, 1 failed\nFinished in 0.18s\n```\n\nIn CI, the same run also produces a JUnit XML, an enriched-Markdown summary\n(rendered as a GitHub PR comment and on the workflow run page), and inline\n`::error file=...,line=...::` annotations against `spec.yaml` lines.\n\n## Usage with Helm Charts\n\nUse `pre_run` to render templates before validation:\n\n```yaml\n# tests/production/spec.yaml\nname: \"Production values\"\ntags: [\"production\", \"helm\"]\n\npre_run:\n  - helm template my-app ../../ -f values.yaml \u003e manifests/rendered.yaml\n\ndescribe:\n  - name: \"Deployment\"\n    select: 'select(.kind == \"Deployment\")'\n    it:\n      - should: \"have 3+ replicas for HA\"\n        expect: spec.replicas\n        toBeGreaterOrEqual: 3\n\n      - should: \"not use latest tag\"\n        expect: spec.template.spec.containers[0].image\n        toNotEndWith: \":latest\"\n\n      - should: \"have resource limits\"\n        expect: spec.template.spec.containers[0].resources.limits\n        toExist: true\n```\n\n## Usage with Kustomize\n\n```yaml\n# tests/staging/spec.yaml\nname: \"Staging overlay\"\ntags: [\"staging\", \"kustomize\"]\n\npre_run:\n  - kustomize build ../../overlays/staging \u003e manifests/rendered.yaml\n\ndescribe:\n  - name: \"Deployment\"\n    select: 'select(.kind == \"Deployment\")'\n    it:\n      - should: \"be in staging namespace\"\n        expect: metadata.namespace\n        toEqual: \"staging\"\n\n      - should: \"have env label\"\n        expect: metadata.labels.env\n        toEqual: \"staging\"\n```\n\n## Usage with Plain Manifests\n\nNo `pre_run` needed — just put YAML files in a `manifests/` directory:\n\n```\ntests/my-feature/\n  spec.yaml\n  manifests/\n    deployment.yaml\n    service.yaml\n```\n\n## spec.yaml\n\nFull schema reference: [docs/spec-format.md](docs/spec-format.md).\n\nTests are defined in `spec.yaml` files with an RSpec-like vocabulary:\n\n```yaml\nname: \"Production deployment\"\ntags: [\"deployment\", \"production\"]\n\npre_run:\n  - helm template my-app ../../chart -f values.yaml \u003e manifests/rendered.yaml\n\ndescribe:\n  - name: \"Deployment configuration\"\n    select: 'select(.kind == \"Deployment\")'\n    it:\n      - should: \"have 3 replicas\"\n        expect: spec.replicas\n        toEqual: 3\n\n      - should: \"use a pinned image tag\"\n        expect: spec.template.spec.containers[0].image\n        toNotEndWith: \":latest\"\n\n      - should: \"have resource limits\"\n        expect: spec.template.spec.containers[0].resources.limits\n        toExist: true\n\n      - should: \"be in production namespace\"\n        expect: metadata.namespace\n        toBeOneOf: [\"production\", \"prod\"]\n```\n\n## Directory Structure\n\n```\ntests/\n  my-feature/\n    spec.yaml              # Test specification\n    manifests/             # YAML files to test\n      deployment.yaml\n      service.yaml\n    values.yaml            # Optional: Helm values for pre_run\n```\n\n## Field paths\n\nThe `expect:` field accepts these syntaxes — mix freely:\n\n```yaml\nexpect: spec.replicas                              # dotted path\nexpect: spec.template.spec.containers[0].image     # array index\nexpect: spec.template.spec.containers[*].image     # wildcard — assertion runs against every element\nexpect: metadata.labels[\"app.kubernetes.io/name\"]  # bracket notation for keys with dots/special chars\nexpect: .spec.replicas                             # leading dot (JQ-style) also works\n```\n\nWildcards (`[*]`) iterate every element — useful for \"every container must have resource limits\" style checks. See [docs/spec-format.md](docs/spec-format.md#field-path-syntax) for the full reference.\n\n## Assertion Operators\n\n| Operator | Example | Description |\n|----------|---------|-------------|\n| `toEqual` | `toEqual: 3` | Exact match |\n| `toNotEqual` | `toNotEqual: \"default\"` | Must not match |\n| `toBeGreaterThan` | `toBeGreaterThan: 2` | Numeric \u003e |\n| `toBeLessThan` | `toBeLessThan: 10` | Numeric \u003c |\n| `toBeGreaterOrEqual` | `toBeGreaterOrEqual: 1` | Numeric \u003e= |\n| `toBeLessOrEqual` | `toBeLessOrEqual: 5` | Numeric \u003c= |\n| `toContain` | `toContain: \"nginx\"` | Substring match |\n| `toNotContain` | `toNotContain: \"debug\"` | Must not contain |\n| `toStartWith` | `toStartWith: \"nginx:\"` | Prefix |\n| `toEndWith` | `toEndWith: \"-alpine\"` | Suffix |\n| `toNotStartWith` | `toNotStartWith: \"alpine:\"` | Must not start with |\n| `toNotEndWith` | `toNotEndWith: \":latest\"` | Must not end with |\n| `toMatch` | `toMatch: \"^v\\\\d+\"` | Regex |\n| `toExist` | `toExist: true` | Field exists |\n| `toBeNull` | `toBeNull: false` | Null check |\n| `toHaveKey` | `toHaveKey: \"app\"` | Object has key |\n| `toBeOneOf` | `toBeOneOf: [\"a\", \"b\"]` | Set membership |\n| `toNotBeOneOf` | `toNotBeOneOf: [\"x\"]` | Not in set |\n| `toContainItem` | `toContainItem: 80` | Array contains |\n| `toHaveLength` | `toHaveLength: 3` | Exact length |\n| `toHaveMinLength` | `toHaveMinLength: 1` | Min length |\n| `toHaveMaxLength` | `toHaveMaxLength: 5` | Max length |\n\nOperators can be combined — all must pass:\n\n```yaml\n- should: \"be a valid image\"\n  expect: spec.template.spec.containers[0].image\n  toStartWith: \"nginx:\"\n  toNotEndWith: \":latest\"\n  toMatch: \":\\\\d+\\\\.\\\\d+\\\\.\\\\d+$\"\n```\n\n## Output Formats\n\n| Flag | Format | Use case |\n|------|--------|----------|\n| (default) | Console | RSpec-like colored tree |\n| `--json-output` | JSON | Programmatic consumption |\n| `--yaml-output` | YAML | YAML-native workflows |\n| `--markdown-output` | Markdown | Documentation |\n| `--emd-output` | Enriched MD | GitHub PR comments |\n| `--html-output` | HTML | Interactive single-file standards report |\n| `--junit-output` | JUnit XML | CI/CD integration |\n\n## CLI Reference\n\n```\nCOMMANDS:\n  validate, test, run   Run test specs against YAML manifests\n  report                Generate an interactive single-file HTML report\n  serve                 Serve a generated HTML report locally\n  list, ls              List discovered specs and tags\n  init                  Scaffold a new test spec\n  version               Show version information\n\nVALIDATE FLAGS:\n  --test-dir, -d        Test directory (default: \"tests\")\n  --tag, -t             Filter by tag (repeatable)\n  --workers, -w         Parallel workers (default: 1)\n  --fail-fast           Stop on first failure\n  --pre-run-timeout     Max duration for each pre_run command (default: 60s)\n  --quiet, -q           Summary only\n  --json-output         JSON output file\n  --yaml-output         YAML output file\n  --markdown-output     Markdown output file\n  --emd-output          Enriched markdown output file\n  --html-output         Interactive single-file HTML report\n  --junit-output        JUnit XML output file\n  --github-annotations  Emit ::error file=...,line=... for failing assertions\n                        (auto-enabled when GITHUB_ACTIONS=true)\n\nREPORT:\n  yamlspec report --test-dir tests --output yamlspec-report.html\n  yamlspec serve --file yamlspec-report.html --addr 127.0.0.1:8080\n```\n\n## CI/CD — Reusable Workflow\n\nAdd yamlspec to any repo with one workflow file:\n\n```yaml\n# .github/workflows/yamlspec.yml\nname: yamlspec\non: [pull_request, push]\n\njobs:\n  test:\n    uses: AxeForging/yamlspec/.github/workflows/reusable.yml@main\n    with:\n      test-dir: tests\n      install-helm: true        # if your specs use helm template\n      install-kustomize: true   # if your specs use kustomize build\n      comment-on-pr: true       # post results as PR comment\n```\n\nThis installs yamlspec, runs your specs, generates JSON/EMD/JUnit artifacts, and posts a collapsible results comment on PRs. See [docs/reusable-workflow.md](docs/reusable-workflow.md) for all options.\n\n## Examples\n\nFive runnable examples live under [`examples/`](examples) — see the [examples README](examples/README.md) for what each demonstrates and the exact command to run it.\n\n## Development\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide. Quick reference:\n\n```bash\nmake build-local    # Build binary\nmake test           # Run all tests\nmake test-unit      # Unit tests only\nmake test-e2e       # Integration tests\nmake lint           # Linter\nmake install        # Install to /usr/local/bin\n```\n\nRelease history is in [CHANGELOG.md](CHANGELOG.md).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxeforging%2Fyamlspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxeforging%2Fyamlspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxeforging%2Fyamlspec/lists"}