From a4c2a9283df689fa19433cb50243d1e63e7ca36b Mon Sep 17 00:00:00 2001 From: jan-kubica Date: Tue, 23 Jun 2026 23:44:47 +0200 Subject: [PATCH] feat: add shared Rust policy templates --- README.md | 17 +++++- cliff.toml | 22 +++---- rust/README.md | 51 ++++++++++++++++ rust/cargo-config.toml | 6 ++ rust/cargo-root.toml | 113 +++++++++++++++++++++++++++++++++++ rust/cargo-workspace.toml | 120 ++++++++++++++++++++++++++++++++++++++ rust/clippy.toml | 26 +++++++++ rust/rustfmt.toml | 4 ++ 8 files changed, 346 insertions(+), 13 deletions(-) create mode 100644 rust/README.md create mode 100644 rust/cargo-config.toml create mode 100644 rust/cargo-root.toml create mode 100644 rust/cargo-workspace.toml create mode 100644 rust/clippy.toml create mode 100644 rust/rustfmt.toml diff --git a/README.md b/README.md index a1aaea0..f0c482c 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,14 @@ # stella tooling -Shared TypeScript and oxlint configuration for stella public packages. +Shared TypeScript, oxlint, and Rust configuration for stella public packages. This repo intentionally contains only portable tooling policy: - `@stll/typescript-config`: strict TypeScript config presets. - `@stll/oxlint-config`: general upstream oxlint rules and the shared `stella-lowercase` and `no-raw-colors` JS plugins. +- `rust/`: source-of-truth Rust formatting, lint, and Cargo profile templates. Repo-specific stella rules stay in the consuming repo: custom oxlint plugins, security rules, i18n rules, generated native artifacts, benchmark exceptions, @@ -18,7 +19,7 @@ and package-specific ignores. ## Usage -Install the shared packages: +Install the shared TypeScript and oxlint packages: ```bash bun add -d @stll/typescript-config @stll/oxlint-config oxlint oxlint-tsgolint typescript @@ -87,3 +88,15 @@ Recommended scripts: } } ``` + +Use the Rust templates by copying them into a Rust repository: + +```bash +cp rust/rustfmt.toml /path/to/repo/rustfmt.toml +cp rust/clippy.toml /path/to/repo/clippy.toml +``` + +Then copy either `rust/cargo-root.toml` or `rust/cargo-workspace.toml` into the +repository's root `Cargo.toml`. Cargo does not support extending these settings +from another package, so the templates are kept here as the canonical source and +synced into consumers. diff --git a/cliff.toml b/cliff.toml index bdae487..fbd12bf 100644 --- a/cliff.toml +++ b/cliff.toml @@ -45,17 +45,17 @@ sort_commits = "newest" # digits leave headroom for new sections without breaking sort # (single-digit `10` would otherwise sort before `2`). commit_parsers = [ - { message = "^feat", group = "00:๐Ÿš€ Features" }, - { message = "^fix", group = "01:๐Ÿ› Bug Fixes" }, - { message = "^perf", group = "02:โšก Performance" }, - { message = "^refactor", group = "03:โ™ป๏ธ Refactor" }, - { message = "^docs", group = "04:๐Ÿ“š Documentation" }, - { message = "^test", group = "05:๐Ÿงช Tests" }, + { message = "^feat", group = "00:๐Ÿš€ Features" }, + { message = "^fix", group = "01:๐Ÿ› Bug Fixes" }, + { message = "^perf", group = "02:โšก Performance" }, + { message = "^refactor", group = "03:โ™ป๏ธ Refactor" }, + { message = "^docs", group = "04:๐Ÿ“š Documentation" }, + { message = "^test", group = "05:๐Ÿงช Tests" }, { message = "^chore\\(deps[^)]*\\)", group = "06:๐Ÿ“ฆ Dependencies" }, { message = "^chore\\(release\\)", skip = true }, - { message = "^chore", group = "07:โš™๏ธ Miscellaneous" }, - { message = "^style", skip = true }, - { message = "^ci", skip = true }, - { message = "^build", skip = true }, - { message = "^revert", group = "08:โช Reverts" }, + { message = "^chore", group = "07:โš™๏ธ Miscellaneous" }, + { message = "^style", skip = true }, + { message = "^ci", skip = true }, + { message = "^build", skip = true }, + { message = "^revert", group = "08:โช Reverts" }, ] diff --git a/rust/README.md b/rust/README.md new file mode 100644 index 0000000..7752755 --- /dev/null +++ b/rust/README.md @@ -0,0 +1,51 @@ +# stella Rust policy + +Shared Rust formatting, lint, and Cargo profile templates for stella public +packages. + +Cargo cannot import `[lints]`, `[profile]`, or `clippy.toml` from another +package. Treat this directory as the source of truth and copy the templates +into Rust repositories when adding or refreshing Rust support. + +## Files + +- `rustfmt.toml`: formatting baseline. +- `clippy.toml`: portable disallowed APIs and lint thresholds. +- `cargo-root.toml`: root `Cargo.toml` snippets for single-crate packages. +- `cargo-workspace.toml`: root `Cargo.toml` snippets for workspaces. +- `cargo-config.toml`: optional `.cargo/config.toml` aliases for local and CI + checks. + +## Recommended Checks + +```bash +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features --locked -- -D warnings +cargo test --workspace --all-features --locked +cargo audit +cargo deny check +``` + +For pure Rust crates that do not call FFI at test runtime, also run: + +```bash +cargo miri test --workspace +``` + +## Adoption + +1. Copy `rustfmt.toml` and `clippy.toml` to the repository root. +2. Copy the relevant `[workspace.lints]` or `[lints]` section into + `Cargo.toml`. +3. Copy the release/profile section into the root `Cargo.toml`. +4. Add `[lints] workspace = true` to each workspace member, if using a + workspace. +5. Add local exceptions only with a short reason at the narrowest scope. + +Keep repo-specific policy in the consuming repo. Examples: custom filesystem +wrappers, generated native artifacts, benchmark exceptions, or intentionally +unsafe FFI shims. + +The shared baseline targets Rust 2024. Repositories still on Rust 2021 can copy +the templates and temporarily set `edition = "2021"` in `rustfmt.toml` until +they migrate. diff --git a/rust/cargo-config.toml b/rust/cargo-config.toml new file mode 100644 index 0000000..8f8c6aa --- /dev/null +++ b/rust/cargo-config.toml @@ -0,0 +1,6 @@ +# Optional .cargo/config.toml snippet for Rust repositories. + +[alias] +ci-fmt = "fmt --all -- --check" +ci-clippy = "clippy --workspace --all-targets --all-features --locked -- -D warnings" +ci-test = "test --workspace --all-features --locked" diff --git a/rust/cargo-root.toml b/rust/cargo-root.toml new file mode 100644 index 0000000..115a1f1 --- /dev/null +++ b/rust/cargo-root.toml @@ -0,0 +1,113 @@ +# Copy these snippets into the root Cargo.toml for a single-crate package. + +[lints.rust] +warnings = { level = "deny", priority = -1 } +dead_code = "deny" +future_incompatible = { level = "deny", priority = -1 } +nonstandard_style = { level = "deny", priority = -1 } +rust_2018_idioms = { level = "deny", priority = -1 } +unreachable_code = "deny" +unreachable_patterns = "deny" +unreachable_pub = "deny" +unsafe_code = "deny" +unused_imports = "deny" +unused_macros = "deny" +unused_mut = "deny" +unused_variables = "deny" + +[lints.rustdoc] +broken_intra_doc_links = "deny" +bare_urls = "deny" + +[lints.clippy] +all = { level = "deny", priority = -1 } +pedantic = { level = "warn", priority = -1 } +cargo = { level = "warn", priority = -1 } +nursery = { level = "warn", priority = -1 } + +dbg_macro = "deny" +todo = "deny" +unimplemented = "deny" +panic = "deny" +unwrap_used = "deny" +expect_used = "deny" +indexing_slicing = "warn" +integer_division = "warn" +arithmetic_side_effects = "warn" +as_conversions = "warn" +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_precision_loss = "warn" +cast_sign_loss = "warn" +clone_on_ref_ptr = "deny" +create_dir = "deny" +decimal_literal_representation = "warn" +derive_partial_eq_without_eq = "deny" +disallowed_macros = "deny" +disallowed_methods = "deny" +disallowed_types = "deny" +empty_enum_variants_with_brackets = "deny" +empty_structs_with_brackets = "deny" +enum_glob_use = "deny" +exit = "deny" +filetype_is_file = "deny" +float_cmp = "warn" +fn_to_numeric_cast_any = "deny" +format_collect = "deny" +if_then_some_else_none = "deny" +implicit_clone = "deny" +inefficient_to_string = "deny" +large_enum_variant = "deny" +large_stack_arrays = "deny" +large_stack_frames = "deny" +manual_let_else = "deny" +manual_memcpy = "deny" +map_unwrap_or = "deny" +mem_forget = "deny" +missing_assert_message = "warn" +missing_errors_doc = "allow" +missing_panics_doc = "allow" +module_name_repetitions = "allow" +multiple_crate_versions = "allow" +needless_collect = "deny" +needless_continue = "deny" +needless_pass_by_ref_mut = "deny" +needless_pass_by_value = "deny" +or_fun_call = "deny" +print_stderr = "deny" +print_stdout = "deny" +redundant_clone = "deny" +same_name_method = "deny" +self_named_module_files = "allow" +semicolon_if_nothing_returned = "deny" +shadow_reuse = "allow" +shadow_same = "warn" +shadow_unrelated = "warn" +std_instead_of_alloc = "allow" +std_instead_of_core = "allow" +string_slice = "warn" +tests_outside_test_module = "allow" +trivially_copy_pass_by_ref = "deny" +unnecessary_wraps = "deny" +unneeded_field_pattern = "deny" +unreachable = "deny" +unused_async = "deny" +unused_self = "deny" +use_self = "warn" +used_underscore_binding = "deny" +verbose_file_reads = "deny" +wildcard_imports = "deny" + +[profile.release] +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = "symbols" + +[profile.dev] +debug = "line-tables-only" + +[profile.ci] +inherits = "dev" +debug-assertions = true +overflow-checks = true diff --git a/rust/cargo-workspace.toml b/rust/cargo-workspace.toml new file mode 100644 index 0000000..8142dbe --- /dev/null +++ b/rust/cargo-workspace.toml @@ -0,0 +1,120 @@ +# Copy these snippets into the root Cargo.toml for a workspace. +# Add this to each member crate: +# +# [lints] +# workspace = true + +[workspace] +resolver = "2" + +[workspace.lints.rust] +warnings = { level = "deny", priority = -1 } +dead_code = "deny" +future_incompatible = { level = "deny", priority = -1 } +nonstandard_style = { level = "deny", priority = -1 } +rust_2018_idioms = { level = "deny", priority = -1 } +unreachable_code = "deny" +unreachable_patterns = "deny" +unreachable_pub = "deny" +unsafe_code = "deny" +unused_imports = "deny" +unused_macros = "deny" +unused_mut = "deny" +unused_variables = "deny" + +[workspace.lints.rustdoc] +broken_intra_doc_links = "deny" +bare_urls = "deny" + +[workspace.lints.clippy] +all = { level = "deny", priority = -1 } +pedantic = { level = "warn", priority = -1 } +cargo = { level = "warn", priority = -1 } +nursery = { level = "warn", priority = -1 } + +dbg_macro = "deny" +todo = "deny" +unimplemented = "deny" +panic = "deny" +unwrap_used = "deny" +expect_used = "deny" +indexing_slicing = "warn" +integer_division = "warn" +arithmetic_side_effects = "warn" +as_conversions = "warn" +cast_possible_truncation = "warn" +cast_possible_wrap = "warn" +cast_precision_loss = "warn" +cast_sign_loss = "warn" +clone_on_ref_ptr = "deny" +create_dir = "deny" +decimal_literal_representation = "warn" +derive_partial_eq_without_eq = "deny" +disallowed_macros = "deny" +disallowed_methods = "deny" +disallowed_types = "deny" +empty_enum_variants_with_brackets = "deny" +empty_structs_with_brackets = "deny" +enum_glob_use = "deny" +exit = "deny" +filetype_is_file = "deny" +float_cmp = "warn" +fn_to_numeric_cast_any = "deny" +format_collect = "deny" +if_then_some_else_none = "deny" +implicit_clone = "deny" +inefficient_to_string = "deny" +large_enum_variant = "deny" +large_stack_arrays = "deny" +large_stack_frames = "deny" +manual_let_else = "deny" +manual_memcpy = "deny" +map_unwrap_or = "deny" +mem_forget = "deny" +missing_assert_message = "warn" +missing_errors_doc = "allow" +missing_panics_doc = "allow" +module_name_repetitions = "allow" +multiple_crate_versions = "allow" +needless_collect = "deny" +needless_continue = "deny" +needless_pass_by_ref_mut = "deny" +needless_pass_by_value = "deny" +or_fun_call = "deny" +print_stderr = "deny" +print_stdout = "deny" +redundant_clone = "deny" +same_name_method = "deny" +self_named_module_files = "allow" +semicolon_if_nothing_returned = "deny" +shadow_reuse = "allow" +shadow_same = "warn" +shadow_unrelated = "warn" +std_instead_of_alloc = "allow" +std_instead_of_core = "allow" +string_slice = "warn" +tests_outside_test_module = "allow" +trivially_copy_pass_by_ref = "deny" +unnecessary_wraps = "deny" +unneeded_field_pattern = "deny" +unreachable = "deny" +unused_async = "deny" +unused_self = "deny" +use_self = "warn" +used_underscore_binding = "deny" +verbose_file_reads = "deny" +wildcard_imports = "deny" + +[profile.release] +lto = "fat" +codegen-units = 1 +panic = "abort" +strip = "symbols" + +[profile.dev] +debug = "line-tables-only" + +[profile.ci] +inherits = "dev" +debug-assertions = true +overflow-checks = true diff --git a/rust/clippy.toml b/rust/clippy.toml new file mode 100644 index 0000000..251b36f --- /dev/null +++ b/rust/clippy.toml @@ -0,0 +1,26 @@ +# Portable stella Rust lint configuration. Keep repo-specific wrappers and +# exceptions in consuming repositories. + +disallowed-macros = [ + { path = "std::dbg", reason = "remove debug output before commit" }, + { path = "std::print", reason = "library crates should return data or use structured logging" }, + { path = "std::println", reason = "library crates should return data or use structured logging" }, + { path = "std::eprint", reason = "library crates should return data or use structured logging" }, + { path = "std::eprintln", reason = "library crates should return data or use structured logging" }, +] + +disallowed-methods = [ + { path = "std::mem::forget", reason = "leaks ownership; use a narrow ownership type or ManuallyDrop with justification" }, + { path = "std::string::String::from_utf8_lossy", reason = "lossy decoding can corrupt offsets and user data; validate or keep bytes" }, +] + +disallowed-types = [ + { path = "std::collections::LinkedList", reason = "prefer Vec, VecDeque, or an explicit intrusive structure" }, +] + +pass-by-value-size-limit = 64 +stack-size-threshold = 131072 +enum-variant-size-threshold = 128 +too-large-for-stack = 4096 +avoid-breaking-exported-api = false +accept-comment-above-attributes = true diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml new file mode 100644 index 0000000..b1b458b --- /dev/null +++ b/rust/rustfmt.toml @@ -0,0 +1,4 @@ +edition = "2024" +max_width = 80 +reorder_imports = true +tab_spaces = 2