From f92c62e9ccccd68cef67582e66aa6890c07ae0be Mon Sep 17 00:00:00 2001 From: Travis Bischel Date: Tue, 20 Oct 2026 19:32:05 -0600 Subject: [PATCH 1/5] ci: fail when a deny.toml advisory ignore outlives its reason #9985 ignored four rustls advisories until the fix was 48 hours old, as ci/check_dependency_age.py requires. Nothing brought us back once the fix was old enough, and rustls stayed on the vulnerable 0.23.45 for a week, until #10193. Every advisory ignore's reason now starts with `expires YYYY-MM-DD:` or `no fix:`. ci/check_advisory_ignores.py runs in the cargo-deny job and fails on a reason without a marker, a malformed date, or an expires day (UTC) that has passed. deny.toml also sets unused-ignored-advisory = "deny", so cargo-deny fails on an ignore that no longer matches a crate. The existing reasons are rewritten from the advisories and Cargo.lock. The quick-xml one was stale: object_store and opendal are on 0.41 now, and what remains is lance-namespace-impls asking for 0.40 and pprof's inferno pulling in 0.26. The RUSTSEC-2026-0381 and 0382 ignores match nothing now, so they are removed: #10215 moved rustls-webpki to the fixed 0.103.16, and the advisory lists webpki-roots 0.26.11, which only re-exports 1.x, as unaffected. Co-authored-by: Claude Opus 5.5 (1M context) --- .github/workflows/ci-scripts.yml | 4 +- .github/workflows/rust.yml | 7 ++ ci/check_advisory_ignores.py | 122 ++++++++++++++++++++++++ ci/test_check_advisory_ignores.py | 150 ++++++++++++++++++++++++++++++ deny.toml | 23 +++-- 5 files changed, 297 insertions(+), 9 deletions(-) create mode 100644 ci/check_advisory_ignores.py create mode 100644 ci/test_check_advisory_ignores.py diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml index d4171960d1b..951418133d9 100644 --- a/.github/workflows/ci-scripts.yml +++ b/.github/workflows/ci-scripts.yml @@ -21,6 +21,8 @@ on: - ci/test_check_proto_comments.py - ci/check_dependency_age.py - ci/test_check_dependency_age.py + - ci/check_advisory_ignores.py + - ci/test_check_advisory_ignores.py - ci/arrow_upgrade.py - ci/test_arrow_upgrade.py - ci/check_module_size.py @@ -46,4 +48,4 @@ jobs: - name: Install test dependencies run: pip install pytest PyYAML - name: Run tests - run: pytest ci/test_format_vote_gate.py ci/test_labeler_area.py ci/test_check_proto_comments.py ci/test_check_dependency_age.py ci/test_arrow_upgrade.py ci/test_check_module_size.py + run: pytest ci/test_format_vote_gate.py ci/test_labeler_area.py ci/test_check_proto_comments.py ci/test_check_dependency_age.py ci/test_check_advisory_ignores.py ci/test_arrow_upgrade.py ci/test_check_module_size.py diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 15809d59144..f154a773188 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -21,6 +21,7 @@ on: - clippy.toml - deny.toml - ci/check_dependency_age.py + - ci/check_advisory_ignores.py - ci/arrow_upgrade.py permissions: @@ -117,6 +118,12 @@ jobs: # fetched. The script falls back to the network when that misses. - name: Check dependency age run: python3 ci/check_dependency_age.py + # Fails if an ignore in deny.toml has no `expires` or `no fix` marker, or + # its expires date has passed. It runs even if a step above failed, so + # one CI run reports every problem. + - name: Check advisory ignores + if: ${{ !cancelled() }} + run: python3 ci/check_advisory_ignores.py arrow-ordering-detect: # Lance inherits its comparison semantics from Arrow, DataFusion and `half`. diff --git a/ci/check_advisory_ignores.py b/ci/check_advisory_ignores.py new file mode 100644 index 00000000000..306c3ef268c --- /dev/null +++ b/ci/check_advisory_ignores.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +"""Fail if an advisory ignore in deny.toml has outlived its reason. + +We ignore a RustSec advisory when its fix cannot land yet, most often because +the fixed version is younger than the 48 hours ci/check_dependency_age.py +requires. Nothing used to bring us back once the fix could land: #9985 ignored +four rustls advisories until the fix was 48 hours old, and rustls then stayed +on the vulnerable version for a week. So every ignore's `reason` must start +with one of two markers: + + expires YYYY-MM-DD: the ignore should be gone after this day (UTC) + no fix: there is nothing to upgrade to + +Once an `expires` day has passed, this check fails until someone upgrades the +crate and removes the ignore, or moves the date and says why it still holds. +An ignore that no longer matches any crate fails cargo-deny itself, through +`unused-ignored-advisory = "deny"`. +""" + +import argparse +import re +import sys +import tomllib +from datetime import date, datetime, timezone +from pathlib import Path + +DEFAULT_CONFIG = "deny.toml" +NO_FIX = "no fix:" +EXPIRES = re.compile(r"expires ([^:]*):") +# date.fromisoformat also takes forms like 20261029, so pin the layout first. +DATE = re.compile(r"\d{4}-\d{2}-\d{2}") +RUSTSEC_ID = re.compile(r"RUSTSEC-\d{4}-\d{4}") + + +def parse_date(text): + if DATE.fullmatch(text): + try: + return date.fromisoformat(text) + except ValueError: + pass + raise ValueError(f"has `{text}` where a YYYY-MM-DD date belongs") + + +def parse_reason(reason): + """Return the day an ignore expires, or None for an ignore with no fix. + + Raises ValueError, saying what is wrong, if the reason has no marker, has a + malformed date, or says nothing after its marker. + """ + if not reason.strip(): + raise ValueError("has no reason") + if reason.startswith(NO_FIX): + expires, why = None, reason[len(NO_FIX) :] + else: + match = EXPIRES.match(reason) + if match is None: + raise ValueError( + f"has a reason that does not start with `expires YYYY-MM-DD:` or `{NO_FIX}`" + ) + expires, why = parse_date(match[1]), reason[match.end() :] + if not why.strip(): + raise ValueError("has a reason that says nothing after its marker") + return expires + + +def load_ignores(path): + config = tomllib.loads(Path(path).read_text()) + return config.get("advisories", {}).get("ignore", []) + + +def check_config(path, today): + """Print every ignore in a cargo-deny config and return whether all are valid.""" + passed = True + for entry in load_ignores(path): + # A bare string is an advisory id or crate spec with no reason at all. + if isinstance(entry, str): + entry = {"id": entry} + name = entry.get("id") or entry.get("crate") or str(entry) + reason = entry.get("reason", "") + try: + expires = parse_reason(reason) + except ValueError as error: + problem = str(error) + else: + if expires is None or expires >= today: + print(f"{path} ignores {name}: {reason}") + continue + problem = "has expired" + passed = False + print(f"{path}: {name} {problem}") + if reason: + print(f" reason: {reason}") + if RUSTSEC_ID.fullmatch(name): + print(f" advisory: https://rustsec.org/advisories/{name}") + return passed + + +def main(argv=None): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("config", nargs="?", default=DEFAULT_CONFIG) + args = parser.parse_args(argv) + + if check_config(args.config, datetime.now(timezone.utc).date()): + return 0 + + # Keep the findings above the advice when CI interleaves the two streams. + sys.stdout.flush() + print( + "\nEvery [advisories] ignore needs a reason that starts with " + "`expires YYYY-MM-DD:` or `no fix:`. Use `expires` about a week out " + "for a fix that cannot land yet, and `no fix` when there is nothing to " + "upgrade to. Once an ignore expires, upgrade the crate and remove the " + "ignore, or move the date and say why it still holds. To see the fixed " + "versions and what pulls in the affected crate, remove the ignore and " + "run `cargo deny check advisories`, or read the advisory.", + file=sys.stderr, + ) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ci/test_check_advisory_ignores.py b/ci/test_check_advisory_ignores.py new file mode 100644 index 00000000000..8d1b8202a45 --- /dev/null +++ b/ci/test_check_advisory_ignores.py @@ -0,0 +1,150 @@ +"""Unit tests for the deny.toml advisory ignore check. + +Run with: pytest ci/test_check_advisory_ignores.py +""" + +from datetime import date + +import pytest + +from check_advisory_ignores import check_config, main, parse_reason + +TODAY = date(2026, 10, 21) + + +def deny_toml(tmp_path, entries): + """Write a deny.toml ignoring `entries`, or with no [advisories] if None.""" + path = tmp_path / "deny.toml" + if entries is None: + lines = ["[bans]", 'multiple-versions = "warn"'] + else: + lines = ["[advisories]", "ignore = ["] + lines += [f" {entry}," for entry in entries] + lines.append("]") + path.write_text("\n".join(lines) + "\n") + return path + + +@pytest.mark.parametrize( + ("reason", "expected"), + [ + pytest.param("no fix: unmaintained", None, id="no_fix"), + pytest.param("expires 2026-10-29: too young", date(2026, 10, 29), id="expires"), + pytest.param("expires 2026-10-29: a: b", date(2026, 10, 29), id="colon_in_why"), + ], +) +def test_parse_reason_accepts_a_marker(reason, expected): + assert parse_reason(reason) == expected + + +@pytest.mark.parametrize( + ("reason", "problem"), + [ + pytest.param("", "has no reason", id="empty"), + pytest.param("until 48 hours old", "does not start with", id="no_marker"), + pytest.param("No fix: unmaintained", "does not start with", id="marker_case"), + pytest.param("expires: 2026-10-29", "does not start with", id="colon_first"), + pytest.param("expires 2026-13-01: x", "`2026-13-01`", id="month_13"), + pytest.param("expires 2026-10-1: x", "`2026-10-1`", id="short_day"), + pytest.param("expires 20261029: x", "`20261029`", id="basic_iso"), + pytest.param("expires next week: x", "`next week`", id="words"), + pytest.param("expires 2026-10-29 x: y", "`2026-10-29 x`", id="text_in_date"), + pytest.param("no fix:", "says nothing after", id="no_fix_without_why"), + pytest.param("expires 2026-10-29: ", "says nothing", id="expires_without_why"), + ], +) +def test_parse_reason_rejects(reason, problem): + with pytest.raises(ValueError, match=problem): + parse_reason(reason) + + +@pytest.mark.parametrize( + ("entries", "passes", "printed"), + [ + pytest.param( + ['{ id = "RUSTSEC-2026-0001", reason = "expires 2026-10-28: young" }'], + True, + ["ignores RUSTSEC-2026-0001: expires 2026-10-28: young"], + id="expires_later", + ), + pytest.param( + ['{ id = "RUSTSEC-2026-0001", reason = "expires 2026-10-21: young" }'], + True, + ["ignores RUSTSEC-2026-0001"], + id="expires_today", + ), + pytest.param( + ['{ id = "RUSTSEC-2026-0001", reason = "expires 2026-10-20: young" }'], + False, + [ + "RUSTSEC-2026-0001 has expired\n", + "reason: expires 2026-10-20: young\n", + "advisory: https://rustsec.org/advisories/RUSTSEC-2026-0001\n", + ], + id="expired_yesterday", + ), + pytest.param( + ['{ id = "RUSTSEC-2026-0001", reason = "no fix: unmaintained" }'], + True, + ["ignores RUSTSEC-2026-0001: no fix: unmaintained"], + id="no_fix", + ), + pytest.param( + ['"RUSTSEC-2026-0001"'], + False, + ["RUSTSEC-2026-0001 has no reason"], + id="bare_id", + ), + pytest.param( + ['{ id = "RUSTSEC-2026-0001" }'], + False, + ["RUSTSEC-2026-0001 has no reason"], + id="no_reason", + ), + pytest.param( + ['{ crate = "demo@0.1.0", reason = "yanked upstream" }'], + False, + ["demo@0.1.0 has a reason that does not start with"], + id="yanked_crate", + ), + pytest.param( + [ + '{ id = "RUSTSEC-2026-0001", reason = "no fix: unmaintained" }', + '{ id = "RUSTSEC-2026-0002", reason = "until 48 hours old" }', + '{ id = "RUSTSEC-2026-0003", reason = "expires 2026-10-01: young" }', + ], + False, + [ + "ignores RUSTSEC-2026-0001", + "RUSTSEC-2026-0002 has a reason that does not start with", + "RUSTSEC-2026-0003 has expired", + ], + id="reports_every_entry", + ), + pytest.param([], True, [], id="no_ignores"), + pytest.param(None, True, [], id="no_advisories_table"), + ], +) +def test_check_config(tmp_path, capsys, entries, passes, printed): + assert check_config(deny_toml(tmp_path, entries), TODAY) is passes + out = capsys.readouterr().out + for line in printed: + assert line in out + + +@pytest.mark.parametrize( + ("reason", "code"), + [ + pytest.param("expires 2999-01-01: young", 0, id="future"), + pytest.param("expires 2000-01-01: young", 1, id="past"), + ], +) +def test_main_tells_how_to_fix_a_failure(tmp_path, capsys, reason, code): + path = deny_toml(tmp_path, [f'{{ id = "RUSTSEC-2026-0001", reason = "{reason}" }}']) + assert main([str(path)]) == code + err = capsys.readouterr().err + if code: + assert "remove the ignore, or move the date" in err + assert "cargo deny check advisories" in err + else: + assert err == "" diff --git a/deny.toml b/deny.toml index 80208a66806..594cc7a9d70 100644 --- a/deny.toml +++ b/deny.toml @@ -75,20 +75,27 @@ feature-depth = 1 #db-urls = ["https://github.com/rustsec/advisory-db"] # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. +# +# Each reason must start with `expires YYYY-MM-DD:` or `no fix:`, and +# ci/check_advisory_ignores.py fails CI once an expires day (UTC) has passed. +# Use expires about a week out for a fix that cannot land yet, such as one +# younger than the 48 hours ci/check_dependency_age.py requires. Use no fix +# when there is nothing to upgrade to. ignore = [ #"RUSTSEC-0000-0000", #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, - { id = "RUSTSEC-2024-0436", reason = "`paste` is used by datafusion" }, - { id = "RUSTSEC-2023-0071", reason = "`rsa` is used by opendal via reqsign" }, - { id = "RUSTSEC-2025-0119", reason = "`number_prefix` used by hf-hub in examples" }, - { id = "RUSTSEC-2026-0194", reason = "`quick-xml` <0.41 pulled transitively via object_store (datafusion) and reqsign-aws-v4 (opendal); upstream must upgrade first" }, - { id = "RUSTSEC-2026-0195", reason = "`quick-xml` <0.41 pulled transitively via object_store (datafusion) and reqsign-aws-v4 (opendal); upstream must upgrade first" }, - { id = "RUSTSEC-2024-0449", reason = "`serde_yaml` pulled transitively via datafusion-substrait; serde features not utilized by us" }, - { id = "RUSTSEC-2026-0381", reason = "fixed `webpki-roots` 1.0.10 is under 48 hours old, cannot upgrade due to our release age policy; 0.26.11 comes from hf-hub 0.4 in examples and only re-exports 1.x" }, - { id = "RUSTSEC-2026-0382", reason = "fixed `rustls-webpki` 0.103.16 is under 48 hours old, cannot upgrade due to our release age policy" }, + { id = "RUSTSEC-2024-0436", reason = "no fix: `paste` is unmaintained with no patched release; lance-bitpacking and foyer-memory (latest 0.22.6) depend on it" }, + { id = "RUSTSEC-2023-0071", reason = "no fix: no `rsa` release fixes the Marvin timing side channel; opendal's reqsign crates depend on it" }, + { id = "RUSTSEC-2025-0119", reason = "expires 2027-01-20: `number_prefix` is unmaintained; indicatif 0.17 pulls it in via hf-hub 0.4 and tokenizers 0.15 in rust/examples, and moving those to hf-hub 0.5+ and tokenizers 0.22.2+ (indicatif 0.18) drops it" }, + { id = "RUSTSEC-2026-0194", reason = "expires 2027-01-20: fixed in `quick-xml` 0.41; lance-namespace-impls still asks for 0.40, and pprof 0.15 (tests only) pulls in 0.26 via inferno 0.11, so recheck for a pprof release on inferno 0.12.7+" }, + { id = "RUSTSEC-2026-0195", reason = "expires 2027-01-20: fixed in `quick-xml` 0.41; lance-namespace-impls still asks for 0.40, and pprof 0.15 (tests only) pulls in 0.26 via inferno 0.11, so recheck for a pprof release on inferno 0.12.7+" }, + { id = "RUSTSEC-2024-0449", reason = "no fix: `unsafe-libyaml` is unmaintained; serde_yaml pulls it in for substrait 0.63, which datafusion-substrait (latest 55.2) still requires, and serde_yaml_ng for lindera 3" }, ] +# Fail when an ignored advisory no longer matches any crate, so an ignore is +# removed along with the upgrade that fixed it. +unused-ignored-advisory = "deny" # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. From fd486118218b71926556af400b2ac88439fb8b54 Mon Sep 17 00:00:00 2001 From: Travis Bischel Date: Tue, 20 Oct 2026 19:57:32 -0600 Subject: [PATCH 2/5] chore(deps): move rust/examples to hf-hub 0.5 and tokenizers 0.22 hf-hub 0.4 and tokenizers 0.15 pull in indicatif 0.17, which depends on the unmaintained number_prefix (RUSTSEC-2025-0119). hf-hub 0.4 also pulls in ureq 2, which gets its roots through the webpki-roots 0.26 shim. hf-hub 0.5.0 and tokenizers 0.22.2 are the smallest releases on indicatif 0.18, and hf-hub 0.5 moves to ureq 3, which depends on webpki-roots 1.x directly. Nothing matches the number_prefix ignore now, so it is removed. hf-hub's default features turn on native-tls for ureq and reqwest. The example only uses the sync API, so hf-hub now gets just its ureq feature. That drops native-tls and openssl from Cargo.lock. Co-authored-by: Claude Opus 5.5 (1M context) --- Cargo.lock | 398 +++++++++++++++------------------------ deny.toml | 1 - rust/examples/Cargo.toml | 4 +- 3 files changed, 150 insertions(+), 253 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 980cd76bf33..fe78f5183dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,7 @@ dependencies = [ "const-random", "getrandom 0.3.4", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -1337,6 +1338,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cbc" version = "0.1.2" @@ -1476,7 +1486,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] @@ -1547,6 +1557,21 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if 1.0.4", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + [[package]] name = "compression-codecs" version = "0.4.38" @@ -1582,10 +1607,21 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width", "windows-sys 0.59.0", ] +[[package]] +name = "console" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" +dependencies = [ + "encode_unicode", + "libc", + "unicode-width", + "windows-sys 0.61.2", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -1639,6 +1675,35 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap 2.14.0", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1897,16 +1962,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db756b5eb7d81d31f31f660f4132f8cf5698de52fca144c143d0ae0cbb5f2e06" -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core 0.14.4", - "darling_macro 0.14.4", -] - [[package]] name = "darling" version = "0.20.11" @@ -1927,20 +1982,6 @@ dependencies = [ "darling_macro 0.23.0", ] -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", -] - [[package]] name = "darling_core" version = "0.20.11" @@ -1951,7 +1992,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", + "strsim", "syn 2.0.119", ] @@ -1964,21 +2005,10 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", + "strsim", "syn 2.0.119", ] -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core 0.14.4", - "quote", - "syn 1.0.109", -] - [[package]] name = "darling_macro" version = "0.20.11" @@ -2001,6 +2031,15 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "dary_heap" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe" +dependencies = [ + "serde", +] + [[package]] name = "dashmap" version = "6.2.1" @@ -2695,34 +2734,13 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_builder" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" -dependencies = [ - "derive_builder_macro 0.12.0", -] - [[package]] name = "derive_builder" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ - "derive_builder_macro 0.20.2", -] - -[[package]] -name = "derive_builder_core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" -dependencies = [ - "darling 0.14.4", - "proc-macro2", - "quote", - "syn 1.0.109", + "derive_builder_macro", ] [[package]] @@ -2737,23 +2755,13 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "derive_builder_macro" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" -dependencies = [ - "derive_builder_core 0.12.0", - "syn 1.0.109", -] - [[package]] name = "derive_builder_macro" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ - "derive_builder_core 0.20.2", + "derive_builder_core", "syn 2.0.119", ] @@ -2828,6 +2836,15 @@ dependencies = [ "const-random", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "downcast" version = "0.11.0" @@ -3066,21 +3083,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -3704,26 +3706,21 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hf-hub" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97" +checksum = "aef3982638978efa195ff11b305f51f1f22f4f0a6cabee7af79b383ebee6a213" dependencies = [ "dirs", - "futures", "http 1.4.2", "indicatif", "libc", "log", - "native-tls", - "num_cpus", "rand 0.9.5", - "reqwest 0.12.28", "serde", "serde_json", "thiserror 2.0.18", - "tokio", "ureq", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3913,22 +3910,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -4209,14 +4190,14 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.11" +version = "0.18.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c" dependencies = [ - "console", - "number_prefix", + "console 0.16.6", "portable-atomic", "unicode-width", + "unit-prefix", "web-time", ] @@ -4297,15 +4278,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -5449,7 +5421,7 @@ dependencies = [ "byteorder", "csv", "daachorse", - "derive_builder 0.20.2", + "derive_builder", "encoding_rs", "encoding_rs_io", "glob", @@ -5490,6 +5462,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +[[package]] +name = "litrs" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4744e383959f0db86ede514b809b1c53251889093803c05267acc7d4e7030d70" + [[package]] name = "lock_api" version = "0.4.14" @@ -5873,23 +5851,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "ndarray" version = "0.16.1" @@ -6098,12 +6059,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - [[package]] name = "objc2-core-foundation" version = "0.3.2" @@ -6556,49 +6511,12 @@ dependencies = [ "serde_json", ] -[[package]] -name = "openssl" -version = "0.10.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" -dependencies = [ - "bitflags 2.13.0", - "cfg-if 1.0.4", - "foreign-types", - "libc", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-sys" -version = "0.9.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -7390,7 +7308,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -7539,12 +7456,12 @@ dependencies = [ [[package]] name = "rayon-cond" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059f538b55efd2309c9794130bc149c6a553db90e9d99c2030785c82f0bd7df9" +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" dependencies = [ "either", - "itertools 0.11.0", + "itertools 0.14.0", "rayon", ] @@ -7840,13 +7757,11 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", "mime", "mime_guess", - "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -7858,7 +7773,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -8695,7 +8609,7 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b441962c817e33508847a22bd82f03a30cff43642dc2fae8b050566121eb9a" dependencies = [ - "console", + "console 0.15.11", "similar", ] @@ -8884,12 +8798,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f446288b699d66d0fd2e30d1cfe7869194312524b3b9252594868ed26ef056a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -8978,17 +8886,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.119" @@ -9275,24 +9172,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokenizers" -version = "0.15.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd47962b0ba36e7fd33518fbf1754d136fd1474000162bbf2a8b5fcb2d3654d" +checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223" dependencies = [ + "ahash", "aho-corasick", - "clap", - "derive_builder 0.12.0", + "compact_str", + "dary_heap", + "derive_builder", "esaxx-rs", - "getrandom 0.2.17", + "getrandom 0.3.4", "indicatif", - "itertools 0.12.1", - "lazy_static", + "itertools 0.14.0", "log", "macro_rules_attribute", "monostate", "onig", "paste", - "rand 0.8.6", + "rand 0.9.5", "rayon", "rayon-cond", "regex", @@ -9300,7 +9198,7 @@ dependencies = [ "serde", "serde_json", "spm_precompiled", - "thiserror 1.0.69", + "thiserror 2.0.18", "unicode-normalization-alignments", "unicode-segmentation", "unicode_categories", @@ -9334,16 +9232,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-retry" version = "0.3.2" @@ -9812,6 +9700,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -9826,22 +9720,35 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.12.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ "base64 0.22.1", + "cookie_store", "flate2", "log", - "native-tls", - "once_cell", + "percent-encoding", "rustls", "rustls-pki-types", "serde", "serde_json", "socks", - "url", - "webpki-roots 0.26.11", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64 0.22.1", + "http 1.4.2", + "httparse", + "log", ] [[package]] @@ -9868,6 +9775,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -9898,12 +9811,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -10087,15 +9994,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.10", -] - [[package]] name = "webpki-roots" version = "1.0.10" diff --git a/deny.toml b/deny.toml index 594cc7a9d70..378da1672aa 100644 --- a/deny.toml +++ b/deny.toml @@ -88,7 +88,6 @@ ignore = [ #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, { id = "RUSTSEC-2024-0436", reason = "no fix: `paste` is unmaintained with no patched release; lance-bitpacking and foyer-memory (latest 0.22.6) depend on it" }, { id = "RUSTSEC-2023-0071", reason = "no fix: no `rsa` release fixes the Marvin timing side channel; opendal's reqsign crates depend on it" }, - { id = "RUSTSEC-2025-0119", reason = "expires 2027-01-20: `number_prefix` is unmaintained; indicatif 0.17 pulls it in via hf-hub 0.4 and tokenizers 0.15 in rust/examples, and moving those to hf-hub 0.5+ and tokenizers 0.22.2+ (indicatif 0.18) drops it" }, { id = "RUSTSEC-2026-0194", reason = "expires 2027-01-20: fixed in `quick-xml` 0.41; lance-namespace-impls still asks for 0.40, and pprof 0.15 (tests only) pulls in 0.26 via inferno 0.11, so recheck for a pprof release on inferno 0.12.7+" }, { id = "RUSTSEC-2026-0195", reason = "expires 2027-01-20: fixed in `quick-xml` 0.41; lance-namespace-impls still asks for 0.40, and pprof 0.15 (tests only) pulls in 0.26 via inferno 0.11, so recheck for a pprof release on inferno 0.12.7+" }, { id = "RUSTSEC-2024-0449", reason = "no fix: `unsafe-libyaml` is unmaintained; serde_yaml pulls it in for substrait 0.63, which datafusion-substrait (latest 55.2) still requires, and serde_yaml_ng for lindera 3" }, diff --git a/rust/examples/Cargo.toml b/rust/examples/Cargo.toml index fa6d0676655..7bc157c0652 100644 --- a/rust/examples/Cargo.toml +++ b/rust/examples/Cargo.toml @@ -48,7 +48,7 @@ tempfile = { workspace = true } tokio = { workspace = true } all_asserts.workspace = true env_logger.workspace = true -hf-hub = "0.4.2" +hf-hub = { version = "0.5.0", default-features = false, features = ["ureq"] } parquet = { workspace = true } -tokenizers = "0.15.2" +tokenizers = "0.22.2" rand.workspace = true From b640053e16b89ac4348138d9d77b46fd0cf62594 Mon Sep 17 00:00:00 2001 From: Travis Bischel Date: Tue, 20 Oct 2026 20:08:16 -0600 Subject: [PATCH 3/5] fix(examples): enable parquet's snap codec for llm_dataset_creation The wikitext parquet files the example downloads are snappy compressed, and the workspace builds parquet without codecs, so the example failed reading them with "Disabled feature at compile time: snap". The examples now enable parquet's snap feature. Co-authored-by: Claude Opus 5.5 (1M context) --- Cargo.lock | 7 +++++++ rust/examples/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fe78f5183dd..5027612edd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6638,6 +6638,7 @@ dependencies = [ "num-traits", "paste", "seq-macro", + "snap", "thrift", "tokio", "twox-hash", @@ -8658,6 +8659,12 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "snap" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199905e6153d6405f9728fe44daace35f8f837bbf830bb6e85fbd5828709a886" + [[package]] name = "socket2" version = "0.6.4" diff --git a/rust/examples/Cargo.toml b/rust/examples/Cargo.toml index 7bc157c0652..1f1bb558bb2 100644 --- a/rust/examples/Cargo.toml +++ b/rust/examples/Cargo.toml @@ -49,6 +49,6 @@ tokio = { workspace = true } all_asserts.workspace = true env_logger.workspace = true hf-hub = { version = "0.5.0", default-features = false, features = ["ureq"] } -parquet = { workspace = true } +parquet = { workspace = true, features = ["snap"] } tokenizers = "0.22.2" rand.workspace = true From 185bcc21b83c4387a4433595bf0b7ab68045af56 Mon Sep 17 00:00:00 2001 From: Travis Bischel Date: Thu, 22 Oct 2026 12:47:34 -0600 Subject: [PATCH 4/5] ci: drop the dependency-age allowlist entries for the webpki fixes #10215 allowlisted rustls-webpki 0.103.16 and webpki-roots and webpki-root-certs 1.0.10 so the eMudhra fixes could land before they were 48 hours old. All three are past 48 hours now, rustls-webpki, the youngest, since 2026-10-22 08:58 UTC, and each entry said to remove it after that time. ci/check_dependency_age.py passes on all three lockfiles without them. Co-authored-by: Claude Opus 5.5 (1M context) --- ci/dependency-age-allowlist.toml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/ci/dependency-age-allowlist.toml b/ci/dependency-age-allowlist.toml index 8404443e309..60866509a4e 100644 --- a/ci/dependency-age-allowlist.toml +++ b/ci/dependency-age-allowlist.toml @@ -13,18 +13,3 @@ # crate = "some-crate" # version = "1.2.3" # reason = "RUSTSEC-2026-0000, allowlisted in Aikido 2026-09-16" - -[[allow]] -crate = "rustls-webpki" -version = "0.103.16" -reason = "RUSTSEC-2026-0382 / CVE-2026-111943: rejects chains that carry the compromised eMudhra intermediate keys; remove after 2026-10-22T08:58Z" - -[[allow]] -crate = "webpki-roots" -version = "1.0.10" -reason = "drops emSign ECC Root CA - G3 after the eMudhra intermediate compromise; remove after 2026-10-21T20:11Z" - -[[allow]] -crate = "webpki-root-certs" -version = "1.0.10" -reason = "drops emSign ECC Root CA - G3 after the eMudhra intermediate compromise; remove after 2026-10-21T20:11Z" From 1939edd7d90745fb7427c1d58d4b964b5f1ff2bb Mon Sep 17 00:00:00 2001 From: Travis Bischel Date: Thu, 22 Oct 2026 14:58:21 -0600 Subject: [PATCH 5/5] ci: show both ignore markers in deny.toml's examples The commented examples at the top of the advisory ignore list still showed a bare id and free-form reasons, which ci/check_advisory_ignores.py now rejects. They now show an expires entry, a no fix entry and a yanked crate entry in the form the check accepts, so the list stays a usable template once the current expiring ignores are gone. Co-authored-by: Claude Opus 5.5 (1M context) --- deny.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/deny.toml b/deny.toml index 378da1672aa..11b39923ec3 100644 --- a/deny.toml +++ b/deny.toml @@ -82,10 +82,9 @@ feature-depth = 1 # younger than the 48 hours ci/check_dependency_age.py requires. Use no fix # when there is nothing to upgrade to. ignore = [ - #"RUSTSEC-0000-0000", - #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, - #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish - #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, + #{ id = "RUSTSEC-0000-0000", reason = "expires 2026-01-31: fixed `some-crate` 1.2.4 is under 48 hours old" }, + #{ id = "RUSTSEC-0000-0000", reason = "no fix: `some-crate` is unmaintained with no patched release; `other-crate` depends on it" }, + #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "expires 2026-01-31: 0.1.2 replaces the yanked release and is under 48 hours old" }, { id = "RUSTSEC-2024-0436", reason = "no fix: `paste` is unmaintained with no patched release; lance-bitpacking and foyer-memory (latest 0.22.6) depend on it" }, { id = "RUSTSEC-2023-0071", reason = "no fix: no `rsa` release fixes the Marvin timing side channel; opendal's reqsign crates depend on it" }, { id = "RUSTSEC-2026-0194", reason = "expires 2027-01-20: fixed in `quick-xml` 0.41; lance-namespace-impls still asks for 0.40, and pprof 0.15 (tests only) pulls in 0.26 via inferno 0.11, so recheck for a pprof release on inferno 0.12.7+" },