Skip to content

Commit a3ea0cc

Browse files
committed
Adds cargo's min-publish-age policy
- uses nightly for cargo fmt / update - uses stable for builds - add --locked to our builds - add workflow to check for age violations
1 parent 26a62dd commit a3ea0cc

8 files changed

Lines changed: 86 additions & 25 deletions

File tree

‎.cargo/config.toml‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Supply-chain cooldown for dependency resolution (unstable min-publish-age,
2+
# tracking issue rust-lang/cargo#17009): crate versions published less than
3+
# 14 days ago are excluded when the resolver runs on a nightly cargo.
4+
# Stable cargo ignores these tables silently, so builds from the committed
5+
# Cargo.lock are unaffected; run `just update` to resolve under the policy.
6+
# When the feature stabilizes, drop the [unstable] table and the nightly
7+
# resolver pin in the justfile: the policy then binds all resolution.
8+
# The fmt nightly (older than the feature) prints an unused-key warning
9+
# for these tables; harmless.
10+
[unstable]
11+
min-publish-age = true
12+
13+
[registry]
14+
global-min-publish-age = "14 days"

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ jobs:
2424
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
2525

2626
- name: Install Rust toolchain
27-
uses: dtolnay/rust-toolchain@master
27+
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
2828
with:
2929
toolchain: nightly-2026-01-01
30-
components: clippy, rustfmt
30+
components: rustfmt
3131

3232
- name: Install protoc
3333
run: sudo provisioning/protoc.sh
@@ -41,7 +41,7 @@ jobs:
4141
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
4242

4343
- name: Check compilation
44-
run: cargo check
44+
run: cargo check --locked
4545

4646
- name: Check formatting
4747
run: just fmt-check

‎.github/workflows/release.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ jobs:
207207
${{ runner.os }}-cargo-build-
208208
209209
- name: Build binary (Darwin)
210-
run: cargo build --release --target ${{ matrix.target }} --bin ${{ matrix.name }}
210+
run: cargo build --locked --release --target ${{ matrix.target }} --bin ${{ matrix.name }}
211211

212212
- name: Package binary (Darwin)
213213
run: |

‎.github/workflows/security-audit.yml‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,21 @@ jobs:
2222
- uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2.83.2
2323
with:
2424
tool: cargo-audit
25-
- run: cargo audit
25+
- run: cargo audit
26+
# Stable cargo ignores the publish-age policy, so the lockfile can pin
27+
# too-young crates (or deliberately via `just update-allow`); surface them.
28+
- name: Check lockfile against the publish-age cooldown
29+
continue-on-error: true
30+
run: |
31+
rustup toolchain install nightly-2026-06-21 --profile minimal
32+
if ! cargo +nightly-2026-06-21 update --dry-run -Z min-publish-age > cooldown.txt 2>&1; then
33+
msg=$(head -20 cooldown.txt | sed ':a;N;$!ba;s/\n/%0A/g') # %0A = newline in annotations
34+
echo "::warning title=Publish-age cooldown probe failed::$msg"
35+
exit 0
36+
fi
37+
hits=$(grep -E "Downgrading|is too new" cooldown.txt || true)
38+
if [ -n "$hits" ]; then
39+
count=$(echo "$hits" | wc -l)
40+
msg=$(echo "$hits" | head -20 | sed ':a;N;$!ba;s/\n/%0A/g')
41+
echo "::warning title=Lockfile pins $count crate(s) younger than the publish-age cooldown::$msg"
42+
fi

‎examples/da_commit/Dockerfile‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ RUN cargo chef prepare --recipe-path recipe.json
88
FROM chef AS builder
99
COPY --from=planner /app/recipe.json recipe.json
1010

11-
RUN cargo chef cook --release --recipe-path recipe.json
11+
RUN cargo chef cook --locked --release --recipe-path recipe.json
1212

1313
RUN apt-get update && apt-get install -y protobuf-compiler
1414

1515
COPY . .
16-
RUN cargo build --release --bin da_commit
16+
RUN cargo build --locked --release --bin da_commit
1717

1818

1919
FROM ubuntu AS runtime

‎examples/status_api/Dockerfile‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ RUN cargo chef prepare --recipe-path recipe.json
88
FROM chef AS builder
99
COPY --from=planner /app/recipe.json recipe.json
1010

11-
RUN cargo chef cook --release --recipe-path recipe.json
11+
RUN cargo chef cook --locked --release --recipe-path recipe.json
1212

1313
RUN apt-get update && apt-get install -y protobuf-compiler
1414

1515
COPY . .
16-
RUN cargo build --release --bin status_api
16+
RUN cargo build --locked --release --bin status_api
1717

1818

1919
FROM ubuntu AS runtime

‎justfile‎

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,53 @@
1-
toolchain := "nightly-2026-01-01"
1+
# Used ONLY by fmt/fmt-check: rustfmt.toml relies on nightly-only options.
2+
# check/clippy/test run on stable via rust-toolchain.toml, so lints always
3+
# match the shipped compiler.
4+
fmt_toolchain := "nightly-2026-01-01"
5+
6+
# Used ONLY to resolve dependency updates: min-publish-age needs a newer
7+
# nightly than the fmt pin above.
8+
resolver_toolchain := "nightly-2026-06-21"
9+
10+
[doc("""
11+
Update dependencies under the publish-age cooldown (.cargo/config.toml):
12+
versions published less than 14 days ago are excluded from resolution.
13+
Resolution done on stable (cargo add, plain cargo update) is NOT covered;
14+
this recipe is the intended path for routine updates. Git dependencies
15+
have no publish age and are refreshed WITHOUT any cooldown: review their
16+
lockfile rev changes manually.
17+
""")]
18+
update *args:
19+
rustup toolchain install {{resolver_toolchain}} > /dev/null 2>&1 && cargo +{{resolver_toolchain}} update -Z min-publish-age {{args}}
20+
21+
[doc("""
22+
Escape hatch for an urgent update to a version younger than the cooldown,
23+
e.g. `just update-allow h2 0.4.16`. The bypass applies to the WHOLE
24+
resolution of this invocation (transitive picks included), so review the
25+
full Cargo.lock diff, not just the target package.
26+
""")]
27+
update-allow package version:
28+
@echo "NOTE: the cooldown bypass is invocation-global; review the full Cargo.lock diff.
29+
rustup toolchain install {{resolver_toolchain}} > /dev/null 2>&1 && CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow cargo +{{resolver_toolchain}} update -Z min-publish-age -p {{package}} --precise {{version}}
230
331
fmt:
4-
rustup toolchain install {{toolchain}} > /dev/null 2>&1 && \
5-
cargo +{{toolchain}} fmt
32+
rustup toolchain install {{fmt_toolchain}} > /dev/null 2>&1 && \
33+
cargo +{{fmt_toolchain}} fmt
634
735
fmt-check:
8-
rustup toolchain install {{toolchain}} > /dev/null 2>&1 && \
9-
cargo +{{toolchain}} fmt --check
36+
rustup toolchain install {{fmt_toolchain}} > /dev/null 2>&1 && \
37+
cargo +{{fmt_toolchain}} fmt --check
1038
1139
clippy:
12-
cargo +{{toolchain}} clippy --all-features --no-deps -- -D warnings
40+
cargo clippy --locked --all-features --no-deps -- -D warnings
1341
1442
# Everything needed to run before pushing
1543
checklist:
16-
cargo check
44+
cargo check --locked || (echo "Cargo.lock out of date: resolve with 'just update' (publish-age cooldown), not plain cargo update" && exit 1)
1745
just fmt
1846
just clippy
1947
just test
2048
cargo audit
49+
@out=$(cargo +{{resolver_toolchain}} update --dry-run -Z min-publish-age 2>&1 | grep -E "Downgrading|is too new" || true); \
50+
if [ -n "$out" ]; then echo "WARNING: lockfile pins crates younger than the publish-age cooldown:"; echo "$out"; fi
2151
2252
# ===================================
2353
# === Build Commands for Services ===
@@ -99,7 +129,7 @@ clean:
99129
100130
# Runs the suite of tests for all commit-boost crates.
101131
test:
102-
cargo test --all-features
132+
cargo test --locked --all-features
103133
104134
# =====================
105135
# === Test Coverage ===
@@ -112,11 +142,11 @@ test:
112142
# If results look wrong after upgrading cargo-llvm-cov, run `just coverage-clean` first.
113143
# Requires: cargo install cargo-llvm-cov && rustup component add llvm-tools-preview
114144
coverage:
115-
cargo llvm-cov --all-features --html --open
145+
cargo llvm-cov --locked --all-features --html --open
116146
117147
# Print a quick coverage summary to the terminal without opening a browser.
118148
coverage-summary:
119-
cargo llvm-cov --all-features --summary-only
149+
cargo llvm-cov --locked --all-features --summary-only
120150
121151
# Remove all coverage instrumentation artifacts produced by cargo-llvm-cov.
122152
coverage-clean:
@@ -141,7 +171,7 @@ coverage-clean:
141171
- critcmp: baseline diffing tool used by bench-compare
142172
""")]
143173
bench-install-tools:
144-
cargo install cargo-criterion critcmp
174+
cargo install --locked cargo-criterion critcmp
145175
146176
[doc("""
147177
Run microbenchmarks and save results as a named baseline. Example: just bench main
@@ -151,14 +181,14 @@ bench-install-tools:
151181
For accurate baseline comparisons, use bench-compare instead.
152182
""")]
153183
bench baseline:
154-
cargo bench --package cb-bench-micro -- --save-baseline {{baseline}}
184+
cargo bench --locked --package cb-bench-micro -- --save-baseline {{baseline}}
155185
156186
[doc("""
157187
Run microbenchmarks, save results as "current", then diff against a named baseline.
158188
Example: just bench-compare main
159189
""")]
160190
bench-compare baseline:
161-
cargo bench --package cb-bench-micro -- --save-baseline current
191+
cargo bench --locked --package cb-bench-micro -- --save-baseline current
162192
critcmp {{baseline}} current
163193
164194
# =================

‎provisioning/build.Dockerfile‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM --platform=${BUILDPLATFORM} rust:1.91-slim-bookworm AS chef
33
ARG TARGETOS TARGETARCH BUILDPLATFORM TARGET_CRATE
44
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
55
WORKDIR /app
6-
RUN cargo install cargo-chef --locked && \
6+
RUN cargo install cargo-chef --version 0.1.78 --locked && \
77
rm -rf $CARGO_HOME/registry/
88

99
FROM --platform=${BUILDPLATFORM} chef AS planner
@@ -60,7 +60,7 @@ RUN if [ -f ${BUILD_VAR_SCRIPT} ]; then \
6060
fi && \
6161
apt update && \
6262
apt install -y git make libssl-dev:${TARGETARCH} zlib1g-dev:${TARGETARCH} pkg-config && \
63-
cargo chef cook ${TARGET_FLAG} --release --recipe-path recipe.json
63+
cargo chef cook --locked ${TARGET_FLAG} --release --recipe-path recipe.json
6464

6565
# Get the latest Protoc since the one in the Debian repo is incredibly old
6666
COPY provisioning/protoc.sh provisioning/protoc.sh
@@ -79,7 +79,7 @@ RUN if [ -f ${BUILD_VAR_SCRIPT} ]; then \
7979
echo "No cross-compilation needed"; \
8080
fi && \
8181
export GIT_HASH=$(git rev-parse HEAD) && \
82-
cargo build ${TARGET_FLAG} --release --bin ${TARGET_CRATE} && \
82+
cargo build --locked ${TARGET_FLAG} --release --bin ${TARGET_CRATE} && \
8383
if [ ! -z "$TARGET" ]; then \
8484
# If we're cross-compiling, we need to move the binary out of the target dir
8585
mv target/${TARGET}/release/${TARGET_CRATE} target/release/${TARGET_CRATE}; \

0 commit comments

Comments
 (0)