Static, local CLI for checking environment-variable delivery contracts.
Project description
runtime-contract
runtime-contract is an offline static-analysis CLI that checks whether environment variables used
by a specific application component are actually supplied to that component in the correct build or
runtime phase.
It analyzes application code and deployment declarations together. It never executes the analyzed code, reads secret values, or contacts a runtime environment. Results are deterministic and can be rendered as terminal text, canonical JSON, or SARIF 2.1.0.
GitHub Action
Add one uses: step to run the released CLI. The Action prepares its own pinned Python environment
and installs the exact runtime-contract version from public PyPI; consumers do not install Python,
pip, pipx, uv, or this package themselves.
- name: Check runtime configuration contract
uses: piotr-adamski/runtime-contract@v0
with:
command: check
path: .
format: text
fail-on: error
The repository must already be checked out. A complete minimal job, with every third-party Action pinned to an immutable commit, is:
jobs:
runtime-contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- uses: piotr-adamski/runtime-contract@v0
with:
command: check
path: .
fail-on: error
For higher-assurance organizations, replace @v0 with the full 40-character commit SHA advertised
by the corresponding release. The immutable v0.x.y tag is the reproducible semver reference;
v0 moves only after full CI and release verification. There is no latest tag.
Code Scanning with SARIF
The CLI writes SARIF atomically, so installer and Action logs never enter the report:
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: false
- name: Run runtime-contract
id: runtime-contract
uses: piotr-adamski/runtime-contract@v0
with:
command: check
path: .
format: sarif
output: runtime-contract.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9
with:
sarif_file: runtime-contract.sarif
Action inputs
| Input | Default | Contract |
|---|---|---|
command |
check |
scan, check, explain, or diff. |
path |
. |
Project directory for scan/check; optional project/report source for explain. Not used by diff. |
format |
text |
text, json, or sarif for scan/check; text or json for explain/diff. |
fail-on |
error |
error, warning, info, or never for scan/check. Must stay at the default for other commands. |
config |
empty | Configuration path relative to path for scan/check. |
version |
0.1.0 |
One exact public PyPI release. Moving values such as latest and URLs are rejected. |
output |
empty | Report path passed as one --output argument. For scan/check, it is relative to path. |
rule |
empty | Rule or finding identifier required by explain. |
left |
empty | Left project directory or saved JSON report required by diff. |
right |
empty | Right project directory or saved JSON report required by diff. |
environment |
empty | Optional environment profile for scan, check, or diff. |
Action outputs
| Output | Contract |
|---|---|
exit-code |
Exact CLI exit code; 2 when Action input validation or installation fails. |
result-file |
Absolute requested report path, or an empty string when output is not set. |
runtime-contract-version |
Version verified through the installed CLI, or empty when setup fails. |
Product exit codes are preserved. A blocking check therefore fails the Action with exit 1, and
invalid usage, partial analysis, or technical failure exits 2. Use the step's
continue-on-error: true only when a later workflow step intentionally needs to inspect a negative
test result.
The Action is required in CI on Ubuntu, macOS, and Windows GitHub-hosted runners. It uses
astral-sh/setup-uv pinned to a full SHA, uv==0.11.28, managed Python 3.11.15, an isolated
virtual environment, and runtime-contract==<version> from https://pypi.org/simple. The installed
CLI version and dependency consistency are checked before analysis. Basic use needs no secret,
token, telemetry, private index, or executable code from the analyzed repository.
The problem
An environment variable can exist in documentation, a neighboring service, or a build stage and
still be unavailable to the process that needs it. File-by-file checks miss that relationship.
runtime-contract maps consumers and providers to components, targets, and phases so it can detect
missing delivery, build/runtime mismatches, unsafe literals, and other contract errors before
deployment.
It does not compare a live cluster or production environment with the repository. It checks the static contract represented by the selected repository files.
Example: required variable not delivered
Application code requires DATABASE_URL:
# api/settings.py
import os
DATABASE_URL = os.environ["DATABASE_URL"]
But Compose starts the api component without passing that variable:
# compose.yaml
services:
api:
build: ./api
environment:
LOG_LEVEL: info
Running runtime-contract check . reports the component-specific error and exits 1:
RTC001 Required variable not provided
at api/settings.py:3:16 | target=api key=DATABASE_URL phase=runtime
Result: complete
Supported in v0.1.2
- Consumers: Python and JavaScript/TypeScript.
- Providers and declarations:
.env.example, Dockerfile, Docker Compose, and standard Kubernetes workload manifests. - Build-time and runtime phase matching, component/target mapping, and RTC001–RTC012 evaluation.
- Offline, read-only analysis with deterministic terminal, JSON, and SARIF output.
- Project configuration, classifications, severity overrides, and targeted suppressions.
Installation
Python 3.11 or newer is required. Install the released package in an isolated environment:
pipx install runtime-contract==0.1.2
runtime-contract --version
Or install it in an active virtual environment:
python -m pip install runtime-contract==0.1.2
runtime-contract --version
Pin the version in automation to keep CLI and output-schema behavior reproducible.
Quickstart
From the root of the repository you want to inspect:
runtime-contract scan .
runtime-contract check .
scan inventories the contract and always remains non-blocking for findings. check evaluates the
same result as a policy gate. A configuration file is optional; add runtime-contract.yaml when the
repository needs multiple component roots, environments, explicit classifications, severity
overrides, or suppressions.
For a self-contained first run from this source repository:
runtime-contract scan examples/scan-flow
runtime-contract check examples/scan-flow
The second command intentionally exits 1 because the example contains active errors.
Main commands
runtime-contract scan PATH
runtime-contract check PATH
runtime-contract explain RTC001
runtime-contract diff BEFORE AFTER
runtime-contract config validate PATH
Use JSON or SARIF for integrations:
runtime-contract scan . --format json --output runtime-contract.json
runtime-contract check . --format sarif --output runtime-contract.sarif
See the complete CLI reference for every command and option.
Exit codes
| Exit | Meaning |
|---|---|
0 |
Successful, reliable command. For check, no active finding reaches the failure threshold. |
1 |
Complete, reliable check with an active finding at or above the failure threshold. |
2 |
Invalid usage/configuration, technical failure, or partial/failed analysis. |
130 |
Interrupted by the user. |
scan never returns 1. Structured partial or failed analysis is still emitted when safe, but Exit
2 prevents CI from treating it as reliable. Reports go to stdout or the selected --output file;
usage and technical errors go to stderr.
For line-level GitHub Code Scanning alerts, adapt the complete SARIF workflow and its configuration. It needs no repository secret.
Important limitations
- Static analysis cannot prove what a deployed process actually received.
- Dynamic variable names, aliases, reflection, generated manifests, and framework-specific APIs may be partial or unsupported instead of guessed.
- Compose
env_filecontents, Helm/Kustomize output, cluster state, image contents, and remote references are not resolved. - Real
.env*files are excluded; only the exact.env.examplefilename is analyzed. - Parser and resource budgets fail closed on oversized or structurally unsafe input.
- The Action needs outbound access to GitHub Actions distribution and public PyPI during each
invocation. Organizations that allowlist Actions must also allow its SHA-pinned
astral-sh/setup-uvdependency.
See known risks and the full static-analysis limits.
Reference documentation
- CLI commands, options, streams, and exits
- RTC001–RTC012 rule reference
runtime-contract.yaml, classifications, and suppressions- Terminal, JSON, SARIF, schemas, and compatibility
- Security, privacy, parser controls, and resource budgets
- Known risks and intentional limitations
- GitHub Action release and Marketplace checklist
- Analyzer extension API and built-in analyzer behavior
- Domain model and normalization API
- Offline broken/fixed demo
Contributing, security, and license
Contributions use the DCO. Report vulnerabilities through the process in SECURITY.md. The project is licensed under Apache-2.0; see the Code of Conduct and changelog for project governance and release history.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file runtime_contract-0.1.2.tar.gz.
File metadata
- Download URL: runtime_contract-0.1.2.tar.gz
- Upload date:
- Size: 113.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7822a305a8efc6d294aa2f021c3b82d61ba26424bf8d44983e924279e32ac884
|
|
| MD5 |
1eeeed55be6782439fa3e3323f0526d5
|
|
| BLAKE2b-256 |
441f9dfae7b4bc515ed1729536ba4acd4a1c87554b5ee8c3910f15e9e2050994
|
Provenance
The following attestation bundles were made for runtime_contract-0.1.2.tar.gz:
Publisher:
publish.yml on piotr-adamski/runtime-contract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runtime_contract-0.1.2.tar.gz -
Subject digest:
7822a305a8efc6d294aa2f021c3b82d61ba26424bf8d44983e924279e32ac884 - Sigstore transparency entry: 2172574339
- Sigstore integration time:
-
Permalink:
piotr-adamski/runtime-contract@c84caf68853e97e3b662f4df76b548279f631278 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/piotr-adamski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c84caf68853e97e3b662f4df76b548279f631278 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file runtime_contract-0.1.2-py3-none-any.whl.
File metadata
- Download URL: runtime_contract-0.1.2-py3-none-any.whl
- Upload date:
- Size: 150.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b98f8db9d77a65d871d32898c6af05268bf16826ba05949c7cf18111e1a3ba4
|
|
| MD5 |
f4a2393819c916862a173f8f955a49b2
|
|
| BLAKE2b-256 |
4940cf5dadd200b26fb36acfca22db28a871668bde3e929817ceba78d615d5cb
|
Provenance
The following attestation bundles were made for runtime_contract-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on piotr-adamski/runtime-contract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runtime_contract-0.1.2-py3-none-any.whl -
Subject digest:
0b98f8db9d77a65d871d32898c6af05268bf16826ba05949c7cf18111e1a3ba4 - Sigstore transparency entry: 2172574354
- Sigstore integration time:
-
Permalink:
piotr-adamski/runtime-contract@c84caf68853e97e3b662f4df76b548279f631278 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/piotr-adamski
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c84caf68853e97e3b662f4df76b548279f631278 -
Trigger Event:
workflow_dispatch
-
Statement type: