Skip to content

release.yml: same-revision CI gate, timeouts, environment coverage, latest promotion guard #985

Closed

Description

@e54-bot

Follow-up from wrightkit/.github#49 audit (docs/ci-release-audit-2026-10.md, W-P2).

Problem

  • release-identity verifies tag↔commit↔version but encodes no same-revision CI gate; only the nightly path is CI-gated via workflow_run success (release.yml:36–39). Stable publication relies on Release-PR merge protection, invisible in the workflow.
  • No timeout-minutes on any job in release.yml or release-please.yml (rust-ci.md rule 7).
  • publish-r2, advance-latest, publish-tap hold R2/GH_TOKEN secrets without environment: release (only publish-release/publish-npm use it).
  • Per-tag concurrency groups (wright-<tag>) do not serialize across tags; two stable runs can interleave publish-r2/publish-release --latest/advance-latest and regress latest (R2 pointer or GitHub-latest).
  • Edge: if the Release already exists as public (not draft), publish-release logs and uploads nothing — a silently empty release.

Desired behavior

  • release-identity (or an equivalent early job) asserts the required check-runs succeeded for RELEASE_COMMIT before any publish job runs.
  • timeout-minutes on every job.
  • R2/token-bearing publish jobs run in the release environment.
  • latest promotion is serialized per repository or version-monotonic so an older tag cannot overwrite a newer release.
  • The existing-public-release edge fails loudly instead of shipping an empty release.

Acceptance criteria

  • Stable publication refuses when the tagged revision's required checks have not succeeded.
  • Every job carries timeout-minutes.
  • publish-r2/advance-latest/publish-tap run in environment: release.
  • Concurrent stable runs cannot regress latest.
  • Pre-existing public release is an explicit failure, not a silent no-op.

Evidence

Audit wright release findings with line citations in docs/ci-release-audit-2026-10.md.

Activity

  1. added
    ready-for-implementationContract settled; an Engineer can implement without inventing a decision
    p3Chores, cleanup, nice to have; only when nothing higher is ready
    on Oct 24, 2026
  2. added theissue type on Oct 24, 2026
  3. e54-bot commented on Oct 24, 2026

    @e54-bot
    CollaboratorAuthor

    Implementation delivered in #989 (approve after review round 2; all CI checks green). The remaining action is the required CODEOWNERS review on .github/workflows/ — same owner gate as #988.

    What the PR implements, per the acceptance criteria:

    • release-identity gained a stable-only Require CI success on the release revision step polling the CI result aggregate check-run on RELEASE_COMMIT (fails closed on missing/non-success/API error, 90-minute window).
    • Stable runs serialize via the shared wright-stable concurrency group; a Guard latest promotion order step refuses a tag older than the published wright/latest/version pointer (equal versions pass for idempotent re-runs).
    • timeout-minutes on all 11 jobs in release.yml + the release-please job.
    • environment: release added to publish-r2, advance-latest, publish-tap (all five secret-bearing publish jobs now use it; publish-r2 also covers nightly, so nightly R2 publishes now run in the release environment — flagging in case the environment has protection rules that would stall nightlies).
    • publish-release now fails when the GitHub Release already exists as public instead of silently no-opping.

    A latent bug this work also fixed: the check-runs poll used gh api -f (implicit POST → 404 on a GET-only endpoint). The same bug existed in the shared release-plz-crates.yml gate and is fixed on .github main via wrightkit/.github#131.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-decisionProduct or behavior decision unresolvedp3Chores, cleanup, nice to have; only when nothing higher is readyready-for-implementationContract settled; an Engineer can implement without inventing a decision

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions