Release and Recovery Procedure¶
Only a maintainer with repository and PyPI project control may publish a release.
One-Time Trusted Publishing Setup¶
- Create or claim the
pyffmpegcoreproject on PyPI with the intended maintainer account. - In PyPI, add a GitHub Trusted Publisher for owner
OthmaneBlial, repositorypyffmpegcore, workflowrelease.yml, environmentpypi. - In GitHub, protect the
pypienvironment and restrict it to protected release tags. - Keep the workflow permission limited to
id-token: write; do not add a long-lived PyPI API token.
Release Gate¶
- Confirm every earlier P0 roadmap gate and all required checks are green.
- Update
CHANGELOG.md, compatibility notes, and the runtime version. - Run the Release workflow manually with
workflow_dispatch. That event only builds and tests the release bundle. Attestation, PyPI publication, public-install, and GitHub Release jobs run only after a signed version-tag push. - Create an SSH-signed annotated tag matching the runtime version exactly.
The maintainer key must match
.github/allowed_signers, and the GitHub tag ruleset prevents deletion and non-fast-forward updates ofv*refs:
release_version="$(python -c 'from pyffmpegcore import __version__; print(__version__)')"
git -c gpg.format=ssh \
-c user.signingkey="$HOME/.ssh/id_ed25519" \
tag -s "v${release_version}" -m "pyffmpegcore ${release_version}"
git -c gpg.format=ssh \
-c gpg.ssh.allowedSignersFile=.github/allowed_signers \
tag --verify "v${release_version}"
- Push the tag. The workflow builds once, tests the exact wheel on the supported OS/Python anchors, attests it, and publishes it through OIDC.
- The workflow waits for the exact wheel and source distribution to appear in the public PyPI JSON endpoint. It then performs a clean
pipx install,--version,doctor, andsmoke-teston Linux, macOS, and Windows before creating the matching GitHub Release with checksums. The GitHub Release is marked as a prerelease while the package classifier says Beta. A failed public-install gate must be fixed forward; it must not be bypassed by creating the release manually.
scripts.build_cli_artifacts sets SOURCE_DATE_EPOCH from the source
commit (or from the packaged PKG-INFO timestamp when rebuilding an sdist)
unless a valid explicit value is supplied. It normalizes sdist tar/gzip
timestamps and ownership metadata. Rebuilding the same source with the same
pinned toolchain therefore reproduces the wheel and sdist bytes; the release
workflow still tests and publishes the single artifact bundle it built
first.
- Record the public terminal proof only after those endpoints are healthy:
export PYFFMPEGCORE_DEMO_WHEEL_HASH="<SHA-256 of the exact versioned PyPI wheel>"
scripts/record_terminal_demo.sh "docs/assets/terminal-demo-v${release_version}.cast" "${release_version}"
Get the hash from that version's PyPI JSON digests.sha256 for the wheel (not the source archive). The recorder checks the installed wheel against it, captures a real PTY session, enforces a 60–90 second duration and required proof steps, rejects private home paths, and writes an accessible text transcript beside the cast. Never hand-edit the recording to invent output.
Never rebuild or replace files for an existing version. A failed gate means fix forward with a new commit and, if any immutable artifact was already published, a new version.
Rollback and Yanking¶
Python packages cannot be safely “rolled back” by replacing files. For a broken but non-malicious release:
- yank the affected PyPI version with a concise reason;
- mark the GitHub Release as affected without deleting evidence;
- document the impact and workaround;
- publish a corrected patch version through the normal pipeline.
Delete an artifact only for legal, credential, malware, or personal-data exposure where preservation causes more harm. Record the reason privately and publish a public incident note when safe.
Deprecation¶
Announce a CLI/API deprecation in the changelog and user documentation before
removal. Before 1.0, follow the API stability policy: keep
the old public API working for at least two minor releases and 90 days, emit a
runtime DeprecationWarning, name the first removal version, and test both
paths. Provide a migration example. After 1.0, intentional incompatible
public-contract changes require a major version. Security or correctness
exceptions need an explicit release note and migration path.
Security Fixes¶
Coordinate confirmed vulnerabilities in a private GitHub Security Advisory. Prepare tests and the fix on the advisory fork when needed, request a CVE when appropriate, and publish the patched release before or with disclosure. Do not expose reporter data or exploit details prematurely. Follow the response expectations in the security policy.