Skip to content

Bug: bans.build allow-build-scripts error does not show computed hash when using non-default build script path #765

Closed

Description

@tv42

Describe the bug

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-graph
warning[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 baf4e7f4b6b69ebf659ab35a8324d5dcdeb06209c35fef9ebe1d1035d8c48455

error[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 ban
error[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.toml
build = "builder/main.rs"

cargo-deny version

cargo-deny 0.18.2

What OS were you running cargo-deny on?

Linux

Additional context

No response

Activity

  1. added
    bugSomething isn't working
    on May 13, 2025
  2. tv42 commented on May 13, 2025

    @tv42
    Author

    Even if I get the sha256 myself, it never matches.

    [[bans.build.bypass]]
    crate = "aws-lc-sys"
    build-script = "e8e389f69f556256f9c00702ead273e942c35aca823274d2e305dcd2f7d6b9ea"
    $ cargo deny check ban --hide-inclusion-graph
    error[build-script-not-allowed]: crate 'aws-lc-sys = 0.29.0' has a build script but is not allowed to have one
    bans FAILED
    $ sha256sum ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-sys-0.29.0/builder/main.rs
    e8e389f69f556256f9c00702ead273e942c35aca823274d2e305dcd2f7d6b9ea  /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!

  3. cschanhniem commented on Jun 19, 2026

    @cschanhniem

    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:

    1. 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.

    2. 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions