Release Safety & Idempotency Check
Relevant source files
The following files were used as context for generating this wiki page:
The Release Safety & Idempotency Check system is a critical component of the numan-plugins CI/CD pipeline, designed to ensure that binary releases are immutable and that the publication process fails closed rather than producing corrupted or inconsistent states. The project's architecture mandates that release assets are immutable; once a package version is published, it cannot be replaced or modified without a new version or explicit build revision.
This system implements a "Draft-then-finalize" pattern, where releases are first claimed as run-owned drafts, verified for completeness across all target platforms, and only then made public. It enforces strict provenance by verifying that human-facing tags resolve to immutable upstream source commits before any build activity begins.
Sources: README.md:28-35, REVIEW.md:23-28
Pre-Publication Verification
Before a build workflow can proceed to generating artifacts, it must satisfy several safety invariants regarding the state of the repository and the requested release version.
Absence Checks
The system enforces idempotency by failing if a Git tag or release already exists for the target version. This prevents accidental overwriting of existing binaries. The logic uses the GitHub CLI (gh) to query both the Git references and the release API.
The flowchart above illustrates the fail-closed logic executed by ensure_release_absent.py to guarantee release immutability.
Sources: scripts/ensure_release_absent.py:38-55, REVIEW.md:23-24
Upstream Tag Resolution
Every plugin in manifest.json pins a source_commit (a 40-character SHA) and a tag. The safety check requires that the upstream tag resolves exactly to the pinned commit. This ensures provenance and prevents "tag sliding" where a human-facing tag might point to different code over time.
Sources: scripts/validate_manifest.py:116-140, REVIEW.md:21-22
Release Transaction Lifecycle
The publication process is managed as a transaction consisting of four distinct phases: claim, upload, finalize, and cleanup. This ensures that even in the event of partial CI failures, the repository does not end up with a "half-published" release.
Transaction Phases
| Phase | Description | Key Requirement |
|---|---|---|
| Claim | Creates a Git tag and a draft release for a specific commit. | Must return a numeric release_id. |
| Upload | Pushes build artifacts to the specific draft release. | Uses release_id to avoid tag discovery race conditions. |
| Finalize | Verifies asset count, sizes, and digests before making the release public. | Tag must still point to the original workflow commit. |
| Cleanup | Deletes the draft release and tag if any stage fails. | Only deletes if the release is still in draft status. |
Sources: scripts/release_transaction.py:1-255, scripts/test_workflow_safety.py:91-96
The Finalize Safeguard
The finalize command is the ultimate gatekeeper. It compares the local assets generated during the matrix build against the assets actually present on GitHub's servers.
The sequence diagram shows the verification loop that occurs before a draft is promoted to a public release.
Sources: scripts/release_transaction.py:165-195, scripts/test_release_transaction.py:73-95
Workflow Safety Constraints
The CI workflows (build.yml and repo-safety.yml) implement several hardening measures to protect the release process:
- Manual Dispatch Only: Publication can only be triggered via
workflow_dispatchwith a non-emptyonly=parameter. Pushes and Pull Requests are restricted to validation only and cannot publish. - Pinned Actions: Every GitHub Action reference must be pinned to a 40-character commit SHA, not a mutable tag.
- Shell Injection Prevention: Workflow expressions (e.g.,
${{ ... }}) are kept inenvorwithblocks and never interpolated directly into executable shell text. - Least Privilege: Only the specific
releasejob is grantedcontents: writepermissions; all other jobs and workflows arecontents: read.
Sources: scripts/test_workflow_safety.py:53-89, REVIEW.md:12-16
Conclusion
The Release Safety & Idempotency Check system provides a robust framework for managing binary artifact delivery. By combining strict manifest validation, transactional release management, and defensive CI configuration, the project maintains a clear trust boundary and ensures that every published plugin binary is traceable to its immutable upstream source.
Sources: README.md:17-27, REVIEW.md:18-35