Turn release evidence into a bounded Codex maintenance task before an npm, Python, or Rust package is published.
PackRehearsal is a local-first, zero-runtime-dependency release assurance CLI. It compares package manifests with the archive bytes that will actually ship, then emits deterministic findings, SARIF, baselines, receipts, and evidence-bounded work orders for Codex. The scanner—not a model—defines the finding scope and verification command. The default path does not execute project code, call an OpenAI API, contact a registry, or extract an archive.
PackRehearsal 1.x is stable. CLI commands and exit codes; report, Codex task, baseline, and receipt schemas v1; and published rule IDs follow the compatibility policy below. Intentional breaking changes require a new major version.
The local Release Gate WebUI imports a real report-v1 JSON
file, exposes the report's artifacts and findings, and exports a deterministic,
schema-compatible codex-task-v1 brief for the maintainer's selected,
non-baselined findings. Files stay in browser memory: the UI does not upload the
report, read project files, execute project code, or merge and release changes.
The CLI remains the authoritative scanner; the browser validates the report
contract but does not authenticate its author or rerun the scan.
Python 3.11 or newer is required. Install the published package from PyPI:
python -m pip install "packrehearsal==1.2.0"
packrehearsal scan .
packrehearsal codex-brief . --output codex-maintenance-brief.mdThe repository dogfoods its own static scan. The checked-in example report currently renders as:
PackRehearsal 1.2.0
root: .
packages: 2 artifacts: 0 findings: 0
No findings.
To compare source metadata with a built artifact:
packrehearsal scan . \
--artifact dist/example-1.2.3-py3-none-any.whlTo gate the complete Python release set, pass the wheel and sdist together:
packrehearsal scan . \
--artifact dist/example-1.2.3-py3-none-any.whl \
--artifact dist/example-1.2.3.tar.gzThe python.artifact-set-mismatch gate compares package identity, version,
Requires-Python, dependencies, license metadata, and extras across both
artifacts. It blocks the release when bytes built for the same tag describe
different install contracts.
A green source tree can still produce a broken or unexpectedly packaged artifact. PackRehearsal checks evidence at the release boundary:
| Problem | Evidence inspected |
|---|---|
| Declared entrypoint never reaches the archive | Manifest targets and archive members |
| Wheel or sdist identifies the wrong release | Manifest name/version and artifact metadata |
| Wheel and sdist disagree with each other | Parsed compatibility, dependency, license, and extra metadata |
| README, license, or configured payload is omitted | Repository paths and packaged paths |
| Credential-like or unexpectedly large file would ship | Repository and archive member inventory |
| Monorepo packages publish incompatible sibling versions | Normalized internal dependency constraints |
| Archive contains traversal, links, special files, or excessive expansion | Bounded ZIP/TAR structural inspection |
Every finding includes a stable rule ID, severity, package/location, supporting evidence, remediation, and a fingerprint suitable for reviewable baselines. See the rule catalog for the executable rule families.
codex-brief turns only new, in-scope findings into a deterministic Markdown
or JSON task:
packrehearsal codex-brief . \
--artifact dist/example-1.2.3-py3-none-any.whl \
--artifact dist/example-1.2.3.tar.gz \
--minimum-severity low \
--format json \
--output codex-maintenance-task.jsonThe task carries a content-derived task ID, originating scan ID, artifact hashes, exact finding fingerprints, remediation, guardrails, and a verification command. Repository-derived text is marked as untrusted data. Codex is told not to execute project code, weaken policy, make unrelated edits, merge, or release. If there are no selected findings, the task explicitly says do not invent work.
No API key is required: PackRehearsal produces the evidence bundle, while the
maintainer decides whether and where to give it to Codex. See the complete
Codex maintainer workflow and repository-native
AGENTS.md.
Reviewed Codex outcomes can be recorded without inventing success metrics. The maintenance evidence ledger distinguishes measured tasks from targets, preserves rejected suggestions and boundary violations, and generates a deterministic public Markdown summary.
packrehearsal scan is deliberately static:
- no registry or network access;
- no writes to the inspected repository;
- no package lifecycle scripts or imports of project code;
- no extraction of untrusted archives;
- root-anchored, no-follow reads for manifests and rule inputs;
- hard ceilings for archive bytes, entries, expansion, and compression ratio;
- deterministic JSON suitable for review and baselining.
Receipts bind report and artifact hashes and can be verified offline. They are unsigned self-consistency evidence—not proof of authorship or package safety.
Every v1 release includes SHA-256 checksums and GitHub build-provenance attestations generated from the tagged source. After downloading an asset:
gh attestation verify packrehearsal-1.1.0-py3-none-any.whl \
--repo liyuqin606-del/packrehearsalpackrehearsal rehearse is a separate trusted-code boundary. Package builders
can execute arbitrary project code, so rehearsal requires an explicit
--trusted-rehearsal acknowledgement. Source-copy size, entry count, deadline,
and subprocess output have hard caps, but rehearsal is not an OS sandbox.
Never enable it for an unreviewed fork. Read the threat
model before using it in CI.
| Ecosystem | Static discovery | Artifact inspection | Trusted candidate build |
|---|---|---|---|
| npm / workspaces | Yes | .tgz |
npm pack --ignore-scripts |
| Python | Yes | wheel and sdist | python -m build |
| Rust / workspaces | Yes | .crate |
cargo package |
New adapters will be considered after the current three are stabilized with fixtures and maintainer feedback.
packrehearsal inspect dist/example-1.2.3-py3-none-any.whl
packrehearsal inspect package/example-1.2.3.tgz --format jsoninspect produces a bounded structural snapshot. Use scan ROOT --artifact PATH when you also want manifest-aware rules.
packrehearsal scan . --format json --output report.json
packrehearsal scan . --format markdown --output report.md
packrehearsal scan . --format sarif --output report.sarifpackrehearsal codex-brief . --format markdown --output codex-brief.md
packrehearsal codex-brief . --format json --output codex-task.jsoncodex-brief always exits zero after a successful scan because its job is to
write a task, not apply the normal finding gate. Findings remain unchanged and
continue to control packrehearsal scan exit status.
packrehearsal scan . --write-baseline .packrehearsal-baseline.json
packrehearsal scan . \
--baseline .packrehearsal-baseline.json \
--fail-on highA baseline suppresses known fingerprints from the failure gate; review it like code. The bundled GitHub Action refuses repository baselines on pull-request and merge-group events so a proposed revision cannot exempt its own findings.
packrehearsal scan . \
--artifact dist/example.whl \
--receipt release-receipt.json
packrehearsal verify-receipt release-receipt.json --artifact-root .Install the optional Python build frontend, then acknowledge the execution boundary explicitly:
python -m pip install "packrehearsal[rehearsal]==1.2.0"
packrehearsal rehearse . --trusted-rehearsalGenerate conservative defaults:
packrehearsal initUnknown keys and rule IDs fail closed. Repository configuration may tighten
archive limits but cannot raise built-in ceilings. Use --no-repo-config when
CI must ignore configuration supplied by the checked-out revision.
{
"allow_network": false,
"disabled_rules": [],
"fail_on": "high",
"include_hidden": false,
"max_depth": 12,
"severity_overrides": {},
"trusted_timeout_seconds": 180
}The composite action runs only the static path, imports itself in Python
isolated mode, ignores repository configuration, and has no install-time
dependency step. Its optional codex-output input emits a JSON maintenance task
before the normal finding gate. Pin the Action to a reviewed full commit SHA:
name: PackRehearsal
on:
pull_request:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Scan release metadata
uses: liyuqin606-del/packrehearsal@a94d39c32da5ac698d28c5a84e74e65e699f81db
with:
root: .
format: sarif
output: packrehearsal.sarif
fail-on: high
codex-output: codex-maintenance-task.json
- name: Retain the Codex maintenance task
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: codex-maintenance-task
path: codex-maintenance-task.json
if-no-files-found: warn
retention-days: 7Do not run trusted rehearsal on pull_request_target or on unreviewed fork
code. If a PR workflow needs a baseline, load it from an independently trusted
base-revision checkout rather than the proposed revision.
| Code | Meaning |
|---|---|
0 |
Command completed; for scan, no new finding met the failure threshold |
1 |
A new finding met the configured severity threshold |
2 |
Invalid arguments, configuration, or unsafe input |
3 |
Trusted rehearsal failed, exceeded a resource bound, or timed out |
git clone https://github.com/liyuqin606-del/packrehearsal.git
cd packrehearsal
uv sync --extra dev --extra rehearsal
uv run ruff check .
uv run mypy src/packrehearsal
uv run pytest --cov=packrehearsal --cov-branch
uv run packrehearsal scan .
uv run packrehearsal codex-brief . --format json --output /tmp/codex-task.jsonThe test suite is offline and covers archive bounds, symlink/TOCTOU defenses, workspace discovery, trusted-build resource limits, rule behavior, reporters, Codex task injection boundaries, baselines, and receipts.
Version 1.1 adds the stable Codex task schema and repository-native maintainer workflow to the 1.x discovery, archive inspection, rules, reporters, baselines, receipts, and trusted-rehearsal boundary. Patch releases may add rules or harden parsers without changing documented command semantics. New required arguments, removal of public commands or rule IDs, incompatible schema changes, and weaker safety defaults are reserved for a new major version.
Future work is driven by reproducible public issues: more real-world fixtures, additional monorepo dependency evidence, and opt-in clean-environment smoke tests for trusted branches. New ecosystems require maintainer feedback before implementation.
The precise 1.x guarantees and intentionally unstable surfaces are documented in the compatibility policy.
- Contributing guide
- Security policy
- Governance
- Compatibility policy
- Support
- Threat model
- Architecture
- Rule catalog
- Codex workflow
- Maintenance roadmap
- Maintenance evidence ledger
- Public pilot and case-study guide
- Community launch plan
Security-sensitive reports should use GitHub private vulnerability reporting. PackRehearsal is licensed under Apache-2.0.
PackRehearsal is community-maintained and is not affiliated with or endorsed by OpenAI. Codex and OpenAI are trademarks of their respective owner.
