Skip to main content

Catch contract drift across documentation, configuration, specifications, and tests.

Project description

RepoInvariant

Alpha: catch contract drift across repository artifacts before merge.

RepoInvariant is a deterministic CLI and GitHub Action that checks whether the contracts spread across your repository still agree. It focuses on two expensive, repeatable failure modes:

  • environment variables drifting between .env.example, Docker Compose, Kubernetes, GitHub Actions, and Spring configuration;
  • requirement IDs disappearing between Markdown, OpenAPI x-feature-id, and tests.

It reports exact evidence instead of guessing intent. No API key, LLM, or source upload is required.

Status

RepoInvariant v0.1.0 is the first public alpha. The configuration and finding codes may change before v1.0.0. Pin an exact commit SHA when using the GitHub Action.

Quick start

Install the CLI from PyPI:

uv tool install repoinvariant

cd /path/to/your/repository
repoinvariant init
repoinvariant check .

During development, use:

uv sync --frozen --extra dev
uv run repoinvariant check examples/ticket-service
uv run pytest

A finding looks like this:

compose.yml:12:7: error ENV001: DATABASE_URL is used but missing from the environment contract
docs/requirements.md:18:1: error TRACE001: REQ-HOLD-CREATE is missing from the specification
FAIL: 6 files, 2 errors, 0 warnings

Configuration

Run repoinvariant init to create .repoinvariant.yml:

version: 1

env:
  contracts: [.env.example]
  compose: [compose*.yml, docker-compose*.yml]
  kubernetes: [k8s/**/*.yml]
  workflows: [.github/workflows/*.yml]
  spring:
    - src/main/resources/application*.yml
    - src/main/resources/application*.properties
  ignore: [CI, HOME, PATH, GITHUB_*, RUNNER_*]

features:
  requirements: [docs/**/*.md]
  specifications: [openapi*.yml, docs/openapi*.yml]
  tests: [tests/**/*, src/test/**/*]
  id_pattern: '\bREQ-[A-Z0-9][A-Z0-9-]*\b'
  openapi_extension: x-feature-id
  requirements_mode: definitions
  ignore: []

rules:
  ENV001: error
  ENV002: warning
  ENV003: warning
  TRACE001: error
  TRACE002: error
  TRACE003: error
  TRACE004: warning

requirements_mode: definitions counts IDs only when they look like canonical Markdown definitions (headings, definition lists, and the first column of tables). Set it to mentions for legacy repositories where any prose reference is authoritative.

The built-in REQ-* pattern is printed verbatim because it is a constrained public identifier format. Matches from a custom id_pattern are reported as deterministic custom-id-N labels; source locations remain exact, but arbitrary matched repository text never reaches logs or report artifacts.

Each finding code can be set to error, warning, or off. This makes staged adoption explicit: start a noisy rule as a warning, fix the baseline, then promote it to an error. Quote "off" when editing YAML to avoid YAML 1.1 boolean parsing surprises.

Then run one of the stable report formats:

repoinvariant check . --format text
repoinvariant check . --format json --output repoinvariant-report.json
repoinvariant check . --format markdown --output repoinvariant-report.md
repoinvariant check . --format sarif --output repoinvariant-report.sarif

Exit code 0 means no blocking drift, 1 means a configured contract failed, and 2 means the command or configuration was invalid. Add --fail-on warning for a stricter merge gate.

GitHub Action

The repository must be checked out before RepoInvariant runs. For supply-chain safety, pin an exact commit SHA:

permissions:
  contents: read

steps:
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  - uses: xixvivji/RepoInvariant@<commit-sha>
    with:
      path: .
      format: sarif
      output: repoinvariant-report.sarif
      no-features: "true" # optional during staged adoption

The action installs only the source bundled with the pinned action revision. It does not transmit repository contents.

The action also accepts no-env and no-features boolean inputs. Prefer rule-level severity configuration when only one check needs a temporary downgrade.

Finding codes

Code Meaning Default severity
ENV001 A consumer uses an environment variable absent from the contract error
ENV002 A contract variable has no discovered consumer warning
ENV003 Explicit defaults disagree across artifacts warning
TRACE001 A requirement ID is absent from the specification error
TRACE002 A specification ID has no requirement error
TRACE003 A specification ID has no test reference error
TRACE004 A requirement appears to be defined more than once warning

Design boundaries

RepoInvariant deliberately does not:

  • decide whether two differently worded requirements mean the same thing;
  • modify repository files automatically;
  • compare live infrastructure or databases;
  • print secret values found in configuration;
  • claim full OpenAPI, Compose, Kubernetes, or Spring validation.

Use their native validators alongside RepoInvariant. RepoInvariant owns the gap between artifacts.

Configured files and report destinations must stay inside the repository. RepoInvariant rejects configuration/output symlinks, limits configuration files to 256 KiB and scanned files to 2 MiB, and fails closed on malformed configured YAML. Custom requirement patterns run with a timeout and one shared matching-time budget. File reads and atomic report writes use no-follow directory descriptors so a concurrent symlink swap cannot redirect them outside the repository.

Roadmap

  • Environment contract checks
  • Requirement → OpenAPI → test traceability
  • Text, JSON, Markdown, and SARIF reports
  • Composite GitHub Action
  • Version-baseline contracts across Gradle, Docker, CI, and documentation
  • Reusable parser plugin API
  • PyPI trusted publishing and provenance-attested release automation
  • Real-world compatibility fixtures from external projects

See CONTRIBUTING.md to help shape future releases.

License

Apache License 2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

repoinvariant-0.1.0.tar.gz (100.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

repoinvariant-0.1.0-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

File details

Details for the file repoinvariant-0.1.0.tar.gz.

File metadata

  • Download URL: repoinvariant-0.1.0.tar.gz
  • Upload date:
  • Size: 100.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for repoinvariant-0.1.0.tar.gz
Algorithm Hash digest
SHA256 57a13c25b97b7face650fdb5ecbcc9c3ad5b85ec8f1a7fa6a39e4f02243d8cda
MD5 6fc3f6d37fe248f10c83735e3cbaa35a
BLAKE2b-256 016863c76ba9579338ea800e22a4c228e17bc0a8023b88ea819eebb3c5fad52e

See more details on using hashes here.

Provenance

The following attestation bundles were made for repoinvariant-0.1.0.tar.gz:

Publisher: release.yml on xixvivji/RepoInvariant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file repoinvariant-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: repoinvariant-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for repoinvariant-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 90b27f6554f5f0afde3bcc2c9a93ef0ff85a183a7bd76c0b1659beff68e3c214
MD5 f566dd6f4753ef24175203fadceb7d27
BLAKE2b-256 392a6b769613ab1a6978c01d58b9c3b261f7d3e45f4b669120b739dd6da0ced5

See more details on using hashes here.

Provenance

The following attestation bundles were made for repoinvariant-0.1.0-py3-none-any.whl:

Publisher: release.yml on xixvivji/RepoInvariant

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page