Skip to content

ci: add crates.io publish job to release workflow#29

Merged
mickvandijke merged 2 commits intomainfrom
ci/crates-io-publish
Mar 18, 2026
Merged

ci: add crates.io publish job to release workflow#29
mickvandijke merged 2 commits intomainfrom
ci/crates-io-publish

Conversation

@mickvandijke
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a publish-crate job to the release workflow that publishes to crates.io after the GitHub release is created
  • Uses CRATES_IO_TOKEN secret (matching saorsa-core's convention)
  • Includes dry-run verification before actual publish

Before merging

  • Ensure CRATES_IO_TOKEN secret is configured in repo settings

After merging

Re-tag v0.4.0 to trigger the release with crates.io publish:

git push origin :refs/tags/v0.4.0
git tag -f v0.4.0
git push origin v0.4.0

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 18, 2026 12:45
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 18, 2026

Greptile Summary

This PR adds a publish-crate job to the existing release workflow, publishing the crate to crates.io after the GitHub release is created. The job correctly depends on release, uses the standard CARGO_REGISTRY_TOKEN secret, and follows the common pattern of a dry-run step before the real publish.

Key changes:

  • New publish-crate job chains off the existing release job and runs on ubuntu-22.04.
  • Uses dtolnay/rust-toolchain@stable and Swatinem/rust-cache@v2, consistent with other jobs in the file.
  • Dry-run step (cargo publish --dry-run --allow-dirty) is meant as a pre-flight check.
  • Actual publish step (cargo publish --no-verify --allow-dirty) skips cargo's built-in verification, relying entirely on the dry-run result.

Issue found:

  • Both steps use --allow-dirty, which bypasses cargo's check that the working tree is clean. Because the dry-run's guard is disabled via --allow-dirty, and the publish step's guard is disabled via --no-verify, neither step performs an independent, rigorous integrity check on the committed code. In a clean actions/checkout@v4 environment, --allow-dirty is unnecessary on the dry-run step and should be removed to preserve the verification chain.

Confidence Score: 3/5

  • Safe to merge with low immediate risk, but the dry-run verification is weaker than intended due to --allow-dirty on the verification step.
  • The workflow structure is sound and the secret name matches convention. The only meaningful issue is that --allow-dirty on the dry-run step plus --no-verify on the publish step means neither cargo safety check is fully active — in the current clean-checkout CI environment this is unlikely to cause a real problem, but it removes a layer of defence-in-depth for future workflow changes.
  • .github/workflows/release.yml — specifically the Verify crate and Publish to crates.io steps in the new publish-crate job.

Important Files Changed

Filename Overview
.github/workflows/release.yml Adds a publish-crate job that runs after release; the job's dry-run and actual-publish steps both use --allow-dirty, and the publish step also adds --no-verify, meaning neither step performs a complete independent integrity check on the packaged crate.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub (tag push)
    participant build as build jobs
    participant sign as sign job
    participant release as release job
    participant publish as publish-crate job
    participant cio as crates.io

    GH->>build: trigger on v* tag
    build->>sign: artifacts uploaded
    sign->>release: signed artifacts
    release->>GH: GitHub Release created
    release->>publish: needs: release
    publish->>publish: cargo publish --dry-run --allow-dirty
    publish->>cio: cargo publish --no-verify --allow-dirty\n(CARGO_REGISTRY_TOKEN)
    cio-->>publish: published ✓
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 396-399

Comment:
**Dry-run + publish bypass each other's safety checks**

The two steps together end up verifying very little. The dry-run step uses `--allow-dirty`, which tells cargo to ignore any untracked or modified files in the working tree — so it isn't checking the exact committed snapshot. The actual publish step then uses `--no-verify`, which skips cargo's own packaging verification entirely.

The intended safety net is: "dry-run catches problems, so actual publish can skip re-checking." But because the dry-run already skips the dirty-state guard (`--allow-dirty`), the chain of trust is weakened. If anything modifies the working tree between checkout and publication (e.g., the `rust-cache` action writing files, or a future workflow change), neither step will flag the discrepancy.

In a clean `actions/checkout@v4` environment, `--allow-dirty` is not needed. Removing it from the dry-run step restores the guarantee that you are verifying exactly what was committed:

```suggestion
      - name: Verify crate
        run: cargo publish --dry-run

      - name: Publish to crates.io
        run: cargo publish --allow-dirty
```

(The `--allow-dirty` can stay on the publish step alone to handle the edge case where `cargo publish --dry-run` updates `Cargo.lock` and leaves the tree slightly dirty, but the verification itself should run against the clean tree.)

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "ci: add crates.io pu..."

Comment thread .github/workflows/release.yml Outdated
Comment on lines +396 to +399
run: cargo publish --dry-run --allow-dirty

- name: Publish to crates.io
run: cargo publish --no-verify --allow-dirty
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Dry-run + publish bypass each other's safety checks

The two steps together end up verifying very little. The dry-run step uses --allow-dirty, which tells cargo to ignore any untracked or modified files in the working tree — so it isn't checking the exact committed snapshot. The actual publish step then uses --no-verify, which skips cargo's own packaging verification entirely.

The intended safety net is: "dry-run catches problems, so actual publish can skip re-checking." But because the dry-run already skips the dirty-state guard (--allow-dirty), the chain of trust is weakened. If anything modifies the working tree between checkout and publication (e.g., the rust-cache action writing files, or a future workflow change), neither step will flag the discrepancy.

In a clean actions/checkout@v4 environment, --allow-dirty is not needed. Removing it from the dry-run step restores the guarantee that you are verifying exactly what was committed:

Suggested change
run: cargo publish --dry-run --allow-dirty
- name: Publish to crates.io
run: cargo publish --no-verify --allow-dirty
- name: Verify crate
run: cargo publish --dry-run
- name: Publish to crates.io
run: cargo publish --allow-dirty

(The --allow-dirty can stay on the publish step alone to handle the edge case where cargo publish --dry-run updates Cargo.lock and leaves the tree slightly dirty, but the verification itself should run against the clean tree.)

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release.yml
Line: 396-399

Comment:
**Dry-run + publish bypass each other's safety checks**

The two steps together end up verifying very little. The dry-run step uses `--allow-dirty`, which tells cargo to ignore any untracked or modified files in the working tree — so it isn't checking the exact committed snapshot. The actual publish step then uses `--no-verify`, which skips cargo's own packaging verification entirely.

The intended safety net is: "dry-run catches problems, so actual publish can skip re-checking." But because the dry-run already skips the dirty-state guard (`--allow-dirty`), the chain of trust is weakened. If anything modifies the working tree between checkout and publication (e.g., the `rust-cache` action writing files, or a future workflow change), neither step will flag the discrepancy.

In a clean `actions/checkout@v4` environment, `--allow-dirty` is not needed. Removing it from the dry-run step restores the guarantee that you are verifying exactly what was committed:

```suggestion
      - name: Verify crate
        run: cargo publish --dry-run

      - name: Publish to crates.io
        run: cargo publish --allow-dirty
```

(The `--allow-dirty` can stay on the publish step alone to handle the edge case where `cargo publish --dry-run` updates `Cargo.lock` and leaves the tree slightly dirty, but the verification itself should run against the clean tree.)

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds crates.io publishing to the existing tag-based release pipeline so that a Rust crate is published after the GitHub Release is created.

Changes:

  • Introduces a new publish-crate job that runs after the release job.
  • Runs cargo publish --dry-run before attempting an actual cargo publish.
  • Uses the repository secret CRATES_IO_TOKEN via CARGO_REGISTRY_TOKEN.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread .github/workflows/release.yml Outdated
Comment on lines +396 to +399
run: cargo publish --dry-run --allow-dirty

- name: Publish to crates.io
run: cargo publish --no-verify --allow-dirty
Comment thread .github/workflows/release.yml Outdated
run: cargo publish --dry-run --allow-dirty

- name: Publish to crates.io
run: cargo publish --no-verify --allow-dirty
Comment thread .github/workflows/release.yml Outdated
uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

Comment thread .github/workflows/release.yml Outdated
publish-crate:
name: Publish to crates.io
needs: release
runs-on: ubuntu-22.04
Aligns with saorsa-core's release workflow pattern:
- validate job checks version format and Cargo.toml match
- test job runs fmt, clippy, and tests before building
- security-audit job runs cargo audit
- publish-crate runs parallel to build pipeline after gates pass
- workflow_dispatch support with dry_run option
- all version references use validate job outputs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mickvandijke mickvandijke merged commit b04f49c into main Mar 18, 2026
11 checks passed
@mickvandijke mickvandijke deleted the ci/crates-io-publish branch March 18, 2026 13:25
mickvandijke added a commit that referenced this pull request Apr 1, 2026
Implements the remaining untested scenarios from REPLICATION_DESIGN.md
Section 18, bringing coverage from 47/56 to 56/56:

- #20: paid-list local hit bypasses presence quorum (quorum.rs)
- #22: paid-list rejection below threshold (quorum.rs)
- #29: audit start gate during bootstrap (audit.rs)
- #30: audit peer selection from sampled keys (audit.rs)
- #31: audit periodic cadence with jitter bounds (config.rs)
- #32: dynamic challenge size equals PeerKeySet (audit.rs)
- #47: bootstrap claim grace period in audit path (audit.rs)
- #48: bootstrap claim abuse after grace period (paid_list.rs)
- #53: audit partial per-key failure with mixed responsibility (audit.rs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mickvandijke added a commit that referenced this pull request Apr 1, 2026
Implements the remaining untested scenarios from REPLICATION_DESIGN.md
Section 18, bringing coverage from 47/56 to 56/56:

- #20: paid-list local hit bypasses presence quorum (quorum.rs)
- #22: paid-list rejection below threshold (quorum.rs)
- #29: audit start gate during bootstrap (audit.rs)
- #30: audit peer selection from sampled keys (audit.rs)
- #31: audit periodic cadence with jitter bounds (config.rs)
- #32: dynamic challenge size equals PeerKeySet (audit.rs)
- #47: bootstrap claim grace period in audit path (audit.rs)
- #48: bootstrap claim abuse after grace period (paid_list.rs)
- #53: audit partial per-key failure with mixed responsibility (audit.rs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

3 participants