Skip to content

ci: make crate publish re-runnable and fix cargo-sbom install on persistent cache#41

Merged
27Bslash6 merged 2 commits into
mainfrom
fix/release-publish-rerunnable
Jun 6, 2026
Merged

ci: make crate publish re-runnable and fix cargo-sbom install on persistent cache#41
27Bslash6 merged 2 commits into
mainfrom
fix/release-publish-rerunnable

Conversation

@27Bslash6

@27Bslash6 27Bslash6 commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

What

Makes the crate publish job both robust and re-runnable:

  1. cargo install cargo-sbom --locked --force — the self-hosted runner's CARGO_HOME (/cache/cargo) is a persistent volume, so the binary survives between runs and a plain install exits 101 (binary cargo-sbom already exists). --force reinstalls the --locked pinned version idempotently.
  2. workflow_dispatch trigger + publish gate widened to release_created || workflow_dispatch — lets a tagged-but-unpublished version be published via CI (with full build-provenance + SBOM attestation) instead of by hand.

Why

0.2.1 was tagged by release-please but its publish job failed twice — first a transient Sigstore/Fulcio cert error, then deterministically on the cargo-sbom step above. The release was gated such that there was no CI path to re-publish an already-tagged version (re-running the failed run is pinned to the old workflow file). This fixes both the immediate bug and the structural gap.

After merge

gh workflow run release.yml (or the Actions UI Run workflow button) publishes the current main version (0.2.1) through the full attest → SBOM → publish pipeline.

ci: type — non-releasing.

Summary by CodeRabbit

  • Chores
    • Enhanced release workflow with a manual re-publish escape hatch and serialised release runs to avoid overlapping releases.
    • Adjusted release conditions so releases run for both automated creations and manual dispatches on main.
    • Improved tool installation during releases to be idempotent on persistent runners, reducing setup failures from repeated runs.

…istent cache

Two coupled problems surfaced publishing 0.2.1 from the self-hosted runner:

1. `cargo install cargo-sbom --locked` exits 101 ("binary already exists")
   because the runner's CARGO_HOME (/cache/cargo) is a persistent volume —
   the binary survives across runs. Plain install is not idempotent there.
   Fix: add --force so it reinstalls the --locked pinned version each time.

2. When the publish job fails after release-please has already tagged the
   release, there was no way to re-publish: the job is gated on
   `release_created`, which is only true on the release-PR merge, and
   re-running the original run is pinned to the old workflow file.
   Fix: add a `workflow_dispatch` trigger and allow the publish job to run
   on it, so a tagged-but-unpublished version can be published via CI
   (preserving build-provenance + SBOM attestation) instead of by hand.
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Looking for one thing? Review this PR in Change Stack to search files, summaries, diffs, and code without losing your place.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f32cef0c-6fa1-481d-9850-e4412bd58063

📥 Commits

Reviewing files that changed from the base of the PR and between 0255792 and 852727f.

📒 Files selected for processing (1)
  • .github/workflows/release.yml

Walkthrough

Adds workflow_dispatch for manual re-publish, adds a concurrency group to serialize release runs, updates the publish job condition to run on automated releases or manual dispatch on refs/heads/main, and makes cargo-sbom installation idempotent by adding --force.

Changes

Release Workflow Manual Dispatch and Tooling

Layer / File(s) Summary
Manual dispatch trigger and concurrency
.github/workflows/release.yml
Adds workflow_dispatch: {} and a concurrency block (group: release-${{ github.ref }}, cancel-in-progress: false) to enable manual invocation and prevent overlapping release runs.
Publish job condition update
.github/workflows/release.yml
Modifies the publish job if: to run when release_created == 'true' or when manually dispatched targeting refs/heads/main.
SBOM tool installation idempotency
.github/workflows/release.yml
Changes cargo install cargo-sbom to include --force alongside --locked to avoid install failures on persistent self-hosted runners.

Possibly related PRs

  • cachekit-io/cachekit-core#27: Both modify .github/workflows/release.yml, including SBOM installation/usage details that relate to this PR's idempotency change.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: making the crate publish job re-runnable and fixing cargo-sbom installation on persistent cache.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-publish-rerunnable

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)

1-16: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add concurrency guard to serialise release/publish executions

There is no workflow/job concurrency control, so overlapping runs (e.g. push + manual dispatch) can race into duplicate publish attempts against crates.io. Add a concurrency group (workflow-level or publish job-level) with cancel-in-progress: false.

Suggested fix
 name: Release
+concurrency:
+  group: release-${{ github.ref }}
+  cancel-in-progress: false

