[workspace] resolver = "3" members = ["crates/*"] [workspace.package] edition = "2024" rust-version = "1.97.1" license = "Apache-2.0" [workspace.dependencies] memorysafe-core = { path = "crates/memorysafe-core" } memorysafe-embed = { path = "crates/memorysafe-embed" } memorysafe-backend = { path = "crates/memorysafe-backend" } memorysafe-backend-sqlite = { path = "crates/memorysafe-backend-sqlite" } memorysafe-policy = { path = "crates/memorysafe-policy" } memorysafe-auth = { path = "crates/memorysafe-auth" } memorysafe-engine = { path = "crates/memorysafe-engine" } memorysafe-mcp = { path = "crates/memorysafe-mcp" } memorysafe-api = { path = "crates/memorysafe-api" } memorysafe-cli = { path = "crates/memorysafe-cli" } memorysafe-shadow = { path = "crates/memorysafe-shadow" } rmcp = { version = "3.2.0", default-features = false, features = [ "server", "macros", "schemars", "transport-io", "transport-streamable-http-server", ] } schemars = "1.2.2" http = "1.3.1" anyhow = "1.0.104" # Not part of the plan's own workspace-dependencies diff for this task: the # task's Cargo.toml puts `tempfile.workspace = true` under # `memorysafe-mcp`'s `[dev-dependencies]`, but nothing before this task ever # added `tempfile` to `[workspace.dependencies]` (memorysafe-engine and # memorysafe-backend-sqlite each pin their own local `tempfile = "3.27.0"` # instead). Promoted here, pinned to the same version already used # workspace-wide, so `memorysafe-mcp` can resolve it the way its own # Cargo.toml is written. tempfile = "3.27.0" # Also not part of the plan's own workspace-dependencies diff, for the same # reason as `tempfile` above: `memorysafe-engine`, `memorysafe-backend` and # `memorysafe-backend-sqlite` each pin their own local `tokio = "1.53.1"` # rather than a workspace one, so nothing before this task ever added # `tokio` to `[workspace.dependencies]` -- and `memorysafe-mcp`'s own # Cargo.toml (this task's brief, verbatim) inherits it via # `tokio = { workspace = true, features = [...] }` in both # `[dependencies]` and `[dev-dependencies]`. No default features here: # every consumer already states its own feature set explicitly. tokio = { version = "1.53.1", default-features = false } serde = { version = "1.0.229", features = ["derive"] } # `float_roundtrip`: serde_json's DEFAULT float parser is a fast, non-exact # `significand as f64` times/divided-by an approximate `POW10` lookup (see # serde_json's `de.rs::f64_from_parts`), not a correctly-rounded algorithm. # For most decimals it agrees with a correctly-rounded parse, but not always # -- e.g. `0.98_f32 as f64` (bits `3fef5c2900000000`) serialises to the # exact, correctly shortest-round-tripping string "0.9800000190734863", and # the default parser reads that string back as bits `3fef5c2900000001`, one # ULP off. This is exactly the shape `memorysafe_core::FeatureMap` values # have wherever a `Reason.evidence` number started life as an `f32` policy # threshold widened `as f64` by the `features!` macro -- e.g. `NearDuplicate`'s # `threshold` evidence -- so any exact `f64` round-trip through JSON, # anywhere in this workspace, silently moved a bit without this feature. # # Set here, not on a single crate's dependency: the parser must not vary by # build scope. `memorysafe-core` owns the wire-format tests over `Decision` # and `FeatureMap` that this shape actually hits, and by this workspace's # Global Constraints `memorysafe-core` cannot depend on a backend crate, so # it cannot inherit a crate-level feature from one -- that constraint is # real and CI enforces it, via the purity job's `cargo tree` dependency # check, not a build. A crate-level override therefore unifies into a full # `cargo test --workspace` run but silently reverts to the inexact parser # under any per-crate build, `cargo test -p memorysafe-core` being the # obvious one -- which is worse than the original defect: the original was # consistently wrong, that half-fix was inconsistently right. # See `memorysafe-backend-sqlite::audit`'s module doc and # `audit::tests::evidence_shaped_by_f32_widening_survives_the_audit_round_trip_exactly` # for the reproduction this closes. serde_json = { version = "1.0.151", features = ["float_roundtrip"] } thiserror = "2.0.20" ulid = { version = "3.0.0", features = ["serde"] } time = { version = "0.3.55", features = ["serde", "macros"] } blake3 = "1.5" base64 = "0.22" subtle = "2.6.1" getrandom = "0.4.3" # Streamable-HTTP transport (Task 6): a real tower service to mount and a # real listener to bind in tests. No `macros` feature: nothing here uses # `#[axum::debug_handler]`, and enabling it would pull `axum-macros` into # `Cargo.lock` for nothing. axum = "0.8.9" # `default-features = false`, and no TLS feature enabled anywhere in this # workspace: reqwest 0.13.4 gates every TLS path behind its `__tls` feature # (`src/async_impl/client.rs`, checked against the vendored source) and # builds a plain HTTP-only connector without it — there is no # `compile_error!` guard that would force a backend choice just to compile. # Nothing here makes an HTTPS request: the reqwest client this pulls in # exists only as the transport `rmcp`'s streamable-HTTP *client* feature uses # in `memorysafe-mcp`'s tests, against a plain-HTTP loopback listener. A # consumer that does need TLS adds a backend feature (e.g. `rustls`) on its # own `[dependencies]` line; enabling one workspace-wide for a loopback test # would needlessly pull `aws-lc-sys`/`ring`/`rustls-platform-verifier` (a # cmake-plus-C build) into every build's dependency graph. reqwest = { version = "0.13.4", default-features = false } # `CancellationToken`, used by `memorysafe-mcp`'s `tests/http_transport.rs` # to drive `axum::serve(...).with_graceful_shutdown(...)` for the test # listener. Only a dev-dependency there — nothing in any crate's `src/` uses # it — but promoted to the workspace table like the other Task 6 additions # so its version is pinned in one place. tokio-util = "0.7.19" # `tower::ServiceExt::oneshot`, used by `memorysafe-api`'s test harness to # drive its `axum::Router` directly without binding a real listener. Only # `util`: nothing here needs `tower`'s load-balancing, retry, or timeout # middleware. tower = { version = "0.5.3", features = ["util"] } # `TraceLayer`, mounted on `memorysafe-api`'s router. Only `trace`: no other # tower-http middleware is used. tower-http = { version = "0.7.1", features = ["trace"] } tracing = "0.1.44" # `memorysafe-cli` (Task 11), the workspace's composition root: `msafe`'s # argument parsing (`derive`) and its `env` fallback for `--tenant`/ # `--subject`/`--namespace` (`MSAFE_TENANT` etc.), so a flag and its # environment variable are declared once, not parsed twice by hand. clap = { version = "4.6.6", features = ["derive", "env"] } # `msafe.toml` parsing/writing (`memorysafe-cli::config`). toml = "1.1.5" # `main.rs`'s stderr-only log writer, so a stray log line never corrupts the # stdout MCP-over-stdio transport a later task adds under this same binary. tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } # `memorysafe-cli`'s `tests/memory.rs`: drives the built `msafe` binary as a # subprocess rather than calling its internals directly, which is the only # way to observe real exit codes and real stdout/stderr framing. assert_cmd = "2.2.2" predicates = "3.1.4" url = "2.5.8" [workspace.lints.rust] unsafe_code = "forbid" # Denied because a property elsewhere depends on it. `memorysafe-core`'s enum # variants are all PascalCase, which is what makes every # `#[serde(rename_all = "snake_case")]` in the crate load-bearing rather than a # no-op — an attribute whose removal is undetectable because the default # already produces the asserted output is a vacuous test with no visible # defect. That property was previously enforced only by `-D warnings`, which # lives in CI and in the per-round clippy invocation and NOT in the build: a # plain `cargo test` compiled a lowercase variant with a warning. Denying it # here moves the guarantee from a habit to the build. It fires nowhere today. non_camel_case_types = "deny" [workspace.lints.clippy] all = { level = "deny", priority = -1 }