ci: add preflight visibility to PyPI release workflow - #163
Conversation
Adds an ungated preflight job that validates the pushed tag matches the project version in pyproject.toml and writes a step summary, plus a run-name showing the tag, before the pypi environment approval gate. Applies the pattern from arcjet/arcjet's ADR on preflight visibility for approval-gated workflows (docs/adrs/2026-07-08-preflight-visibility-for-gated-workflows.md), adapted here since this workflow has no dispatch inputs to hide - the gap closed is tag/version validation happening before approval instead of inside the gated publish job.
arcjet-py is a public repo; the referenced ADR lives in the private arcjet monorepo and isn't reachable from here.
There was a problem hiding this comment.
Arcjet Review — 🟡 Medium Risk
Decision: Approved
Rationale: This is a well-scoped CI improvement that adds a preflight job to validate the git tag matches the pyproject.toml version before the pypi environment reviewer approves the publish job. Action versions are pinned by SHA, persist-credentials: false is set on checkout, and user-controlled input (github.ref_name) is passed via environment variable and properly quoted in the shell script, avoiding script injection. The CI/CD escalation trigger fires but the change is defensive and low-blast-radius — it only gates the existing pypi job with an additional check. Approving despite Medium risk.
Summary of Changes
Adds a preflight job to the release workflow that runs before the gated pypi publish job, asserting the pushed tag matches the version in pyproject.toml and writing a summary. Also sets a descriptive run-name so the tag is visible in the run list / environment approval notification, and fixes a missing trailing newline.
Escalation Triggers
- CI/CD Pipeline: Modifies .github/workflows/release.yml, which controls PyPI publishing.
Notes
Diff is well under the size threshold. Security-review skill applied: no injection, secret, or auth concerns identified — TAG_NAME is passed via env and always quoted, and third-party actions are SHA-pinned.
Review: b8e657bd | Model: anthropic/claude-opus-4-7 | Powered by Arcjet Review
| TAG_NAME: ${{ github.ref_name }} | ||
| run: | | ||
| if ! printf '%s' "$TAG_NAME" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$'; then | ||
| echo "::error::Tag '$TAG_NAME' does not look like a release tag (vX.Y.Z)." |
There was a problem hiding this comment.
Nit: the regex accepts either - or + as the pre-release/build separator, but semver treats them distinctly (prerelease uses -, build metadata uses +, and both can appear together as -pre+build). If you want strict semver, consider ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$. Not blocking — the current pattern is fine as a sanity check.
| fi | ||
| expected="${TAG_NAME#v}" | ||
| actual="$(uv version --short)" | ||
| if [ "$actual" != "$expected" ]; then |
There was a problem hiding this comment.
Consider guarding against uv version --short failing or emitting unexpected output (e.g., extra whitespace). A quick set -euo pipefail at the top of the script, or trimming actual, would make the comparison more robust if uv ever changes its output format.
There was a problem hiding this comment.
Pull request overview
This PR improves the PyPI release workflow’s approval-gated visibility by adding an ungated “preflight” job that validates the pushed tag against the project version and writes a step summary, so reviewers can confirm correctness before approving the pypi environment gate.
Changes:
- Add a workflow
run-namethat includes the tag being released. - Introduce an ungated
preflightjob to validategithub.ref_nameagainstuv version --shortand publish a step summary. - Gate the existing
pypipublish job on successful completion ofpreflightvianeeds: preflight.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ! printf '%s' "$TAG_NAME" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$'; then | ||
| echo "::error::Tag '$TAG_NAME' does not look like a release tag (vX.Y.Z)." | ||
| exit 1 | ||
| fi |
|
@estellajaysong if you don't mind having a look |
Adds an ungated preflight job that validates the pushed tag matches the project version in pyproject.toml and writes a step summary, plus a run-name showing the tag, before the pypi environment approval gate. Applies the pattern from arcjet/arcjet's ADR on preflight visibility for approval-gated workflows, adapted here since this workflow has no dispatch inputs to hide - the gap closed is tag/version validation happening before approval instead of inside the gated publish job.