Releases: hseshadr/ci
Release list
ci-v3.2.1
Patch. Re-pin only if you publish through python-publish.yml or ts-publish.yml, or if you copied one of the examples/*/publish.yml inline jobs. Nothing else in this release reaches a consumer.
Pin 605e51cbc86f452b56edcf1c9660921da797cbfe, not the tag — tests/security-policy.sh rejects a moving @ci-vN ref, first-party included.
What changed
The publish-verification step polls the registry after an upload and fails if the version is not served. Its budget was 6 attempts 10s apart (~60s). That was too tight, and it failed releases that had genuinely shipped: edgeproc-core 0.4.0 went live on PyPI and its publish run went red anyway.
Measured 2026-08-03 — time from a green upload until the registry served the version:
| package | time to serve |
|---|---|
PyPI edgeproc-core 0.4.0 |
>60s — failed this check while genuinely live |
PyPI edge-proc 0.3.0 |
~120s |
npm @edgeproc/errors 0.1.0 |
~200s — first publish of a new package name |
npm @edgeproc/avow 0.3.0 |
~60s |
New budget: 14 attempts with backoff (5, 10, 15, 30, then 60s) — 600s of sleep, 3x the slowest case measured. The common case still verifies in ~15s, so nobody pays the budget who does not need it.
The failure message now separates STILL PROPAGATING from THE RELEASE NEVER HAPPENED. It previously named only the misconfiguration causes, which is misleading now that a timeout is more often propagation.
The guard keeps its teeth
Only the budget moved. The verdict did not: a green upload is still not proof of a release, the registry is still the authority, and a timeout is still a FAILURE. Run the step against a version PyPI or npm does not serve and it still exits 1 — after 600s instead of 60s. That is the whole cost: a genuinely failed publish now takes ~10 minutes to say so.
Why this was worth a release rather than a shrug: a red run sitting on a live release teaches the reader to wave off red publish runs. That habit is exactly how the six-green-runs-while-the-package-404s defect comes back.
The three examples/*/publish.yml inline copies carry the same bound, so the copy-paste surface does not ship the defect. If you copied one, re-copy it.
Compatibility
- No brick changed shape. No input, output or permission moved, so no caller needs editing — re-pinning from
ci-v3.2.0is a drop-in. - No composite action changed, so the release-commit bootstrap gap does not apply here. All 41 first-party refs at this commit already name
ci-v3.2.0, and every composite reached through them is byte-identical to the one in this tree.
Known gap in this repo's own records
CHANGELOG.md at this commit has no sections for ci-v3.1.0 or ci-v3.2.0 — its Unreleased heading still reads "after ci-v3.0.0" while two releases have been cut since. A follow-up PR records all three. It is a documentation gap only; the released trees are correct.
ci-v3.2.0
This is the tag consumers should pin.
All 26 first-party refs (9 in .github/, 17 in examples/) resolve to the composite running astral-sh/setup-uv v9.0.0.
Per the documented release-commit bootstrap, this tagged tree's own refs name ci-v3.1.0 — a commit cannot contain its own SHA. ci-v3.1.0 is the composite fix, so a consumer pinning ci-v3.2.0 gets reusable workflows whose nested composites run v9.0.0.
ci-v3.1.0
The setup-python-uv composite now runs astral-sh/setup-uv v9.0.0.
ci-v3.0.0's tree carried v8.3.2, so every consumer calling python-gate, python-publish or security-audit executed the old version while their own ci.yml ran v9.0.0.
Do not pin this tag yet — ci's own 9 self-pins still point at ci-v3.0.0. ci-v3.2.0 is the tag consumers should pin.
ci v3.0.0
ci v1.0.1
Security-hardening release for the shared portfolio workflows.
- Pins third-party Actions to immutable SHAs.
- Validates reusable-workflow inputs before shell execution.
- Disables persisted checkout credentials.
- Adds least-privilege permissions, Dependabot cooldown, security-header baseline, ShellCheck, and a clean full-repository zizmor gate.
ci-v1 now points to this release.