You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Bug: bans.build allow-build-scripts error does not show computed hash when using non-default build script path #765
Normally cargo deny check ban outputs error with the computed hash, for easy copy-pasting.
When a crate uses a non-default build = in its Cargo.toml, this does not happen.
To reproduce
Normal case (I've intentionally corrupted the hash to trigger this error):
$ cargo deny check ban --hide-inclusion-graphwarning[checksum-mismatch]: file did not match the expected checksum ┌─ /blah/deny.toml:31:17 │31 │ build-script = "baf4e7f4b6b69ebf659ab35a8324d5dcdeb06209c35fef9ebe1d1035d8c48454" │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected checksum │ ├ path = '$CARGO_HOME/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.13.1/build.rs' ├ error = build script failed checksum: checksum mismatch, calculated baf4e7f4b6b69ebf659ab35a8324d5dcdeb06209c35fef9ebe1d1035d8c48455error[build-script-not-allowed]: crate 'aws-lc-rs = 1.13.1' has a build script but is not allowed to have on
Weird case:
$ cargo deny check banerror[build-script-not-allowed]: crate 'aws-lc-sys = 0.29.0' has a build script but is not allowed to have one
$ grep ^build ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-sys-0.29.0/Cargo.tomlbuild = "builder/main.rs"
$ cargo deny check ban --hide-inclusion-grapherror[build-script-not-allowed]: crate 'aws-lc-sys = 0.29.0' has a build script but is not allowed to have onebans FAILED
$ sha256sum ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-sys-0.29.0/builder/main.rse8e389f69f556256f9c00702ead273e942c35aca823274d2e305dcd2f7d6b9ea /blah/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-sys-0.29.0/builder/main.rs
I guess in this case that's a good thing, because that's a full crate with modules, and the hash would only cover one file. But the error behavior could definitely be better!
The discrepancy comes from where cargo-deny reads the build script path. For crates with the default build = "build.rs" (or no explicit build key), the path resolution goes through cargo_metadata::Package::manifest_path joined with build.rs, and the computed hash is emitted in every error path via bans::diags::build_script_not_allowed.
For crates with a non-default build = "builder/main.rs", the manifest-declared build path is used for the actual scanning, but the diagnostic path in bans/src/diags.rs constructs the display path using the default build.rs convention (via let build_script_path = package.manifest_path.parent().unwrap().join("build.rs")). When the bypass hash is provided but doesnt match, the computed hash is only printed conditional on checksum_mismatch being true — which is only set when the hash comparison actually runs against the file. Since the bypass hash doesnt match the expected file, checksum_mismatch is false, and the hash is silently dropped.
The fix is in two parts:
In bans/src/graph.rs, the check_build_script function should store the actual build script path (from Cargo.tomls build field, available via cargo_metadata::Package::metadata["build"] or parsed from the raw manifest) rather than defaulting to package.root()/build.rs.
In bans/src/diags.rs, build_script_not_allowed should always emit the computed hash string when a bypass entry exists, regardless of checksum_mismatch. Currently the hash is only shown when checksum_mismatch is true, but for the typical onboarding flow the user is trying to get the hash to create a bypass entry in the first place.
The relevant flow:
bans/src/graph.rs:check_build_script()
→ reads build path from Package
→ computes sha256 of the build script
→ if bypass entry exists: compares hashes
→ match: skip check
→ mismatch: set checksum_mismatch = true but only if build_script_path == expected_bypass.build_script
→ no bypass entry: emit build_script_not_allowed WITHOUT computed hash
If tv42 (the reporter) wants to send a PR, the structural change is: always surface (computed_hash, actual_build_script_path) from check_build_script, and let the diagnostic builder decide whether to render it.
Activity
tv42 commentedon May 13, 2025
Even if I get the sha256 myself, it never matches.
I guess in this case that's a good thing, because that's a full crate with modules, and the hash would only cover one file. But the error behavior could definitely be better!
cschanhniem commentedon Jun 19, 2026
The discrepancy comes from where cargo-deny reads the build script path. For crates with the default
build = "build.rs"(or no explicitbuildkey), the path resolution goes throughcargo_metadata::Package::manifest_pathjoined withbuild.rs, and the computed hash is emitted in every error path viabans::diags::build_script_not_allowed.For crates with a non-default
build = "builder/main.rs", the manifest-declared build path is used for the actual scanning, but the diagnostic path inbans/src/diags.rsconstructs the display path using the defaultbuild.rsconvention (vialet build_script_path = package.manifest_path.parent().unwrap().join("build.rs")). When the bypass hash is provided but doesnt match, the computed hash is only printed conditional onchecksum_mismatchbeing true — which is only set when the hash comparison actually runs against the file. Since the bypass hash doesnt match the expected file,checksum_mismatchis false, and the hash is silently dropped.The fix is in two parts:
In
bans/src/graph.rs, thecheck_build_scriptfunction should store the actual build script path (fromCargo.tomlsbuildfield, available viacargo_metadata::Package::metadata["build"]or parsed from the raw manifest) rather than defaulting topackage.root()/build.rs.In
bans/src/diags.rs,build_script_not_allowedshould always emit the computed hash string when a bypass entry exists, regardless ofchecksum_mismatch. Currently the hash is only shown whenchecksum_mismatchis true, but for the typical onboarding flow the user is trying to get the hash to create a bypass entry in the first place.The relevant flow:
If
tv42(the reporter) wants to send a PR, the structural change is: always surface(computed_hash, actual_build_script_path)fromcheck_build_script, and let the diagnostic builder decide whether to render it.