Skip to content

ci: prepare release PRs with the semver version and check tags against Cargo.toml - #23

Open
jonas-dfns wants to merge 11 commits into
mainfrom
ci/semver-version-bump
Open

jonas-dfns wants to merge 11 commits into
mainfrom
ci/semver-version-bump

Conversation

@jonas-dfns

@jonas-dfns jonas-dfns commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Adds a release flow that sets the version for you (or takes yours) through a bot-made PR, and makes publishing refuse a tag that doesn't match Cargo.toml.

How it works

  1. Prepare Release (workflow_dispatch, optional version input) opens the release PR chore(release): X.Y.Z:
    • No input: the version cargo-semver-checks requires against the published crate (one run; the tool reports the bump level, next-version.sh derives the number), and never lower than Cargo.toml on main (an unreleased bump is kept).
    • With input: your version, which only has to be X.Y.Z. It is never blocked; when it differs from what cargo-semver-checks requires, the PR says so for reference.
    • It creates release/X.Y.Z from main and commits only the version lines of Cargo.toml and Cargo.lock.
    • The branch, the commit (Verified) and the PR are made by the dfns-sdk-semver app, so the PR's CI runs. The PR body lists the breaking changes, if any.
  2. Review and merge the release PR, which puts the version in main.
  3. Tag the merge commit X.Y.Z (signed, bare version without a v, like the TS SDK) to publish. publish.yaml now triggers on X.Y.Z tags and gets a check-tag job that runs before the crates-io environment and fails if the tag is not the Cargo.toml version or not on main (the v0.3.1 failure mode).

Later, step 3 can be automated (tag and publish when a chore(release) PR from the app merges) without changing steps 1 and 2.

Security

  • Prepare Release only runs from main. It has a job-level if, and the sdk-semver environment that holds the app's credentials is restricted to main. A copy of the workflow dispatched from another branch can't reach the key.
  • GITHUB_TOKEN stays contents: read everywhere.
  • Version input goes through env: and is validated as X.Y.Z before use.
  • Actions are SHA-pinned, and cargo-semver-checks is pinned to 0.51.0 (cargo install --locked).

⚠️ Admin setup required before merging

Without it, Prepare Release fails at the token step. Publishing works without it.

  1. Create the GitHub App dfns-sdk-semver (owned by dfns):

    • Repository permissions: Contents: Read and write and Pull requests: Read and write, plus Metadata: Read. No webhook.
    • Install it on dfns/dfns-sdk-rust only for now.
  2. Create the sdk-semver environment in dfns-sdk-rust:

    • Deployment branches: selected branches, main only.
    • Variable SEMVER_APP_CLIENT_ID, secret SEMVER_APP_PRIVATE_KEY.
    • No required reviewers.
  3. Change the crates-io environment's deployment tag rule from v* to [0-9]*.[0-9]*.[0-9]*, since release tags no longer start with v. Without it, publishing a new tag is refused.

No ruleset is needed: the automation only writes to the release branches it creates.

Validation (Docker)

  • next-version.sh: against published 0.3.2 it gives 0.3.3 patch; against 0.3.0 it gives 0.4.0 minor breaking ("8 major checks failed"). One run each.
  • open-release-pr.sh with a stubbed gh:
    • A computed breaking release creates the release/0.4.0 branch, commits chore(release): 0.4.0 (Cargo.toml → 0.4.0), and opens the PR with the breaking-change list.
    • A forced 0.3.3, below what cargo-semver-checks requires, gets the same flow, with "For reference, cargo-semver-checks requires 0.4.0".
  • Lint: actionlint 1.7.12 and shellcheck 0.10.0 are clean.

🤖 Generated with Claude Code

…toml

Semver Check runs cargo-semver-checks on monorepo sync PRs against the
published crate and picks the smallest version it accepts (in 0.x a
breaking change bumps the minor). Version Bump, triggered by
workflow_run so it always runs from main, validates that result and
commits it to the sync PR through the GitHub API, labels the release
level, and disables auto-merge on breaking changes. Merging the sync PR
now carries its version, with no separate release PR.

publish.yaml gains a check-tag job that fails before the crates-io
environment when the tag does not match the Cargo.toml version or is
not on main.
@socket-security

socket-security Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgithub/​actions/​create-github-app-token@​bcd2ba49218906704ab6c1aa796996da409d3eb190100100100100

View full report

@socket-security

socket-security Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Caution

Review the following alerts detected in dependencies.

According to your organization's Security Policy, you must resolve all "Block" alerts before proceeding. It is recommended to resolve "Warn" alerts too. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Low priority
System shell access: github actions/create-github-app-token

Location: Package overview

From: .github/workflows/prepare-release.yaml → github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

ℹ Read more on: This package | This alert | What is shell access?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should avoid accessing the shell which can reduce portability, and make it easier for malicious shell access to be introduced.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
Low priority
Potential code anomaly (AI signal): github actions/create-github-app-token is 62.0% likely to have a medium risk anomaly

Notes: No overtly malicious behavior is visible in the workflow YAML alone. However, the workflow executes an opaque repository-local action (uses: ./) that receives a highly sensitive GitHub App private key and then uses the resulting token to perform authenticated PR, commit, and git tag operations. Combined with running npm ci and npm run build (which execute lifecycle/build scripts), this creates a moderate security risk typical of release pipelines, with the local action and dependency/build execution being the primary concerns. The forced major tag update and broad write permissions further increase impact if any upstream component is compromised.

Confidence: 0.62

Severity: 0.64

From: .github/workflows/prepare-release.yaml → github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Block
Low priority
Filesystem access: github actions/create-github-app-token

Location: Package overview

From: .github/workflows/prepare-release.yaml → github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

ℹ Read more on: This package | This alert | What is filesystem access?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: If a package must read the file system, clarify what it will read and ensure it reads only what it claims to. If appropriate, packages can leave file system access to consumers and operate on data passed to it instead.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore github/actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Block

View full report

cargo-semver-checks reports the bump it requires but not the version, so
run it once against the published crate and derive the number, instead of
rerunning it for each candidate version. In 0.y.z its "major" means a y
bump.
Semver Check now runs on all PRs, so hand-written changes (dependencies,
Cargo.toml) also show their release impact through the release labels
and, when breaking, a comment. The version is still only committed to
monorepo sync PRs.

The bump keeps the higher of the computed version and Cargo.toml, so an
unreleased bump already on main (for example a merged breaking sync) is
not lowered by a later patch-level sync. The breaking-change comment is
updated in place instead of repeated.
@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.46%. Comparing base (a7d6376) to head (aa24421).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #23   +/-   ##
=======================================
  Coverage   96.46%   96.46%           
=======================================
  Files           1        1           
  Lines         283      283           
=======================================
  Hits          273      273           
  Misses         10       10           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The workflow now holds the branching: the validated result feeds a
commit step that only runs on sync PRs whose version must change, and a
label step that runs on every PR. Each script does one thing.
A sync PR must be opened by dfnsco-dfns-sdk-sync[bot] (by user ID) and
contain only Verified web-flow commits authored by that app or by
github-actions[bot] (the version commit). Anyone with write access can
name a branch sdk-sync/, and a commit author can be set by email, but a
pushed commit is never a Verified web-flow commit attributed to the app.
Other PRs are labeled but never committed to.
commit-version.sh now checks the PR comes from the sync app before
committing, so validation stays shared and each flow is self-contained.
The label step suggests a version whenever this run did not set one.
Clarify how 0.x versions bump and how to move to 1.0.0.
Version Bump is split into three jobs: validate (read-only), commit-version
(sync PRs, release app token from the main-restricted sdk-release
environment) and label (GITHUB_TOKEN, pull-requests only). GITHUB_TOKEN no
longer needs contents: write.

Version commits are now authored by the release app, which triggers the
PR's CI, and the sync-PR check accepts commits from the sync app and the
release app only. github-actions[bot] commits are no longer accepted, so
a PR workflow with a write token cannot pass as a sync commit.
Environment sdk-semver, variable SEMVER_APP_CLIENT_ID and secret
SEMVER_APP_PRIVATE_KEY.
Replace the version commit on sync PRs with a Prepare Release workflow
(workflow_dispatch). It opens a chore(release) PR, as the dfns-sdk-semver
app, that sets the version in Cargo.toml and Cargo.lock: the version
cargo-semver-checks requires against the published crate, or the one
given as input. A forced version is never blocked; the PR shows what
cargo-semver-checks requires for reference.

Semver Check on PRs becomes a read-only report. Removes the workflow_run
job, the sync-PR identity checks and the labels.
@jonas-dfns jonas-dfns changed the title ci: set the release version on sync PRs and check tags against Cargo.toml ci: prepare release PRs with the semver version and check tags against Cargo.toml Oct 26, 2026
The per-PR Semver Check only reported; Prepare Release computes and shows
the required version when it opens the release PR.
Release tags are the Cargo.toml version without a v prefix (0.3.3), like
the TS SDK. The release branch is release/X.Y.Z. The crates-io
environment's tag rule (v*) must be changed to match.

This branch has not been deployed

No deployments
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