Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
allowed-idents-below-min-chars = [
# clippy defaults
"Eq",
"Err",
"Ge",
"Gt",
"Le",
"Lt",
"Ne",
"Ok",
# standard Rust idioms
"'_", # elided lifetime
"Rc", # std::rc::Rc, peer of Arc
"cx", # async Context (Future::poll convention)
"e", # error binding in `Err(e)`
"fs", # `use std::fs` / `use fs_err as fs` alias
"ip", # IP address (networking)
"rx", # tokio/std mpsc transmit/receive convention
"tx",
# math/engineering conventions
"t0",
"t1", # timestamps
"x1",
"x2", # bounding-box coords
"y1",
"y2",
# workspace conventions
"Io", # io::Error #[from] variant
"Js", # ModuleKind::Js variant (peer of Wasi)
"et", # `et:ws-wasi` WIT package — appears in generated `bindings::et::…`
"id", # short alias for identifier inside closures
"op", # operation-name parameter in et-web JS-interop traits
"ws", # edge_toolkit::ws module (websocket types)
]
min-ident-chars-threshold = 2
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.claude/
*.wasm
*.onnx
target/
Expand Down
7 changes: 7 additions & 0 deletions .mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ cargo-binstall = "latest"
"cargo:ast-grep" = "latest"
"cargo:aube" = "latest"
"cargo:cargo-expand" = "latest"
"cargo:cargo-unmaintained" = "latest"
"cargo:taplo-cli" = "latest"
"cargo:wasm-pack" = "latest"
"cargo:watchexec-cli" = "latest"
Expand Down Expand Up @@ -101,6 +102,7 @@ depends = [
"ast-grep-check",
"cargo-check",
"cargo-clippy",
"cargo-doc-check",
"cargo-fmt-check",
"dart-check",
"dotnet-check",
Expand Down Expand Up @@ -130,6 +132,11 @@ run = "cargo +nightly fmt -- --check"
[tasks.cargo-clippy]
run = "cargo clippy --workspace --tests"

[tasks.cargo-doc-check]
description = "Build rustdoc with -D warnings to fail on any doc issues"
env = { RUSTDOCFLAGS = "-D warnings" }
run = "cargo doc --workspace --no-deps --document-private-items"

[tasks.cargo-clippy-fix]
run = "cargo clippy --fix --allow-dirty --allow-staged --workspace --tests"

Expand Down
8 changes: 8 additions & 0 deletions .taplo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ keys = ["package"]
[[rule]]
formatting = { reorder_arrays = false }
keys = ["workspace"]

# Forbid `path = "..."` dependencies in non-root Cargo.toml files. The root
# Cargo.toml's `[workspace.dependencies]` is the only legitimate place for
# path deps; member crates reference them via `dep.workspace = true`.
[[rule]]
exclude = ["Cargo.toml"]
include = ["**/Cargo.toml"]
schema = { path = "config/taplo/no-path-deps.schema.json" }
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 140 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,19 @@ base64 = "0.22.1"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.4", features = ["derive"] }
edge-toolkit = { path = "libs/edge-toolkit" }
et-modules-service = { path = "services/modules" }
et-otlp = { path = "libs/et-otlp" }
et-storage-service = { path = "services/storage" }
et-web = { path = "libs/web" }
et-ws-service = { path = "services/ws" }
et-ws-test-server = { path = "services/ws-test-server" }
et-ws-wasm-agent = { path = "services/ws-wasm-agent" }
fs-err = "3"
lets_find_up = "0.0.4"
log = "0.4"
onnx-extractor = "0.3"
opentelemetry = "0.31"
otlp-mock = { path = "libs/otlp-mock" }
rstest = "0.26"
secrecy = { version = "0.10.3", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
Expand All @@ -60,7 +66,9 @@ serde-inline-default = "1.0"
serde_default = "0.2"
serde_json = "1"
serde_yaml = "0.9"
temp-env = "0.3"
tempfile = "3"
testing_logger = "0.1"
thiserror = "2"
toml = "0.8"
tracing = "0.1"
Expand All @@ -72,3 +80,135 @@ tracing-actix-web = { version = "0.7", default-features = false, features = [
tracing-opentelemetry = "0.32"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1", features = ["serde", "v4", "v7"] }

[profile.release.package.et-ws-wasm-agent]
opt-level = "s"

[workspace.lints.rust]
# groups
unused = { level = "deny", priority = -1 }
# specific lints
dead_code = "deny"
let_underscore = { level = "deny", priority = -1 }
macro_use_extern_crate = "deny"
non_ascii_idents = "deny"
# Allowing private_bounds & private_interfaces & unnameable_types reduces the noise of using `visibility` crate.
private_bounds = "allow"
private_interfaces = "allow"
unnameable_types = "allow"

redundant_imports = "deny"
redundant_lifetimes = "deny"
trivial_numeric_casts = "deny"
# raises an error on unmet expect statements so they are easily found and fixed
unfulfilled_lint_expectations = "deny"
unsafe_attr_outside_unsafe = "deny"
unsafe_code = "deny"
unsafe_op_in_unsafe_fn = "deny"
# unused_crate_dependencies fires per test binary: dev-deps declared once but consumed by only a
# subset of `tests/*.rs` files (each compiled as its own crate) are flagged as unused in the
# sibling test crates that don't import them. Tracked at rust-lang/rust#95513; re-enable when
# rustc gains a workspace-aware view.
# unused_crate_dependencies = "deny"
unused_results = "warn"

[workspace.lints.rustdoc]
private_intra_doc_links = { level = "deny", priority = 8 }

[workspace.lints.clippy]
# priority numbers are arbitrary ints; higher overrides lower.
# blanket clippy category rules appear at the top, while sub category lints appear below with priority levels
all = { level = "deny", priority = -1 }
complexity = { level = "deny", priority = -1 }
correctness = { level = "deny", priority = -1 }
implicit_return = { level = "allow", priority = 8 }
nursery = { level = "deny", priority = -1 }
pedantic = { level = "deny", priority = -1 }
perf = { level = "deny", priority = -1 }
restriction = { level = "deny", priority = -1 }
style = { level = "deny", priority = -1 }
suspicious = { level = "deny", priority = -1 }
# blanket_clippy_restriction_lints allows the above blanket deny
blanket_clippy_restriction_lints = { level = "allow", priority = 8 }
# allow lint groups to override priorities
integer_division_remainder_used = { level = "deny", priority = 8 }
lint_groups_priority = { level = "allow", priority = 8 }
# Allowing question_mark_used is an explicit implementation choice.
question_mark_used = { level = "allow", priority = 8 }
# Allowing std_instead_of_alloc as we have no reason yet to choose alloc,core over std
single_call_fn = { level = "deny", priority = 4 }
std_instead_of_alloc = { level = "allow", priority = 8 }
std_instead_of_core = { level = "allow", priority = 8 }
str_to_string = { level = "allow", priority = 4 }
struct_excessive_bools = { level = "allow", priority = 8 }
# Allowing shadow_reuse, shadow_same & shadow_unrelated is an explicit style choice, preferring to allow
# developers to reuse a name even if its type changes.
semicolon_if_nothing_returned = { level = "deny", priority = 4 }
shadow_reuse = { level = "allow", priority = 4 }
shadow_same = { level = "allow", priority = 4 }
shadow_unrelated = { level = "allow", priority = 4 }
# Block-scoped statements like `{ *guard = ...; }` use the closing brace to drop borrows;
# moving the `;` outside risks extending MutexGuard lifetimes past the intended scope.
semicolon_outside_block = { level = "allow", priority = 4 }
# Allowing separated_literal_suffix & unseparated_literal_suffix is an explicit style choice.
separated_literal_suffix = { level = "allow", priority = 4 }
unseparated_literal_suffix = { level = "allow", priority = 4 }
# Allowing absolute_paths is an explicit style choice.
absolute_paths = { level = "allow", priority = 4 }
# Allowing pub_use is an explicit style choice to streamline coding.
impl_trait_in_params = { level = "deny", priority = 4 }
pub_use = { level = "allow", priority = 4 }
# Allowing module_name_repetitions & mod_module_files are an explicit code layout choice.
mod_module_files = { level = "allow", priority = 4 }
module_name_repetitions = { level = "allow", priority = 4 }
self_named_module_files = { level = "deny", priority = 4 }
# Allowing missing_docs_in_private_items is an explicit but temporary choice to focus on documentation of public items.
missing_docs_in_private_items = { level = "allow", priority = 2 }
# missing_inline_in_public_items forces use of `#[inline]` on public items, which is not desirable.
missing_inline_in_public_items = { level = "allow", priority = 4 }
# Allowing missing_errors_doc as fixing unwrap's is the more important task.
future_not_send = { level = "deny", priority = 4 }
missing_errors_doc = { level = "allow", priority = 4 }
# pattern_type_mismatch fights with idiomatic match ergonomics (e.g. `for (k, v) in &map`,
# `if let Some(x) = &option`).
pattern_type_mismatch = { level = "allow", priority = 4 }
unused_async = { level = "deny", priority = 2 }
# as_conversions & cast_lossless & cast_possible_wrap should be replaced with safer wrapped conversion
as_conversions = "deny"
cast_lossless = "deny"
cast_possible_wrap = "deny"
clone_on_ref_ptr = { level = "deny", priority = 4 }
infinite_loop = "deny"
too_many_arguments = { level = "deny", priority = 2 }
# Allowing missing_trait_methods to avoid forcing explicit implementation of default trait methods
missing_trait_methods = { level = "allow", priority = 4 }
pub_with_shorthand = { level = "allow", priority = 4 }
pub_without_shorthand = { level = "deny", priority = 4 }
# clippy removing pub(crate) is quite confusing at times
redundant_pub_crate = { level = "allow", priority = 4 }

type_complexity = { level = "deny", priority = 4 }

min_ident_chars = { level = "deny", priority = 4 }

# Allowing arbitrary_source_item_ordering: strict alphabetical ordering destroys semantic grouping
# (e.g. WsMessage variants in connection-lifecycle order, struct fields ordered by importance).
arbitrary_source_item_ordering = { level = "allow", priority = 4 }

# Force use of #[expect(..)] instead of #[allow(..)]
allow_attributes = { level = "deny", priority = 4 }
# This lint also covers #[expect] without a reason, so allow this to prevent silly reason values.
allow_attributes_without_reason = { level = "allow", priority = 4 }

let_underscore_must_use = { level = "deny", priority = 4 }
let_underscore_untyped = { level = "deny", priority = 4 }
missing_panics_doc = { level = "allow", priority = 4 }

[workspace.metadata.unmaintained]
ignore = [
# It is a hg repo, which is not supported by cargo-unmaintained
"oorandom",
# https://github.com/rustsec/advisory-db/issues/2132
"serde_yaml",
"unsafe-libyaml",
]
18 changes: 18 additions & 0 deletions config/ast-grep/rules/no-doctest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
id: no-doctest
language: Rust
severity: error
message: |
Doctests are forbidden. Move runnable examples into a `tests/` file
(every test file must start with `#![cfg(test)]`).
rule:
any:
- kind: line_comment
all:
- regex: "^(///|//!)"
- regex: "```"
- kind: block_comment
all:
- regex: '^/\*[*!]'
- regex: "```"
ignores:
- generated/**
32 changes: 32 additions & 0 deletions config/taplo/no-path-deps.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Workspace member Cargo.toml — no path dependencies",
"description": "Forbids `path = ...` deps outside workspace root; `const` is a hack so taplo prints it as the error.",
"definitions": {
"depTable": {
"type": "object",
"additionalProperties": {
"properties": {
"path": {
"const": "forbidden outside workspace root; declare in [workspace.dependencies] and use `.workspace = true`"
}
}
}
}
},
"type": "object",
"patternProperties": {
"^(dev-|build-)?dependencies$": { "$ref": "#/definitions/depTable" }
},
"properties": {
"target": {
"type": "object",
"additionalProperties": {
"type": "object",
"patternProperties": {
"^(dev-|build-)?dependencies$": { "$ref": "#/definitions/depTable" }
}
}
}
}
}
10 changes: 8 additions & 2 deletions libs/edge-toolkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ edition.workspace = true
license.workspace = true
repository.workspace = true

[lib]
doctest = false

[dependencies]
base64.workspace = true
lets_find_up.workspace = true
Expand All @@ -21,6 +24,9 @@ thiserror.workspace = true

[dev-dependencies]
rstest.workspace = true
temp-env = "0.3"
temp-env.workspace = true
tempfile.workspace = true
testing_logger = "0.1"
testing_logger.workspace = true

[lints]
workspace = true
10 changes: 7 additions & 3 deletions libs/edge-toolkit/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
/// which may happen if the invoking environment is not similar to a "std" environment.
#[must_use]
pub fn executable_name() -> String {
executable_name_inner(std::env::args().collect())
executable_name_inner(&std::env::args().collect::<Vec<_>>())
}

#[expect(clippy::unwrap_used)]
pub fn executable_name_inner(args: Vec<String>) -> String {
#[must_use]
#[expect(
clippy::unwrap_used,
reason = "argv[0] and file_stem are guaranteed under a std environment"
)]
pub fn executable_name_inner(args: &[String]) -> String {
let path = args.first().unwrap();
let path = std::path::PathBuf::from(path);
path.file_stem().unwrap().to_string_lossy().to_string()
Expand Down
11 changes: 6 additions & 5 deletions libs/edge-toolkit/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use base64::{Engine, engine::general_purpose::STANDARD as b64standard};
use secrecy::{ExposeSecret, SecretString};
use base64::{Engine as _, engine::general_purpose::STANDARD as b64standard};
use secrecy::{ExposeSecret as _, SecretString};
use serde::Deserialize;

#[derive(Clone, Debug, Deserialize)]
#[non_exhaustive]
/// Basic Authentication config.
pub struct BasicAuth {
/// Username.
Expand All @@ -14,17 +15,17 @@ pub struct BasicAuth {
impl BasicAuth {
/// Create a new `BasicAuth` instance.
#[must_use]
pub fn new(username: String, password: SecretString) -> Self {
pub const fn new(username: String, password: SecretString) -> Self {
Self { username, password }
}

/// Add authorisation header to HashMap.
/// Add authorisation header to `HashMap`.
pub fn add_basic_auth_header(&self, headers: &mut std::collections::HashMap<String, String>) {
let mut buf = String::default();
b64standard.encode_string(
format!("{}:{}", self.username, self.password.expose_secret()).as_bytes(),
&mut buf,
);
headers.insert("authorization".to_string(), format!("Basic {buf}"));
let _previous = headers.insert("authorization".to_string(), format!("Basic {buf}"));
}
}
Loading
Loading