Skip to content

feat(detector): inventory Rust packages and audit Cargo configuration - #234

Draft
raysubham wants to merge 3 commits into
step-security:mainfrom
raysubham:feat/cargo-inventory
Draft

raysubham wants to merge 3 commits into
step-security:mainfrom
raysubham:feat/cargo-inventory

Conversation

@raysubham

Copy link
Copy Markdown
Contributor

Stacked on #230 (Go module inventory). Until #230 merges, this diff also shows its commits; the Cargo change is the last commit, b48b522. Draft until #230 lands and the API contract changes below are agreed.

What does this PR do?

Adds Rust/Cargo evidence to enterprise telemetry as two optional sections, cargo_inventory and cargo_config_audit (each schema_version: 1), in a new cargo_scan phase right after go_scan. Both are full bounded snapshots sent on every run. The shape mirrors the Go scanner and reuses its guards, source IDs and budgets.

cargo_inventory (static, no Rust toolchain needed)

  • Declared requirements from Cargo.toml: normal, dev, build and target-specific tables; aliases, features, optional and explicit default-features; registry, Git and path selectors. Workspace inheritance is applied; only workspace.dependencies entries that members inherit are followed.
  • Workspaces: members (literal and single-level globs), exclude, in-root path dependencies and explicit package.workspace. Membership that can't be established is workspace_unresolved.
  • Locked packages: Cargo.lock formats 3 and 4, once per workspace root, honoring resolver.lockfile-path. Other formats are unsupported_format.
  • Registry cache (registry/cache + registry/src), Git checkouts (full commit only from a 40/64-hex .git/HEAD), vendored directories, local registries and .crates.toml / .crates2.json install receipts with bin presence.
  • Recorded checksums from Cargo.lock and .cargo-checksum.json, always not_verified.

cargo_config_audit

  • .cargo/config and .cargo/config.toml per project and ancestor inside the search roots, the Cargo home config, includes (depth and count bounded, cycles flagged), and an allowlisted process environment, all resolved per invocation context in precedence order (config_source_ids).
  • Findings cargo-001..cargo-004: HTTP registry/source index, insecure Git source, plaintext token in config, http.check-revoke = false.
  • Credentials files are Stat-only.

Safety properties

  • No cargo, rustc or git command, shell, network call, PATH search or UserAwareExecutor. Every read goes through guarded, bounded executor file methods; .crate archives are read in memory with header, size and path-traversal bounds.
  • Protected directories stay excluded even with include_tcc_protected; there is no Cargo TCC exception.
  • Redaction happens on the device: URL userinfo, query and fragment are stripped (including URL-shaped table names such as [patch."https://…"]), tokens show only as configured, and custom credential providers become custom with arguments dropped.
  • Any refusal, failure or limit marks the affected source partial with a reason code. The record budget is charged during collection, and every owner left unfinished is marked record_limit. The combined output is capped at 16 MiB with a status envelope.
  • Stable source IDs and deterministic ordering, so identical logical inputs produce identical bytes.

Other: github.com/pelletier/go-toml/v2 v2.3.1 → v2.4.3. Community scan output is unchanged.

Contract: internal/model/testdata/cargo_inventory_v1_golden.json holds IDs recomputed from its displayed paths, and it decodes strictly and round-trips byte-identically. For it to pass the Agent API validator, the API needs to:

  • allow cached_package + vendor_unknown when the owner is a local_registry source;
  • allow a pathless user config source only when it is unsupported with path_unresolved.

Type of change

  • Bug fix
  • Enhancement
  • Documentation (SCAN_COVERAGE.md, README.md)

Testing

  • Tested on macOS (version: 27.0)
  • Binary runs without errors (make smoke): pending
  • JSON output is valid: not applicable, the sections are enterprise telemetry only and community JSON is unchanged
  • No secrets or credentials included
  • Lint passes: gofmt, go vet, golangci-lint (0 issues)
  • Tests pass: go test ./... -race -count=1

Also:

  • CGO_ENABLED=0 builds for linux/amd64, darwin/arm64 and windows/amd64; go mod tidy shows no drift.
  • gosec: no new findings in the Cargo files.
  • Regression tests cover URL table-name redaction, partial selection when a higher-precedence config is unreadable, no null arrays, record-limit ownership under every budget, inherited external path dependencies (followed) versus unused ones (not followed), and unreadable bins (Unix, non-root).

Not yet done (release checks):

  • make smoke.
  • Three-VM acceptance (macOS, Linux, Windows) against cargo metadata references.
  • The API validator changes above, then running the shared golden through the real validator.

Related Issues

raysubham and others added 3 commits September 30, 2026 23:53
Add cargo_inventory and cargo_config_audit (schema_version 1) to
enterprise telemetry in a new cargo_scan phase after go_scan.

The inventory reads Cargo.toml declarations with workspace inheritance,
Cargo.lock formats 3 and 4, the registry cache, Git checkouts, vendored
sources and local registries, and cargo install receipts. The audit
reads .cargo/config(.toml) files, their includes and an allowlisted
process environment per invocation context, with findings
cargo-001..cargo-004.

Everything is static: no cargo, rustc or git command, shell or network
call. Reads go through guarded, bounded executor file methods, URL
credentials are redacted on the device, credentials files are checked
for presence only, and any refusal, failure or limit marks the affected
source partial. Bumps go-toml/v2 to v2.4.3.

This branch has not been deployed

No deployments
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.

1 participant