Skip to main content

PackRehearsal

CI CodeQL GitHub release Python 3.11+ License: Apache-2.0

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.

Quick start

Python 3.11 or newer is required. Install the immutable wheel attached to the GitHub release:

python -m pip install \
  "https://github.com/liyuqin606-del/packrehearsal/releases/download/v1.1.0/packrehearsal-1.1.0-py3-none-any.whl"

packrehearsal scan .
packrehearsal codex-brief . --output codex-maintenance-brief.md

The repository dogfoods its own static scan. The checked-in example report currently renders as:

PackRehearsal 1.1.0
root: .
packages: 1  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.whl

What it catches

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
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 maintenance loop

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 \
  --minimum-severity low \
  --format json \
  --output codex-maintenance-task.json

The 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.

Safe by default

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/packrehearsal

packrehearsal 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.

Supported ecosystems

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.

Core workflows

Inspect an existing artifact

packrehearsal inspect dist/example-1.2.3-py3-none-any.whl
packrehearsal inspect package/example-1.2.3.tgz --format json

inspect produces a bounded structural snapshot. Use scan ROOT --artifact PATH when you also want manifest-aware rules.

Produce machine-readable reports

packrehearsal scan . --format json --output report.json
packrehearsal scan . --format markdown --output report.md
packrehearsal scan . --format sarif --output report.sarif

Generate a Codex work order

packrehearsal codex-brief . --format markdown --output codex-brief.md
packrehearsal codex-brief . --format json --output codex-task.json

codex-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.

Baseline existing findings

packrehearsal scan . --write-baseline .packrehearsal-baseline.json
packrehearsal scan . \
  --baseline .packrehearsal-baseline.json \
  --fail-on high

A 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.

Create an evidence receipt

packrehearsal scan . \
  --artifact dist/example.whl \
  --receipt release-receipt.json

packrehearsal verify-receipt release-receipt.json --artifact-root .

Build artifacts from a trusted revision

Install the optional Python build frontend, then acknowledge the execution boundary explicitly:

python -m pip install \
  "packrehearsal[rehearsal] @ https://github.com/liyuqin606-del/packrehearsal/releases/download/v1.1.0/packrehearsal-1.1.0-py3-none-any.whl"

packrehearsal rehearse . --trusted-rehearsal

Configuration

Generate conservative defaults:

packrehearsal init

Unknown 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
}

GitHub Actions

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: 7

Do 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.

Exit codes

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

Development

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.json

The 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.

Stability and roadmap

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 and security

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.

Release files for packrehearsal 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for packrehearsal 1.1.0
File Size Uploaded
packrehearsal-1.1.0.tar.gz 166.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for packrehearsal 1.1.0
File Interpreter ABI Platform
packrehearsal-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 261.8 kB

Release files / packrehearsal-1.1.0.tar.gz

Download URL packrehearsal-1.1.0.tar.gz
Size 166.2 kB
Tags Source
SHA-256 checksum
How to use checksums
410a2501174b0a137004403e9447b4261d902c9d110d4c3cbedcc83a4ecb25a2
BLAKE2b-256 checksum
How to use checksums
2e7eba5b770c7852a48a0ceef6524beabdf0801bb7a55a4ed542624a12330d8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Release files / packrehearsal-1.1.0-py3-none-any.whl

Download URL packrehearsal-1.1.0-py3-none-any.whl
Size 95.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
312dc6221694b243e48903478a47fc4b4a265803fc1a76a1a94c7748ee186c1b
BLAKE2b-256 checksum
How to use checksums
624ccbe9b05b3903598eedca65f919d9e219bdc5ca6fa3b665178395358cf479
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.0

2 release files

This release

1.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page