Also applies to: 34-43

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 1 - 16, Add a concurrency guard
to the Release workflow to prevent overlapping publish runs by adding a
concurrency block (either workflow-level or inside the publish job) with a
stable group name (e.g. "release-${{ github.ref }}" or "publish") and
cancel-in-progress: false; update the existing workflow YAML (the top-level
workflow "Release" or the "publish" job definition) to include concurrency: with
group and cancel-in-progress: false so manual dispatches and pushes are
serialized.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Line 37: The publish gate is unsafe because
needs.release-please.outputs.release_created is a string and workflow_dispatch
can target arbitrary refs; update the `if:` to perform an explicit string
comparison on needs.release-please.outputs.release_created (e.g., compare to
'true') and additionally require the ref for manual dispatch to be the main
branch by checking github.ref (or github.event.ref) equals 'refs/heads/main'
when github.event_name == 'workflow_dispatch'; locate the condition line
referencing needs.release-please.outputs.release_created and github.event_name
and replace it with an explicit boolean expression that enforces both the string
comparison and the main-branch check before allowing cargo publish.

---

Outside diff comments:
In @.github/workflows/release.yml:
- Around line 1-16: Add a concurrency guard to the Release workflow to prevent
overlapping publish runs by adding a concurrency block (either workflow-level or
inside the publish job) with a stable group name (e.g. "release-${{ github.ref
}}" or "publish") and cancel-in-progress: false; update the existing workflow
YAML (the top-level workflow "Release" or the "publish" job definition) to
include concurrency: with group and cancel-in-progress: false so manual
dispatches and pushes are serialized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 578c7a0e-7386-434c-be62-d231fd391537

📥 Commits

Reviewing files that changed from the base of the PR and between 57ebdc5 and 0255792.

📒 Files selected for processing (1)
  • .github/workflows/release.yml

Comment thread .github/workflows/release.yml Outdated
…y dispatch

Addresses CodeRabbit review on #41:
- Add workflow-level concurrency (group: release-<ref>, cancel-in-progress:
  false) so a push and a manual dispatch can't race into two concurrent
  cargo publish attempts.
- Restrict the publish job's manual-dispatch path to refs/heads/main so a
  workflow_dispatch fired from a feature branch can't publish that branch's
  Cargo.toml version. Also make the release_created check an explicit
  == 'true' comparison rather than relying on string coercion.
@27Bslash6

Copy link
Copy Markdown
Contributor Author

@coderabbitai Both addressed in 852727f:

  • Concurrency: added workflow-level concurrency: { group: release-${{ github.ref }}, cancel-in-progress: false }.
  • Gate safety: if: now requires release_created == 'true' explicitly, and the manual-dispatch path is gated on github.ref == 'refs/heads/main' so a dispatch from a feature branch can't publish its own Cargo.toml.

Please re-review.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat .github/workflows/release.yml

Length of output: 3496



@27Bslash6 Both fixes look solid — re-review passes. ✅

Concurrency (concurrency block)

  • group: release-${{ github.ref }} correctly collapses a push-to-main and a same-ref manual dispatch into the same group, so they can't race into two concurrent cargo publish attempts.
  • cancel-in-progress: false is the right call — you never want an in-flight publish torn down mid-way.

Gate safety (if: condition)

if: ${{ needs.release-please.outputs.release_created == 'true'
     || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') }}
  • == 'true' (explicit string comparison) is strictly correct; it won't coerce '' or null to truthy.
  • The refs/heads/main guard on the dispatch leg closes the original concern — a workflow_dispatch fired from a feature branch will not publish that branch's Cargo.toml.
  • On a workflow_dispatch run, release-please still executes but outputs nothing (release_created is empty), so the automated path stays inert and only the dispatch leg fires.

The rest of the workflow (--force on cargo-sbom, the SBOM non-empty assertion, pinned action SHAs) all look fine. This is good to merge.

(✿◠‿◠)🐰


✏️ Learnings added
Learnt from: 27Bslash6
URL: https://github.com/cachekit-io/cachekit-core/pull/41

Timestamp: 2026-06-06T03:48:14.347Z
Learning: In cachekit-io/cachekit-core, the .github/workflows/release.yml workflow uses a self-hosted runner named "cachekit" with a persistent CARGO_HOME at /cache/cargo. The cargo-sbom install step requires --force flag (cargo install cargo-sbom --locked --force) because the persistent volume causes plain `cargo install --locked` to exit 101 when the binary already exists from prior runs.

Learnt from: 27Bslash6
URL: https://github.com/cachekit-io/cachekit-core/pull/41

Timestamp: 2026-06-06T03:48:14.348Z
Learning: In cachekit-io/cachekit-core .github/workflows/release.yml, the publish job gate uses explicit string comparison `needs.release-please.outputs.release_created == 'true'` (not just truthy check) to avoid string-coercion of empty/null output. The workflow_dispatch path is restricted to `github.ref == 'refs/heads/main'` to prevent feature branches from publishing their own Cargo.toml.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@27Bslash6 27Bslash6 merged commit dcf016f into main Jun 6, 2026
30 checks passed
@27Bslash6 27Bslash6 deleted the fix/release-publish-rerunnable branch June 6, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant