Skip to content

rust@v1

Hygiene checks for Rust projects. Adopt it with:

extends:
- alint://bundled/rust@v1

This ruleset is gated with when: facts.has_rust (true if any Cargo.toml exists anywhere in the tree) plus a per-rule scope_filter: { has_ancestor: Cargo.toml } on per-file content rules so they only apply to files inside a Rust package — useful in polyglot monorepos where Rust packages sit alongside Node / Python / Go subdirectories. Rules that don't apply stay quiet. (has_rust is declared below; override with your own facts: block if you need a different heuristic.)

10 rules. Each links to its section below, which explains the check and shows its definition.

RuleReports
rust-cargo-toml-exists
error
Rust project: Cargo.toml at the repo root is required.
rust-cargo-lock-exists
warning
Committing Cargo.lock ensures reproducible builds for binary crates.
rust-toolchain-pinned
info
Pinning a toolchain (rust-toolchain.toml) makes local and CI builds reproducible.
rust-no-tracked-target
error
target/ is Cargo's build dir and must never be committed.
rust-sources-snake-case
error
Rust module filenames must be snake_case.
rust-sources-final-newline
warning
File must end with a single \n.
rust-sources-no-trailing-whitespace
info
No line may end with space or tab.
rust-sources-no-bidi
error
Trojan Source (CVE-2021-42574): bidi override chars in Rust sources are rejected.
rust-sources-no-zero-width
error
Zero-width characters in Rust sources are rejected (review hazard).
rust-no-merge-markers-in-manifests
error
Flag <<<<<<<, =======, >>>>>>>, ||||||| markers at the start of a line, almost always left over...

All 10 rules run only when facts.has_rust holds, so the ruleset stays quiet in repositories it doesn't apply to.

Rust project: Cargo.toml at the repo root is required.

- id: rust-cargo-toml-exists
when: facts.has_rust
kind: file_exists
paths: Cargo.toml
root_only: true
level: error
message: "Rust project: Cargo.toml at the repo root is required."

Committing Cargo.lock ensures reproducible builds for binary crates. Library-only workspaces may legitimately opt out; set this rule's level: off in that case.

- id: rust-cargo-lock-exists
when: facts.has_rust
kind: file_exists
paths: Cargo.lock
root_only: true
level: warning
message: >-
Committing Cargo.lock ensures reproducible builds for binary
crates. Library-only workspaces may legitimately opt out; set
this rule's `level: off` in that case.
policy_url: "https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html"

Pinning a toolchain (rust-toolchain.toml) makes local and CI builds reproducible.

- id: rust-toolchain-pinned
when: facts.has_rust
kind: file_exists
paths: ["rust-toolchain.toml", "rust-toolchain"]
root_only: true
level: info
message: "Pinning a toolchain (rust-toolchain.toml) makes local and CI builds reproducible."
  • kind: dir_absent
  • level: error
  • when: facts.has_rust

target/ is Cargo's build dir and must never be committed.

- id: rust-no-tracked-target
when: facts.has_rust
kind: dir_absent
paths: "**/target"
level: error
message: "`target/` is Cargo's build dir and must never be committed."

Changed in v0.9.18: default-exclude subtrees with deliberately non-snake-case filenames. Three categories surface in rust-lang/rust:

src/doc/** — doc examples + reference snippets
use English-style hyphenation
(`rustc-driver-example.rs`,
`rust-by-example/...`).
src/tools/miri/tests/** — Miri test fixtures use CamelCase /
intentional naming for litmus tests
and concurrency-spec semantics
(`abi_mismatch_repr_C.rs`,
`libc_pthread_mutex_NULL_reentrant.rs`).
src/tools/clippy/tests/ui/** — clippy UI test fixtures use
curly braces, hyphens, and other
non-snake-case markers as part of
the test grammar.
**/*.miri.rs — `.miri.rs` dot-suffix is a Miri-only
override file pattern; the dot in
the basename trips snake-case.

Without these excludes, rust-lang/rust alone surfaced 1,091 false positives — the largest single bundled-rule FP class in the case-study corpus. The excludes are unique to rust-lang/rust + similar compiler/test-fixture projects; they're a no-op for most repos.

  • kind: filename_case
  • level: error
  • when: facts.has_rust
  • fix: file_rename (applied by alint fix)

Rust module filenames must be snake_case.

- id: rust-sources-snake-case
when: facts.has_rust
kind: filename_case
paths:
include: ["**/src/**/*.rs"]
exclude:
- "src/doc/**"
- "src/tools/miri/tests/**"
- "src/tools/clippy/tests/ui/**"
- "src/tools/rustfmt/tests/**"
- "tests/rustdoc-gui/**"
- "**/*.miri.rs"
case: snake
level: error
message: "Rust module filenames must be snake_case."
fix:
file_rename: {}
  • kind: final_newline
  • level: warning
  • when: facts.has_rust
  • fix: file_append_final_newline (applied by alint fix)
- id: rust-sources-final-newline
when: facts.has_rust
kind: final_newline
paths: "**/*.rs"
scope_filter:
has_ancestor: Cargo.toml
level: warning
fix:
file_append_final_newline: {}

rust-sources-no-trailing-whitespace

Section titled "rust-sources-no-trailing-whitespace"
  • kind: no_trailing_whitespace
  • level: info
  • when: facts.has_rust
  • fix: file_trim_trailing_whitespace (applied by alint fix)
- id: rust-sources-no-trailing-whitespace
when: facts.has_rust
kind: no_trailing_whitespace
paths: "**/*.rs"
scope_filter:
has_ancestor: Cargo.toml
level: info
fix:
file_trim_trailing_whitespace: {}

Trojan Source (CVE-2021-42574): bidi override chars in Rust sources are rejected.

- id: rust-sources-no-bidi
when: facts.has_rust
kind: no_bidi_controls
paths: "**/*.rs"
scope_filter:
has_ancestor: Cargo.toml
level: error
message: "Trojan Source (CVE-2021-42574): bidi override chars in Rust sources are rejected."
policy_url: "https://trojansource.codes/"

Zero-width characters in Rust sources are rejected (review hazard).

- id: rust-sources-no-zero-width
when: facts.has_rust
kind: no_zero_width_chars
paths: "**/*.rs"
scope_filter:
has_ancestor: Cargo.toml
level: error
message: "Zero-width characters in Rust sources are rejected (review hazard)."

rust-no-merge-markers-in-manifests

Section titled "rust-no-merge-markers-in-manifests"
- id: rust-no-merge-markers-in-manifests
when: facts.has_rust
kind: no_merge_conflict_markers
paths: ["Cargo.toml", "**/Cargo.toml", "Cargo.lock", "**/Cargo.lock"]
scope_filter:
has_ancestor: Cargo.toml
level: error

The when: clauses above read these facts. Each is resolved once per run; alint facts prints what they resolved to in your repository.

facts:
- id: has_rust
any_file_exists: [Cargo.toml, "**/Cargo.toml"]

Every rule here can be overridden by id from your own .alint.yml: change its level, or set level: off to drop it. An id that doesn't exist is an error at config load, so a typo can't silently pass.

extends:
- alint://bundled/rust@v1
rules:
- id: rust-cargo-toml-exists
level: off
- id: rust-cargo-lock-exists
level: error

To take only part of the ruleset, filter it where you extend it with only: or except::

extends:
- url: alint://bundled/rust@v1
except: [rust-cargo-toml-exists]

Bundled rulesets covers versioning and how rulesets combine.

The full ruleset definition, comments included, is committed at crates/alint-dsl/rulesets/v1/rust.yml in the alint repo.