[package] name = "tidal-server" version = "0.1.0" edition.workspace = true rust-version.workspace = true license.workspace = true [lib] name = "tidal_server" path = "src/lib.rs" # ── tidal-crate lint posture (single source of truth) ────────────────────── # IDENTICAL block across tidaldb / tidal-net / tidal-server / tidalctl. These # crates deliberately DO NOT inherit `[workspace.lints]`; they hold the embedded # recommendation DB + its transport/server/CLI to a stricter correctness bar # (`unsafe_code = forbid`, `clippy::all = deny`, `unwrap_used = deny`). # `unwrap_used = "deny"` is kept per-crate rather than in `[workspace.lints]` # because the workspace also hosts the example/consumer crates under # `applications/` (not held to the engine's bar). Keep these four blocks BYTE-IDENTICAL. [lints.rust] unsafe_code = "forbid" [lints.clippy] all = { level = "deny", priority = -1 } pedantic = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 } # Justified allows (lossy numeric casts are pervasive + intentional in the # ranking/scoring math; module_name_repetitions is idiomatic for the flat # module layout documented in CLAUDE.md): cast_possible_truncation = "allow" module_name_repetitions = "allow" unwrap_used = "deny" [dependencies] # m11p7 hot rotation: the reloadable credential holder (bearer + cluster key) # and the inter-node HTTP TLS cert resolver swap their material lock-free under # load via `arc-swap` (already in the lock transitively; promoted to a direct # dep here). Same primitive tidal-net uses for the gRPC cert resolver. arc-swap = "1" axum = "0.8" # Snapshot-artifact manifest hashing (m11p5 §2): the leader-side # NodeSnapshotSource BLAKE3-hashes every staged file once; the puller verifies # against the manifest. Same crate + version tidaldb already uses, so no new # transitive surface. m11p7 also uses BLAKE3's keyed-hash MODE as the MAC for # per-node signed internal tokens (a foreign pod without the cluster key cannot # forge one) — no new crypto dependency. blake3 = "1" # m11p7: base64url for the signed node-token wire form; tokio-rustls serves the # inter-node HTTP listener over TLS reusing tidal-net's hot-swappable cert # resolver. Both already in the lock (base64 transitively, tokio-rustls via # tidal-net); promoted to direct deps here. base64 = "0.22" tokio-rustls = "0.26" clap = { version = "4.5", features = ["derive", "env"] } crossbeam = "0.8" # Concurrent peer fan-out for cluster broadcast / promote / status aggregation # (m8p10 task 03): `join_all` drives every peer request on the handler task, # in input order, with no per-peer detached task. `default-features = false` # keeps it to the `std` future combinators — no executor, no extra runtime. futures-util = { version = "0.3", default-features = false, features = ["std", "async-await"] } subtle = "2" tower = { version = "0.5", features = ["limit"] } tower-http = { version = "0.6", features = ["timeout", "trace", "request-id"] } serde = { version = "1", features = ["derive"] } serde_json = "1" # serde_yml is the maintained fork of the deprecated/unmaintained serde_yaml # 0.9 (RUSTSEC-2024-0320). It keeps the same `Value`/`Mapping` API, so the # schema/topology/profile parsing below is byte-for-byte behaviour-identical. serde_yml = "0.0.12" thiserror = "2" tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal", "sync"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } # utoipa 5.x derives the OpenAPI 3.1 document (ApiDoc) and per-handler path # attributes that back the unauthenticated GET /openapi.json route. JSON-only: # no swagger-ui asset bundle (that crate's vendored JS does not pass our # -D warnings posture). The `axum_extras` feature is the axum 0.8-compatible # integration surface. utoipa = { version = "5", features = ["axum_extras"] } # `metrics` is load-bearing here (not just a default): cluster mode wires the # tidaldb_cluster_* series + the /metrics listener through cfg(metrics)-gated # engine APIs, so a no-default-features consumer must still get them. tidaldb = { path = "../tidal", features = ["test-utils", "metrics"] } tidal-net = { path = "../tidal-net" } # Cross-process cluster forwarding/broadcast/reconcile + status aggregation # (m8p10 task 03) use the async reqwest client directly on the axum reactor. # `default-features = false` + rustls drops the OpenSSL/native-tls system # dependency (cleaner static build, matches the rustls posture tonic already # uses in tidal-net); `json` for the typed bodies. `blocking` is required in # production too: the `/sharded/*` scatter-gather workers are detached OS # threads (no tokio runtime) and fetch remote shards over a blocking client — # converting that pipeline to async would change the in-process behavior the # seam must preserve. reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "blocking"] } [features] cluster-e2e = [] # m11p9 chaos testing: passes through to tidaldb's WAL fault injection. The # tier-3 fault suite spawns a binary built with this; production never sets it. fault-injection = ["tidaldb/fault-injection"] [dev-dependencies] tempfile = "3" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "blocking"] } serde_json = "1" criterion = { version = "0.5", features = ["html_reports"] } # m11p7 tier-3 security tests: generate a cluster CA + per-node leaf certs (with # loopback SANs) at test time so the mTLS cluster boots over real TLS. Same crate # tidal-net's mtls.rs uses. rcgen = "0.13" [[bench]] name = "scatter" harness = false