From 8f9644f9b969f06afad1b2ca6043d6bde06fe2fc Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Fri, 4 Sep 2026 14:36:42 -0300 Subject: [PATCH 1/3] Add a 14-day publish-age cooldown to dependency resolution and build --locked everywhere Ports Commit-Boost/commit-boost-client#492. Cargo's unstable min-publish-age (rust-lang/cargo#17009) excludes crate versions published less than N days ago from resolution, a cooldown against freshly compromised releases. The policy lives in .cargo/config.toml; stable cargo 1.97.1 ignores the tables silently, so only the pinned nightly-2026-06-21 resolver behind `make update` enforces it. That is why `make lint`, `make test`, CI check/clippy and the Docker cook step now pass --locked: an unresolved manifest change fails loudly instead of being re-resolved on stable around the cooldown. `make update-allow PACKAGE= VERSION=` is the escape hatch for a version younger than the window; it bypasses the whole resolution, so the lockfile diff must be reviewed. `make cooldown-check` and a new advisory CI job surface lockfile entries younger than the window via `cargo update --dry-run`, which is the only form that flags them (`--workspace` does not), and never fail the build. As of today a full re-resolution under any window of 8+ days fails: rand 0.10 needs chacha20 0.10, whose 0.10.0/0.10.1 are yanked and whose only live release was published 2026-08-27. `make update` errors and the CI job warns until 2026-09-10. The lockfile is unchanged and still pins the yanked chacha20 0.10.0. --- .cargo/config.toml | 13 ++++++++++++ .github/workflows/ci.yml | 35 ++++++++++++++++++++++++++++++-- CLAUDE.md | 3 +++ CONTRIBUTING.md | 7 +++++++ Dockerfile | 2 +- Makefile | 43 +++++++++++++++++++++++++++++++++++++--- 6 files changed, 97 insertions(+), 6 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 934b5126..19c7f8f7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,3 +3,16 @@ rustflags = [ "-Ctarget-cpu=x86-64-v3", "-Ctarget-feature=+avx2,+sse2,+ssse3,+sse4.1,+sse4.2,+bmi1,+lzcnt,+pclmulqdq", ] + +# Supply-chain cooldown for dependency resolution (unstable min-publish-age, +# tracking issue rust-lang/cargo#17009): crate versions published less than +# 14 days ago are excluded when the resolver runs on a nightly cargo. +# Stable cargo ignores these tables silently, so builds from the committed +# Cargo.lock are unaffected; run `make update` to resolve under the policy. +# When the feature stabilizes, drop the [unstable] table and the nightly +# resolver pin in the Makefile: the policy then binds all resolution. +[unstable] +min-publish-age = true + +[registry] +global-min-publish-age = "14 days" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a22d9309..be03cf89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,11 +43,14 @@ jobs: - name: Check formatting run: cargo fmt --all -- --check + # `--locked` so the committed Cargo.lock is actually enforced (see the + # tooling steps below), and so a dependency bump cannot sneak past the + # publish-age cooldown in .cargo/config.toml by resolving on stable here. - name: Cargo check - run: cargo check --workspace --all-targets + run: cargo check --locked --workspace --all-targets - name: Clippy - run: cargo clippy --workspace --all-targets -- -D warnings + run: cargo clippy --locked --workspace --all-targets -- -D warnings # tooling/event-monitor declares its own [workspace] table, so every step # above stops at the root workspace members and never reaches it. Its @@ -83,3 +86,31 @@ jobs: cargo run --profile release-fast --bin ethlambda -- benchmark synthetic --mock-crypto \ --num-validators 4 --warmup-slots 4 --iterations 3 --format json \ | jq -e '.schema_version == 1 and (.samples | length == 3)' + + # Stable cargo ignores the publish-age cooldown in .cargo/config.toml, so the + # lockfile can pin too-young crates (or deliberately via `make update-allow`). + # Surface them as annotations; this job never fails the build. + cooldown: + name: Dependency cooldown + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Check lockfile against the publish-age cooldown + run: | + if ! rustup toolchain install nightly-2026-06-21 --profile minimal; then + echo "::warning title=Publish-age cooldown check skipped::toolchain install failed" + exit 0 + fi + if ! cargo +nightly-2026-06-21 update --dry-run -Z min-publish-age > cooldown.txt 2>&1; then + # Drop the index/git refresh chatter so the excerpt is the actual error; %0A = newline in annotations + msg=$(grep -v '^ *Updating ' cooldown.txt | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') + echo "::warning title=Publish-age cooldown probe failed::$msg" + exit 0 + fi + hits=$(grep -E "Downgrading|is too new" cooldown.txt || true) + if [ -n "$hits" ]; then + count=$(echo "$hits" | wc -l) + msg=$(echo "$hits" | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') + echo "::warning title=Lockfile pins $count crate(s) younger than the publish-age cooldown::$msg" + fi diff --git a/CLAUDE.md b/CLAUDE.md index 7ce0bb6c..c04b7cc3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,6 +90,9 @@ make test # All tests + forkchoice spec tests ### Common Operations ```bash rm -rf leanSpec && make leanSpec/fixtures # Download latest released test fixtures +make update UPDATE_ARGS="-p " # Bump deps under the 14-day publish-age cooldown (nightly resolver) +make update-allow PACKAGE= VERSION= # Escape hatch for a version younger than the cooldown +make cooldown-check # Warn about lockfile entries younger than the cooldown make docker-build # Build Docker image (DOCKER_TAG=local) make run-devnet # Run local devnet with lean-quickstart ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9afb826..be6db77d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,6 +96,13 @@ All commits must have a verified signature. - **Comments:** Explain *why*, not *what*. Code should be self-explanatory. - **Error handling:** Use `Result` and `thiserror`. Avoid `.unwrap()` outside tests. - **Dependencies:** Adding a new crate requires justification in the PR description. + Resolve version bumps with `make update` (optionally `UPDATE_ARGS="-p "`): it runs + the resolver under a 14-day publish-age cooldown (`.cargo/config.toml`) that excludes + freshly published crate versions as a supply-chain precaution. A plain `cargo update` or + `cargo add` on stable bypasses the cooldown; `make lint`/`make test` and CI build + `--locked` so an unresolved manifest change fails loudly instead of silently re-resolving. + For an urgent fix younger than the cooldown use `make update-allow PACKAGE= VERSION=` + and review the whole lockfile diff. Git dependencies have no publish age and are not covered. ### Review Process diff --git a/Dockerfile b/Dockerfile index df228ea1..16e62239 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,7 +38,7 @@ ENV NO_DEFAULT_FEATURES=$NO_DEFAULT_FEATURES ARG LOCKED="--locked" ENV LOCKED=$LOCKED -RUN cargo chef cook --profile $BUILD_PROFILE $NO_DEFAULT_FEATURES --features "$FEATURES" --recipe-path recipe.json +RUN cargo chef cook --profile $BUILD_PROFILE $NO_DEFAULT_FEATURES --features "$FEATURES" $LOCKED --recipe-path recipe.json # Build application # Include .git so vergen-git2 can extract version info (branch, commit SHA) diff --git a/Makefile b/Makefile index ee6c28dc..e93eae44 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help fmt lint bench docker-build shadow-build shadow-docker-build run-devnet test docs docs-deps docs-serve +.PHONY: help fmt lint bench update update-allow cooldown-check docker-build shadow-build shadow-docker-build run-devnet test docs docs-deps docs-serve help: ## ๐Ÿ“š Show help for each of the Makefile recipes @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -6,13 +6,50 @@ help: ## ๐Ÿ“š Show help for each of the Makefile recipes fmt: ## ๐ŸŽจ Format all code using rustfmt cargo fmt --all +# `--locked` so the committed Cargo.lock is actually enforced: without it cargo +# silently resolves and rewrites the lockfile, bypassing the publish-age cooldown +# (see `update` below). lint: ## ๐Ÿ” Run clippy on all workspace crates - cargo clippy --workspace --all-targets -- -D warnings + cargo clippy --locked --workspace --all-targets -- -D warnings test: leanSpec/fixtures ## ๐Ÿงช Run all tests # release-fast: release-grade opt-level to avoid stack overflows during # signature verification/aggregation, without paying for LTO on every rebuild - cargo test --workspace --profile release-fast + cargo test --locked --workspace --profile release-fast + +# Used ONLY to resolve dependency updates: min-publish-age (.cargo/config.toml) +# is nightly-only, everything else runs on the stable toolchain pinned in +# rust-toolchain.toml. +RESOLVER_TOOLCHAIN := nightly-2026-06-21 + +# Versions published less than 14 days ago are excluded from resolution. +# Resolution done on stable (`cargo add`, plain `cargo update`) is NOT covered; +# this target is the intended path for routine updates. Git dependencies have +# no publish age and are refreshed WITHOUT any cooldown: review their lockfile +# rev changes manually. +update: ## ๐Ÿ“ฆ Update dependencies under the publish-age cooldown (UPDATE_ARGS="-p foo") + rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ + cargo +$(RESOLVER_TOOLCHAIN) update -Z min-publish-age $(UPDATE_ARGS) + +# Escape hatch for an urgent update to a version younger than the cooldown, +# e.g. `make update-allow PACKAGE=h2 VERSION=0.4.16`. The bypass applies to the +# WHOLE resolution of this invocation (transitive picks included), so review the +# resulting lockfile diff. +update-allow: ## ๐Ÿšจ Update one crate to a version younger than the cooldown (PACKAGE=... VERSION=...) + @test -n "$(PACKAGE)" -a -n "$(VERSION)" || { echo "usage: make update-allow PACKAGE= VERSION=" >&2; exit 1; } + rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ + CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow \ + cargo +$(RESOLVER_TOOLCHAIN) update -Z min-publish-age -p $(PACKAGE) --precise $(VERSION) + +# Stable cargo ignores the cooldown, so the lockfile can pin too-young crates +# (or deliberately via `update-allow`); surface them without touching the file. +cooldown-check: ## ๐Ÿ”Ž Warn about lockfile entries younger than the publish-age cooldown + @rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ + if ! out=$$(cargo +$(RESOLVER_TOOLCHAIN) update --dry-run -Z min-publish-age 2>&1); then \ + echo "WARNING: publish-age cooldown probe failed:"; echo "$$out" | grep -v "^ *Updating " | head -20; exit 0; \ + fi; \ + hits=$$(echo "$$out" | grep -E "Downgrading|is too new" || true); \ + if [ -n "$$hits" ]; then echo "WARNING: lockfile pins crates younger than the publish-age cooldown:"; echo "$$hits"; fi BENCH_ARGS ?= synthetic --mock-crypto From 62bcc5a09969c689b6e89b6d12af3d6ebed8e66a Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Fri, 4 Sep 2026 16:48:33 -0300 Subject: [PATCH 2/3] Make the dependency cooldown check fail the build and drop the update-allow target Review follow-up. An advisory annotation nobody has to act on does not protect anything, so the CI cooldown job now exits non-zero when a lockfile pins a crate younger than the window, and covers tooling/event-monitor's lockfile as well as the root one. Toolchain download failures and resolutions that fail for reasons unrelated to age (today: yanked chacha20 releases upstream) still only warn, since they are outside the PR's control and would block every PR. The grep is narrowed to `Downgrading .*published`: a cooldown-driven downgrade carries the too-young version's publish date, while downgrades for other reasons (MSRV, a tightened requirement; the event-monitor lockfile shows several) do not, and a bare `Downgrading` match would have failed the build on those. `make update-allow` is removed; the escape hatch is the plain cargo env var on the existing target, `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow make update UPDATE_ARGS="-p --precise "`, and the docs say the cooldown job stays red until that version ages past the window. Two explanatory comments above `make lint` and the CI `cargo check` step are dropped, the benchmark smoke step builds `--locked` like everything else, and rustup's stderr is no longer swallowed so a failed toolchain install is visible. --- .github/workflows/ci.yml | 46 +++++++++++++++++++++++----------------- CLAUDE.md | 4 ++-- CONTRIBUTING.md | 6 ++++-- Makefile | 45 +++++++++++++++++---------------------- 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be03cf89..bba605cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,9 +43,6 @@ jobs: - name: Check formatting run: cargo fmt --all -- --check - # `--locked` so the committed Cargo.lock is actually enforced (see the - # tooling steps below), and so a dependency bump cannot sneak past the - # publish-age cooldown in .cargo/config.toml by resolving on stable here. - name: Cargo check run: cargo check --locked --workspace --all-targets @@ -83,34 +80,45 @@ jobs: # harness end-to-end and its JSON output contract in a few seconds. - name: Benchmark smoke (mock crypto) run: | - cargo run --profile release-fast --bin ethlambda -- benchmark synthetic --mock-crypto \ + cargo run --locked --profile release-fast --bin ethlambda -- benchmark synthetic --mock-crypto \ --num-validators 4 --warmup-slots 4 --iterations 3 --format json \ | jq -e '.schema_version == 1 and (.samples | length == 3)' # Stable cargo ignores the publish-age cooldown in .cargo/config.toml, so the - # lockfile can pin too-young crates (or deliberately via `make update-allow`). - # Surface them as annotations; this job never fails the build. + # lockfile can pin too-young crates (or deliberately via the + # CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow escape hatch). Fail the build + # when either lockfile does. Infrastructure failures (toolchain download, a + # resolution that fails for reasons unrelated to age, e.g. a yanked upstream + # crate) only warn: they are outside the PR's control and would block every PR. cooldown: name: Dependency cooldown runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - name: Check lockfile against the publish-age cooldown + - name: Check lockfiles against the publish-age cooldown run: | if ! rustup toolchain install nightly-2026-06-21 --profile minimal; then echo "::warning title=Publish-age cooldown check skipped::toolchain install failed" exit 0 fi - if ! cargo +nightly-2026-06-21 update --dry-run -Z min-publish-age > cooldown.txt 2>&1; then - # Drop the index/git refresh chatter so the excerpt is the actual error; %0A = newline in annotations - msg=$(grep -v '^ *Updating ' cooldown.txt | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') - echo "::warning title=Publish-age cooldown probe failed::$msg" - exit 0 - fi - hits=$(grep -E "Downgrading|is too new" cooldown.txt || true) - if [ -n "$hits" ]; then - count=$(echo "$hits" | wc -l) - msg=$(echo "$hits" | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') - echo "::warning title=Lockfile pins $count crate(s) younger than the publish-age cooldown::$msg" - fi + status=0 + for manifest in Cargo.toml tooling/event-monitor/Cargo.toml; do + if ! cargo +nightly-2026-06-21 update --dry-run -Z min-publish-age --manifest-path "$manifest" > cooldown.txt 2>&1; then + # Drop the index/git refresh chatter so the excerpt is the actual error; %0A = newline in annotations + msg=$(grep -v '^ *Updating ' cooldown.txt | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') + echo "::warning title=Publish-age cooldown probe failed for $manifest::$msg" + continue + fi + # A cooldown-driven downgrade is annotated with the too-young version's + # publish date; downgrades for other reasons (MSRV, a tightened + # requirement) carry no such note and are not this check's business. + hits=$(grep -E '^ *Downgrading .*published' cooldown.txt || true) + if [ -n "$hits" ]; then + count=$(echo "$hits" | wc -l | tr -d ' ') + msg=$(echo "$hits" | head -20 | sed ':a;N;$!ba;s/\n/%0A/g') + echo "::error title=$manifest pins $count crate(s) younger than the publish-age cooldown::$msg" + status=1 + fi + done + exit $status diff --git a/CLAUDE.md b/CLAUDE.md index c04b7cc3..1b7d3b60 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,8 +91,8 @@ make test # All tests + forkchoice spec tests ```bash rm -rf leanSpec && make leanSpec/fixtures # Download latest released test fixtures make update UPDATE_ARGS="-p " # Bump deps under the 14-day publish-age cooldown (nightly resolver) -make update-allow PACKAGE= VERSION= # Escape hatch for a version younger than the cooldown -make cooldown-check # Warn about lockfile entries younger than the cooldown +CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow make update UPDATE_ARGS="-p --precise " # Escape hatch; CI stays red until it ages +make cooldown-check # Fail if a lockfile pins crates younger than the cooldown (same as CI) make docker-build # Build Docker image (DOCKER_TAG=local) make run-devnet # Run local devnet with lean-quickstart ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be6db77d..b3715dc1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,8 +101,10 @@ All commits must have a verified signature. freshly published crate versions as a supply-chain precaution. A plain `cargo update` or `cargo add` on stable bypasses the cooldown; `make lint`/`make test` and CI build `--locked` so an unresolved manifest change fails loudly instead of silently re-resolving. - For an urgent fix younger than the cooldown use `make update-allow PACKAGE= VERSION=` - and review the whole lockfile diff. Git dependencies have no publish age and are not covered. + For an urgent fix younger than the cooldown, prefix the same command with + `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow` and review the whole lockfile diff; CI's + `Dependency cooldown` job will stay red until that version ages past the window. + Git dependencies have no publish age and are not covered. ### Review Process diff --git a/Makefile b/Makefile index e93eae44..3cfb3572 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help fmt lint bench update update-allow cooldown-check docker-build shadow-build shadow-docker-build run-devnet test docs docs-deps docs-serve +.PHONY: help fmt lint bench update cooldown-check docker-build shadow-build shadow-docker-build run-devnet test docs docs-deps docs-serve help: ## ๐Ÿ“š Show help for each of the Makefile recipes @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -6,9 +6,6 @@ help: ## ๐Ÿ“š Show help for each of the Makefile recipes fmt: ## ๐ŸŽจ Format all code using rustfmt cargo fmt --all -# `--locked` so the committed Cargo.lock is actually enforced: without it cargo -# silently resolves and rewrites the lockfile, bypassing the publish-age cooldown -# (see `update` below). lint: ## ๐Ÿ” Run clippy on all workspace crates cargo clippy --locked --workspace --all-targets -- -D warnings @@ -26,30 +23,28 @@ RESOLVER_TOOLCHAIN := nightly-2026-06-21 # Resolution done on stable (`cargo add`, plain `cargo update`) is NOT covered; # this target is the intended path for routine updates. Git dependencies have # no publish age and are refreshed WITHOUT any cooldown: review their lockfile -# rev changes manually. +# rev changes manually. Escape hatch for an urgent bump to a version younger +# than the cooldown, applied to the WHOLE resolution of that invocation: +# CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow make update UPDATE_ARGS="-p h2 --precise 0.4.16" update: ## ๐Ÿ“ฆ Update dependencies under the publish-age cooldown (UPDATE_ARGS="-p foo") - rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ + rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null && \ cargo +$(RESOLVER_TOOLCHAIN) update -Z min-publish-age $(UPDATE_ARGS) -# Escape hatch for an urgent update to a version younger than the cooldown, -# e.g. `make update-allow PACKAGE=h2 VERSION=0.4.16`. The bypass applies to the -# WHOLE resolution of this invocation (transitive picks included), so review the -# resulting lockfile diff. -update-allow: ## ๐Ÿšจ Update one crate to a version younger than the cooldown (PACKAGE=... VERSION=...) - @test -n "$(PACKAGE)" -a -n "$(VERSION)" || { echo "usage: make update-allow PACKAGE= VERSION=" >&2; exit 1; } - rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ - CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow \ - cargo +$(RESOLVER_TOOLCHAIN) update -Z min-publish-age -p $(PACKAGE) --precise $(VERSION) - -# Stable cargo ignores the cooldown, so the lockfile can pin too-young crates -# (or deliberately via `update-allow`); surface them without touching the file. -cooldown-check: ## ๐Ÿ”Ž Warn about lockfile entries younger than the publish-age cooldown - @rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null 2>&1 && \ - if ! out=$$(cargo +$(RESOLVER_TOOLCHAIN) update --dry-run -Z min-publish-age 2>&1); then \ - echo "WARNING: publish-age cooldown probe failed:"; echo "$$out" | grep -v "^ *Updating " | head -20; exit 0; \ - fi; \ - hits=$$(echo "$$out" | grep -E "Downgrading|is too new" || true); \ - if [ -n "$$hits" ]; then echo "WARNING: lockfile pins crates younger than the publish-age cooldown:"; echo "$$hits"; fi +# Stable cargo ignores the cooldown, so a lockfile can pin too-young crates; +# same check as the CI `cooldown` job, without touching the files. A cooldown +# downgrade is annotated with the too-young version's publish date; downgrades +# for other reasons carry no such note and are not flagged. +cooldown-check: ## ๐Ÿ”Ž Fail if a lockfile pins crates younger than the publish-age cooldown + @rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null && \ + status=0; \ + for manifest in Cargo.toml tooling/event-monitor/Cargo.toml; do \ + if ! out=$$(cargo +$(RESOLVER_TOOLCHAIN) update --dry-run -Z min-publish-age --manifest-path $$manifest 2>&1); then \ + echo "WARNING: publish-age cooldown probe failed for $$manifest:"; echo "$$out" | grep -v "^ *Updating " | head -20; continue; \ + fi; \ + hits=$$(echo "$$out" | grep -E "^ *Downgrading .*published" || true); \ + if [ -n "$$hits" ]; then echo "ERROR: $$manifest pins crates younger than the publish-age cooldown:"; echo "$$hits"; status=1; fi; \ + done; \ + exit $$status BENCH_ARGS ?= synthetic --mock-crypto From 2d92e9e01f85e6da1e981f9081892bc5d6578c95 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Fri, 4 Sep 2026 17:54:48 -0300 Subject: [PATCH 3/3] Drop the documented cooldown escape hatch Review follow-up. With the CI cooldown job failing the build on a too-young pin, a bypass that resolves past the window only produces a lockfile CI will reject, so there is nothing to document: the env var is removed from CLAUDE.md, CONTRIBUTING.md, the Makefile comment and the CI job comment. --- .github/workflows/ci.yml | 9 ++++----- CLAUDE.md | 1 - CONTRIBUTING.md | 3 --- Makefile | 4 +--- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bba605cb..b3229101 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,11 +85,10 @@ jobs: | jq -e '.schema_version == 1 and (.samples | length == 3)' # Stable cargo ignores the publish-age cooldown in .cargo/config.toml, so the - # lockfile can pin too-young crates (or deliberately via the - # CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow escape hatch). Fail the build - # when either lockfile does. Infrastructure failures (toolchain download, a - # resolution that fails for reasons unrelated to age, e.g. a yanked upstream - # crate) only warn: they are outside the PR's control and would block every PR. + # lockfile can pin too-young crates. Fail the build when either lockfile does. + # Infrastructure failures (toolchain download, a resolution that fails for + # reasons unrelated to age, e.g. a yanked upstream crate) only warn: they are + # outside the PR's control and would block every PR. cooldown: name: Dependency cooldown runs-on: ubuntu-latest diff --git a/CLAUDE.md b/CLAUDE.md index 1b7d3b60..e8f22ae9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,7 +91,6 @@ make test # All tests + forkchoice spec tests ```bash rm -rf leanSpec && make leanSpec/fixtures # Download latest released test fixtures make update UPDATE_ARGS="-p " # Bump deps under the 14-day publish-age cooldown (nightly resolver) -CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow make update UPDATE_ARGS="-p --precise " # Escape hatch; CI stays red until it ages make cooldown-check # Fail if a lockfile pins crates younger than the cooldown (same as CI) make docker-build # Build Docker image (DOCKER_TAG=local) make run-devnet # Run local devnet with lean-quickstart diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3715dc1..3ca8c736 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,9 +101,6 @@ All commits must have a verified signature. freshly published crate versions as a supply-chain precaution. A plain `cargo update` or `cargo add` on stable bypasses the cooldown; `make lint`/`make test` and CI build `--locked` so an unresolved manifest change fails loudly instead of silently re-resolving. - For an urgent fix younger than the cooldown, prefix the same command with - `CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow` and review the whole lockfile diff; CI's - `Dependency cooldown` job will stay red until that version ages past the window. Git dependencies have no publish age and are not covered. ### Review Process diff --git a/Makefile b/Makefile index 3cfb3572..a7836287 100644 --- a/Makefile +++ b/Makefile @@ -23,9 +23,7 @@ RESOLVER_TOOLCHAIN := nightly-2026-06-21 # Resolution done on stable (`cargo add`, plain `cargo update`) is NOT covered; # this target is the intended path for routine updates. Git dependencies have # no publish age and are refreshed WITHOUT any cooldown: review their lockfile -# rev changes manually. Escape hatch for an urgent bump to a version younger -# than the cooldown, applied to the WHOLE resolution of that invocation: -# CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow make update UPDATE_ARGS="-p h2 --precise 0.4.16" +# rev changes manually. update: ## ๐Ÿ“ฆ Update dependencies under the publish-age cooldown (UPDATE_ARGS="-p foo") rustup toolchain install $(RESOLVER_TOOLCHAIN) --profile minimal > /dev/null && \ cargo +$(RESOLVER_TOOLCHAIN) update -Z min-publish-age $(UPDATE_ARGS)