Skip to content

feat(wbfy): enforce cargo's native min-publish-age in Rust repositories #1256

Description

@exKAZUu

Background and goal

The Renovate preset in willbooster-configs holds crates.io updates back for 7 days with minimumReleaseAge and turns off cargo lockfile maintenance and automerge (WillBooster/willbooster-configs#1098). That check only looks at the dependency Renovate is updating. When Renovate runs cargo update to regenerate Cargo.lock, a new transitive crate from that update can still resolve to a version published minutes ago. The August 2026 crates.io attack (arrayref / internment / append-only-vec, with malicious releases removed less than 90 minutes after publication) shows this can really happen: https://thehackernews.com/2026/08/rust-supply-chain-attack-puts-build.html

Cargo now has a native setting that closes this gap. Stabilization PR rust-lang/cargo#17335 (RFC 3923) merged into milestone 1.100.0:

# .cargo/config.toml
[registry]
global-min-publish-age = "7 days"

With the default resolver.incompatible-publish-age = "deny", any resolution (cargo update, cargo add, cargo generate-lockfile) skips crates.io versions younger than 7 days, including transitive ones. Goal: every Rust repository in the organization resolves dependencies with this setting, and we don't write a custom pubtime check in CI.

Behavior

  • In a repository with a Cargo.toml, wbfy writes .cargo/config.toml next to it with [registry] global-min-publish-age = "7 days", the same age the Renovate preset uses.
  • The Rust toolchain those repositories pin is at least 1.100, so the setting is enforced. Older cargo just warns about the unknown key and ignores it.
  • To push an urgent update through, run CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow cargo update -p <crate> by hand.

Acceptance criteria

  • In a wbfy-applied Rust repository, running cargo update with a crates.io version younger than 7 days available does not select that version.
  • A Renovate cargo update PR in such a repository does not add a transitive crate version younger than 7 days to Cargo.lock.

Scope and non-goals

  • Out of scope: re-checking versions already in Cargo.lock. Cargo accepts locked entries whatever their age, and no CI gate will be added for them. The operational rule "update Rust dependencies only through Renovate PRs (automerge disabled)" covers hand-edited lockfiles and lockfiles resolved with an older cargo.
  • Out of scope: git and path dependencies, which have no pubtime.

Design constraints

  • Blocked until Rust 1.100 is released to stable (stable is currently 1.98.1).
  • docs/expected-repository-rules.md lists the new expectations: the .cargo/config.toml setting, the minimum toolchain, and the Renovate-only rule for Rust dependency updates.

Open questions

  • Which cargo does Renovate use to regenerate Cargo.lock? Does it take the version from rust-toolchain.toml, or does the willbooster-configs preset need constraints: { rust: ">=1.100" }? The fix doesn't work until this is confirmed.
  • How should wbfy handle a repository that already has its own .cargo/config.toml? Options: add only the key, skip with a warning, or treat the file as canonical wbfy output.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions