Skip to main content

max / makenotwork

11.2 KB · 279 lines History Blame Raw
1 [package]
2 name = "makenotwork"
3 version = "0.11.12"
4 edition = "2024"
5 license = "LicenseRef-PolyForm-Noncommercial-1.0.0"
6 # Server binary: never published to a registry. Marks the crate private so
7 # supply-chain tooling (cargo-deny) treats its first-party path deps correctly.
8 publish = false
9
10 [features]
11 # Cheap Argon2id parameters (8 MiB, 1 iteration) so a suite that seeds hundreds
12 # of password hashes is not spending ~600ms on each. Scoped to `auth::hash_password`
13 # and nothing else: verification reads its parameters from the hash string, so
14 # the production verifier is still what runs.
15 #
16 # It used to swap the rate-limit constants too, which meant the limiter under
17 # test was never the limiter that ships. Those are runtime config now
18 # (`constants::RateLimits`), so this feature can no longer change how the server
19 # behaves under load. Do not add anything to it that can.
20 fast-tests = []
21
22 [dependencies]
23 # Async trait (for StorageBackend trait object)
24 async-trait = "0.1"
25
26 # Web framework
27 axum = { version = "0.8.8", features = ["macros"] }
28 axum-extra = { version = "0.12.6", features = ["cookie", "form", "query", "typed-header"] }
29
30 # OpenAPI spec generation
31 utoipa = { version = "5", features = ["axum_extras", "chrono", "uuid"] }
32 utoipa-axum = "0.2"
33 utoipa-swagger-ui = { version = "9", features = ["axum"] }
34 serde = { version = "1.0.228", features = ["derive"] }
35 serde_json = "1.0.149"
36 toml = "1.1"
37 # `process` is used directly (git_ssh, build_runner). It was previously arriving
38 # only by feature unification through an S3 dependency, so it belongs here.
39 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread", "net", "signal", "process"] }
40 tokio-stream = { version = "0.1", features = ["sync"] }
41 tokio-util = { version = "0.7", features = ["io"] }
42 tower = "0.5.3"
43 tower-http = { version = "0.7.0", features = ["trace", "fs", "limit", "request-id", "propagate-header", "set-header"] }
44 tracing = "0.1.44"
45 tracing-subscriber = { version = "0.3.22", features = ["env-filter", "json"] }
46
47 # Templates
48 askama = "0.16.0"
49
50 # Environment & Configuration
51 dotenvy = "0.15.7"
52
53 # Database
54 sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres", "uuid", "chrono", "migrate", "macros"] }
55 uuid = { version = "1.22.0", features = ["v4", "serde"] }
56 chrono = { version = "0.4.44", features = ["serde"] }
57
58 # Authentication
59 argon2 = "0.5.3"
60 tower-sessions = { version = "0.14.0", features = ["axum-core"] }
61 tower-sessions-sqlx-store = { version = "0.15.0", features = ["postgres"] }
62
63 # Concurrent hash map (session touch cache)
64 dashmap = "6"
65
66 # Rate Limiting
67 tower_governor = "0.8.0"
68 governor = "0.10.4"
69
70 # JWT (SyncKit)
71 jsonwebtoken = { version = "10.4.0", features = ["rust_crypto"] }
72
73 # TOTP / 2FA
74 totp-rs = { version = "5.7", features = ["qr"] }
75
76 # WebAuthn / Passkeys
77 # 0.6 is where webauthn-rs drops openssl for crypto-glue (RustCrypto), which is
78 # what gets openssl-sys out of the tree and off cargo-deny's ban list. Still a
79 # `-dev` prerelease upstream, so the version is pinned exactly rather than left
80 # to float. The stored `user_passkeys.credential_json` format is unchanged: a
81 # 0.5-written Passkey round-trips through 0.6 byte-identically, and 0.5 still
82 # reads what 0.6 writes, so no migration and a rollback stays open.
83 webauthn-rs = { version = "=0.6.1-dev", features = ["danger-allow-state-serialisation", "conditional-ui"] }
84 webauthn-rs-proto = "=0.6.1-dev"
85
86 # Security
87 # Direct only so `crypto::install_default_crypto_provider` can name a provider;
88 # every TLS client here reaches rustls transitively.
89 rustls = { version = "0.23", default-features = false, features = ["ring"] }
90 rand = "0.10"
91 hmac = "0.13.0"
92 sha1 = "0.11.0"
93 sha2 = "0.11.0"
94 subtle = "2.6"
95 chacha20poly1305 = "0.11.0"
96 hex = "0.4.3"
97 base64 = "0.22.1"
98 # SSHSIG verification for signed commits and tags (`git::signing`). Feature set
99 # matches `validation::users::SSH_KEY_TYPES`, the algorithms MNW accepts as
100 # account keys: there is no point verifying a signature by a key nobody could
101 # have registered. 0.6 rather than the 0.7 release candidate, and RustCrypto
102 # rather than a C library, per the crypto-provider preference.
103 ssh-key = { version = "0.6", default-features = false, features = ["alloc", "std", "ed25519", "p256", "p384", "p521", "rsa"] }
104
105 # Temp files (content export)
106 tempfile = "3"
107
108 # File scanning
109 infer = "0.22"
110 goblin = "0.10"
111 zip = "8.2"
112 # Single-stream decompressors for archive-bomb detection (already in the tree
113 # transitively via `zip`; pinned to the resolved versions so no new build).
114 flate2 = "1"
115 bzip2 = "0.6"
116 xz2 = "0.1"
117 zstd = "0.13"
118 yara-x = "1.16"
119 fs2 = "0.4"
120 memmap2 = "0.9"
121
122 # CSV parsing (import system)
123 csv = "1.3"
124
125 # CLI
126 clap = { version = "4", features = ["derive"] }
127
128 # Logging (used by sqlx slow query config)
129 log = "0.4"
130
131 # Error handling
132 thiserror = "2.0.18"
133 anyhow = "1.0.102"
134 bytes = "1"
135
136 # Email validation (used at notify-me signup and guest-checkout entry points)
137 email_address = "0.2"
138
139 # Metrics
140 metrics = "0.24"
141 metrics-exporter-prometheus = { version = "0.18.1", default-features = false }
142
143 # Markdown rendering + documentation engine
144 docengine = { git = "https://makenot.work/git/max/docengine.git", features = ["doc-loader", "directives", "frontmatter", "media-urls"] }
145 mnw-assumptions = { path = "../shared/mnw-assumptions" }
146
147 # Tag standard
148 tagtree = { path = "../shared/tagtree" }
149
150 # Shared theme palette + the bundled theme set (Tier 0 creator theming).
151 makeover = "2.4.1"
152
153 # Git source browser
154 gix = { version = "0.86", default-features = false, features = ["blame", "mailmap", "revision", "sha1", "max-performance-safe"] }
155 syntect = { version = "5", default-features = false, features = ["default-syntaxes", "default-themes", "html", "regex-fancy"] }
156 regex = "1"
157 semver = "1"
158
159 # S3 Storage
160 s3-storage = { path = "../shared/s3-storage" }
161
162 # Stripe Payments: async-stripe 1.0.0-rc.6 (split into sub-crates).
163 # The umbrella `async-stripe` provides the HTTP client; resource types live in
164 # per-domain sub-crates. The `deserialize` feature on each resource crate is
165 # required to derive `serde::Deserialize` on Subscription, Invoice, etc: we
166 # parse them from webhook payloads ourselves (no built-in webhook helper in the
167 # rc line; see `payments::webhooks::verify_signature` for our HMAC check).
168 # `default-tls` is native-tls, which drags openssl-sys in through hyper-tls;
169 # cargo-deny bans it. rustls-tls-native keeps the system trust store (matching
170 # reqwest's platform verifier elsewhere in the tree) and carries the `__hyper`
171 # feature the client needs; the provider must be named separately or
172 # async-stripe's connector.rs refuses to compile.
173 async-stripe = { version = "1.0.0-rc.6", default-features = false, features = ["rustls-tls-native", "rustls-ring"] }
174 async-stripe-shared = { version = "1.0.0-rc.6", features = ["deserialize"] }
175 async-stripe-billing = { version = "1.0.0-rc.6", features = ["deserialize", "subscription", "billing_portal_session"] }
176 async-stripe-checkout = { version = "1.0.0-rc.6", features = ["deserialize", "checkout_session"] }
177 async-stripe-connect = { version = "1.0.0-rc.6", features = ["deserialize", "account", "account_link", "transfer", "transfer_reversal"] }
178 async-stripe-core = { version = "1.0.0-rc.6", features = ["deserialize", "balance", "refund", "customer"] }
179 async-stripe-payment = { version = "1.0.0-rc.6", features = ["deserialize"] }
180 async-stripe-product = { version = "1.0.0-rc.6", features = ["deserialize", "product", "price"] }
181 async-stripe-types = { version = "1.0.0-rc.6", features = ["deserialize"] }
182 # reqwest 0.13's `rustls` feature is an alias for `__rustls-aws-lc-rs` and there
183 # is no ring counterpart, so the default feature set is what would drag the C
184 # backend back in. `rustls-no-provider` keeps the platform verifier and lets
185 # `crypto::install_default_crypto_provider` supply ring; the rest of this list is
186 # reqwest's own default set (`charset`, `http2`, `system-proxy`) restated, since
187 # naming a TLS feature means turning defaults off.
188 reqwest = { version = "0.13", default-features = false, features = [
189 "json", "cookies", "form", "query",
190 "charset", "http2", "system-proxy", "rustls-no-provider",
191 ] }
192 urlencoding = "2.1.3"
193
194 # URL parsing
195 url = "2.5.8"
196 apple-codesign = { version = "0.29.0", default-features = false }
197 authenticode = { version = "0.6.0", features = ["std", "object"] }
198 x509-cert = "0.2.5"
199 const-oid = { version = "0.9", features = ["db"] }
200 object = { version = "0.39", features = ["pe"] }
201 ammonia = "4"
202 lightningcss = { version = "1.0.0-alpha.71", default-features = false, features = ["visitor"] }
203
204 [[bin]]
205 name = "mnw-admin"
206 path = "src/bin/mnw-admin.rs"
207
208 # Writes the OpenAPI spec to openapi.json. The spec is the SyncKit wire
209 # contract and the client is in another repo, so it ships as a committed
210 # artifact rather than only as a served endpoint.
211 [[bin]]
212 name = "export-openapi"
213 path = "src/bin/export-openapi.rs"
214
215 [[bin]]
216 name = "export-operational-mail-doc"
217 path = "src/bin/export-operational-mail-doc.rs"
218
219 [build-dependencies]
220 # Emits static/geometry.css (makeover-geometry) and static/layout.css
221 # (makeover-webview). The same generator GO and BB run; only the output paths
222 # differ, since the server serves its stylesheets rather than bundling them.
223 makeover-build = "0.8.0"
224 # Read directly for SizeClass, which the breakpoint guard in build.rs compares
225 # the stylesheets against. makeover-build does not re-export it, so the pin
226 # lives here and has to track the one makeover-build resolves.
227 makeover-geometry = "0.6"
228
229 [dev-dependencies]
230 tower = { version = "0.5.3", features = ["util"] }
231 http-body-util = "0.1"
232 webauthn-authenticator-rs = { version = "=0.6.1-dev", features = ["softpasskey"] }
233 tempfile = "3"
234 proptest = "1"
235 wiremock = "0.6"
236 pom-contract = { path = "../shared/pom-contract" }
237
238 [profile.release]
239 # Drop the symbol table from the shipped binary. Release builds already carry no
240 # debuginfo, so this is purely the symbol table: measured 161.3 MiB -> 120.7 MiB
241 # on 0.10.19 (25.1%) for no runtime cost. Every tier rsyncs that difference on
242 # every promote. Nothing here reads a symbolized backtrace (no `backtrace` crate,
243 # no RUST_BACKTRACE in the unit file). If a panic ever does need symbolizing,
244 # rebuild the sha with `--config profile.release.strip=false`: the build is
245 # reproducible from the git sha the release was cut from.
246 strip = true
247
248 [lints.rust]
249 unused = "warn"
250 unreachable_pub = "warn"
251
252 [lints.clippy]
253 pedantic = { level = "warn", priority = -1 }
254 # Allow-list tuned from a measured breakdown across server/multithreaded/pter
255 # (2026-07-22). These are the high-churn / low-signal pedantic lints; everything
256 # else in `pedantic` stays a warning. Keep this block identical across repos.
257 module_name_repetitions = "allow"
258 # Doc lints. No docs-completeness push is underway.
259 missing_errors_doc = "allow"
260 missing_panics_doc = "allow"
261 doc_markdown = "allow"
262 # Numeric casts. Endemic and mostly intentional in size and byte math.
263 cast_possible_truncation = "allow"
264 cast_sign_loss = "allow"
265 cast_precision_loss = "allow"
266 cast_possible_wrap = "allow"
267 cast_lossless = "allow"
268 # Subjective structure and style nags. High churn, low signal.
269 must_use_candidate = "allow"
270 too_many_lines = "allow"
271 struct_excessive_bools = "allow"
272 similar_names = "allow"
273 items_after_statements = "allow"
274 single_match_else = "allow"
275 # Frequent false-positives in TUI and router-heavy code.
276 match_same_arms = "allow"
277 unnecessary_wraps = "allow"
278 type_complexity = "allow"
279