Skip to content

feat(scanner): Track Cargo build-script inputs - #127

Draft
reneleonhardt wants to merge 1 commit into
JordanCoin:mainfrom
reneleonhardt:feat/rust-build-script-input-dependencies
Draft

feat(scanner): Track Cargo build-script inputs#127
reneleonhardt wants to merge 1 commit into
JordanCoin:mainfrom
reneleonhardt:feat/rust-build-script-input-dependencies

Conversation

@reneleonhardt

Copy link
Copy Markdown
Contributor

What does this PR do?

Record file dependencies declared by literal println!("cargo:rerun-if-changed=...") and println!("cargo::rerun-if-changed=...") build-script directives. Extraction reuses the existing Rust syntax and string-literal scanner; resolution requires Cargo metadata to identify the package's exact custom-build target and accepts only one exact configured, indexed file under that package.

Comments, documentation strings, formatting arguments, malformed or control-containing values, globs, directories, missing files, absolute paths, escaping paths, ambiguous targets, self references, and directives outside the package build script remain unresolved.

Type of change

  • Bug fix
  • New feature
  • New language support
  • Documentation
  • Other (describe below)

Checklist

  • I've tested this locally with go build && ./codemap .
  • I've read CONTRIBUTING.md; this does not add a new language.
  • Documentation is unchanged because the dependency output is self-describing.

Additional notes

Focused extraction and conservative-resolution tests, the scanner suite, scanner staticcheck, and diff hygiene are GREEN.

An installed integration smoke test resolves app/build.rs as the importer of app/src/generated.rs. The integration suite is GREEN under the repository's Go 1.25 minimum and with full macOS race/coverage.

This branch targets and contains no generic macro, Cargo-topology, configuration, or non-Rust changes.

Developed with carefully directed, manually reviewed AI assistance.

Resolve literal Cargo rerun-if-changed directives through the existing Rust syntax scanner, authoritative custom-build ownership, and exact configured-file matching.

Co-Authored-By: GPT-5.6 Sol <codex@openai.com>
@JordanCoin

Copy link
Copy Markdown
Owner

Reviewed against real ground truth — built a Cargo workspace and used cargo check -vv's own freshness output to confirm which files cargo considers inputs, then compared codemap to that. The resolution is correct: both the old cargo: and new cargo:: prefixes work, raw strings work, paths resolve relative to the package root, and every non-literal form (format!, {ident} inline, loops, concat!, commented-out) produces no edge rather than a wrong one. With cargo off PATH it emits zero build-input edges — fails closed. The custom-build target guard is consistent with main's rustDependencyEligible model.

Two things I'd fix before landing.

1. println!($PATH) is unscoped — it matches every println! in every Rust file

scanner/sg-rules/rust.yml:41. parseRustBuildScriptInput then discards ~100% of them, but ast-grep has already matched, serialized, and buffered the lot. Measured on a synthetic 301-file crate with 30k println!s:

main this PR
ast-grep matches 30,000
JSON payload 39 MB
codemap --deps wall 0.31s 0.63s

All of it unmarshalled into []ScanMatch before filtering. The real hazard isn't the 2x — it's astGrepScanTimeout = 30s (scanner/astgrep.go:23). A println-heavy Rust monorepo pushed past that degrades the entire scan to ScanSourceTimeout, losing coverage for every language, not just this feature.

One-line fix, verified — 30,000 matches → 0 on the perf fixture, while the real fixture still yields all 4 genuine matches:

constraints:
  PATH:
    regex: 'cargo::?rerun-if-changed='

(A files: ["**/build.rs"] glob also works but would wrongly exclude crates using build = "custom_build.rs", so the constraint is the better lever.)

2. Directive paths leak into the imports array

scanner/astgrep.go:358-360 only excludes rust-path-imports, so extracted directive strings get appended to FileAnalysis.Imports:

{"path":"app/src/lib.rs","imports":["generated","schema.proto"]}

lib.rs imports nothing named schema.proto — it just contains a println! with that string in an ordinary function. Earlier fixture state also published ["../outside.proto","build.rs","missing.proto","protos"] for build.rs: unresolvable paths plus a self-reference, in the versioned codemap.analysis/v1 payload. Resolved graph edges are unaffected — only the raw array lies.

Worth noting #126 explicitly excludes its own kind (&& m.RuleID != "rust-askama-template-imports"), so #127 is the outlier here. Whoever merges second should make the two consistent rather than preserving both behaviors.

Finding 3 turned out to be a bug in main — filed as #130

Extension-less declared inputs can never resolve. cargo proves app/VERSION is an input; codemap says No files import app/VERSION. Root cause is in buildFileIndexContext: when a path has no extension, filepath.Ext returns "", so noExt == path and the same path is appended twice under the same key — meaning len(byExact[p]) == 2 forever, and the len(...) != 1 idiom rejects it permanently. Hits VERSION, Makefile, Dockerfile, LICENSE.

That's not yours to fix here — it's pre-existing, and the same three lines are also what lets #125 fabricate an edge to a nonexistent file. Filed as #130 with both halves; fixing it there makes this finding disappear without touching your PR.

Merge note

No signature changes, and rust-cargo-rerun-imports doesn't collide with #125's or #126's rule ids. I merged all four Rust PRs locally with union resolution and got a clean build and green go test ./...no repeat of the #117/#118 break. The one hazard for whoever resolves: scanner/astgrep.go:327 must union all three rule IDs. Taking either side of that one-line conflict silently disables a feature with fully green CI.

Nits: ExplicitTarget is set at astgrep.go:354 but resolveRustBuildScriptInput reads ref.Path, so it's dead for this kind; the test file constructs two scanners and never closes the one that actually scans; and rustbuildscript_test.go:97 hard-codes forward-slash expectations that would fail on Windows (latent — CI runs tests on ubuntu+macos only).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants