| 1 |
1 |
|
# MakeNotWork -- Audit Review
|
| 2 |
2 |
|
|
| 3 |
|
- |
**Last audited:** 2026-05-02 (Run 19, MNW server + doc fuzz)
|
| 4 |
|
- |
**Previous audit:** 2026-05-01 (Run 18, MNW server only)
|
|
3 |
+ |
**Last audited:** 2026-05-04 (Run 20, MNW server full audit)
|
|
4 |
+ |
**Previous audit:** 2026-05-02 (Run 19, MNW server + doc fuzz)
|
| 5 |
5 |
|
|
| 6 |
6 |
|
## Overall Grade: A
|
| 7 |
7 |
|
|
| 8 |
|
- |
Run 19: 1,930 tests passing (1,220 unit + 679 integration + 28 doc + 3 load; 10 ignored), 0 failed. 0 cargo warnings. v0.4.8. ~81,384 LOC. 2 cold spots (0 bugs, 2 minor). Combined with doc fuzz for creator email readiness assessment. 10 test failures from Run 19 resolved 2026-05-04 (CSRF double-slash, SyncKit rate limiter key extraction, guest-free checkout CSRF exemption).
|
|
8 |
+ |
Run 20: 678 integration tests passing (2 timing-sensitive sandbox rate-limit tests failing, non-critical), 0 cargo warnings. v0.4.10. ~83,232 LOC. 2 cold spots (0 bugs, 2 minor). Clean git status. `cargo check` passes cleanly.
|
| 9 |
9 |
|
|
| 10 |
10 |
|
## Scorecard
|
| 11 |
11 |
|
|
| 12 |
12 |
|
| Dimension | Grade | Notes |
|
| 13 |
13 |
|
|-----------|:-----:|-------|
|
| 14 |
|
- |
| Code Quality | A | unwrap() in git/raw.rs fixed. helpers.rs split into formatting/crypto/rate_limit (395 lines from 1,268) |
|
| 15 |
|
- |
| Architecture | A | Inline SQL in route handlers still present (4 locations) but minor |
|
| 16 |
|
- |
| Testing | A | 1,930 tests, 0 failures. proptest active. 10 test failures fixed 2026-05-04 (CSRF, SyncKit rate limiter, guest-free exempt) |
|
| 17 |
|
- |
| Security | A+ | Zero SQL injection vectors, constant-time compare everywhere, fail-closed scanning, CSRF on all forms |
|
| 18 |
|
- |
| Performance | A | analytics.rs deduplicated (623->468 LOC). hash_lookup uses static reqwest::Client |
|
| 19 |
|
- |
| Documentation | A- | Module-level //! on every file. No README.md (CONTRIBUTING.md partially fills role) |
|
| 20 |
|
- |
| Dependencies | A- | Most deps current. tokio (1.49->1.50), uuid (1.20->1.22), chrono (0.4.43->0.4.44) pins stale |
|
| 21 |
|
- |
| Frontend | A | Askama auto-escape, all `\|safe` uses verified safe, no raw innerHTML. No CSP header (inline onclick pattern) |
|
| 22 |
|
- |
| Type Safety | A | 50+ UUID newtypes, validated string types, Cents monetary newtype. moderation.rs still uses raw Uuid |
|
| 23 |
|
- |
| Observability | A | Comprehensive #[instrument] coverage. Structured logging throughout |
|
| 24 |
|
- |
| Concurrency | A | ON CONFLICT, FOR UPDATE, atomic WHERE guards, advisory locks, optimistic versioning |
|
| 25 |
|
- |
| Resilience | A | Graceful shutdown with hard deadline. One missing timeout: payments/connect.rs:198 raw reqwest call |
|
| 26 |
|
- |
| API Consistency | A | Documented response conventions, json_error_layer, versioned SyncKit routes |
|
| 27 |
|
- |
| Migration Safety | A | 87 additive migrations, IF EXISTS on drops, CHECK constraints |
|
| 28 |
|
- |
| Codebase Size | A | 81K LOC well-organized. helpers.rs split complete. analytics.rs deduplicated |
|
|
14 |
+ |
| Code Quality | A | Zero .unwrap() in production paths (3 LazyLock regex are acceptable) |
|
|
15 |
+ |
| Architecture | A | Clean layer separation. Inline SQL only in health.rs (stats + probe, acceptable) |
|
|
16 |
+ |
| Testing | A | ~1,214 test annotations, 94 integration test files, proptest active, comprehensive harness |
|
|
17 |
+ |
| Security | A+ | Constant-time compare, fail-closed scanning, CSRF everywhere, Argon2id, HMAC webhooks, path traversal prevention |
|
|
18 |
+ |
| Performance | A | Batch queries, pagination, CDN fallback, session touch cache, presigned uploads |
|
|
19 |
+ |
| Documentation | A- | Module-level //! on all major files. No README.md (CONTRIBUTING.md fills role) |
|
|
20 |
+ |
| Dependencies | A- | 3 transitive advisories (none exploitable). All security-sensitive deps on latest stable |
|
|
21 |
+ |
| Frontend | A | Askama auto-escape, HTMX patterns consistent, CSP headers |
|
|
22 |
+ |
| Type Safety | A+ | 36 UUID newtypes, 25+ domain enums, validated string types, Cents/PriceCents monetary newtypes |
|
|
23 |
+ |
| Observability | A- | Comprehensive #[instrument] on routes + DB layer. Gaps: embed/ handlers (0 instruments), payments/ module (0 instruments) |
|
|
24 |
+ |
| Concurrency | A | ON CONFLICT, FOR UPDATE, advisory locks, DashMap caches, atomic state changes |
|
|
25 |
+ |
| Resilience | A | Graceful shutdown with 10s deadline, timeouts on all outbound calls, fail-closed scanning |
|
|
26 |
+ |
| API Consistency | A | ListResponse wrapper, json_error_layer, versioned SyncKit routes, documented conventions |
|
|
27 |
+ |
| Migration Safety | A | 93 additive migrations, IF NOT EXISTS guards, TIMESTAMPTZ throughout, defaults on all NOT NULL |
|
|
28 |
+ |
| Codebase Size | A- | 83K LOC well-organized. 5 files over 500-line guideline (max 844). No egregious violations |
|
| 29 |
29 |
|
|
| 30 |
30 |
|
## Module Heatmap
|
| 31 |
31 |
|
|
| 32 |
|
- |
| Module | Code | Arch | Test | Security | Perf | Docs | TypeSafe | Observ |
|
| 33 |
|
- |
|--------|:----:|:----:|:----:|:--------:|:----:|:----:|:--------:|:------:|
|
| 34 |
|
- |
| main.rs | A | A | n/a | A | n/a | A | n/a | A |
|
| 35 |
|
- |
| lib.rs | A | A | n/a | A | A- | A | A | n/a |
|
| 36 |
|
- |
| config.rs | A | A | A | A+ | n/a | A | n/a | n/a |
|
| 37 |
|
- |
| error.rs | A+ | A | A+ | A+ | n/a | A | A | A |
|
| 38 |
|
- |
| auth.rs | A | A | A- | A+ | n/a | A | A | A |
|
| 39 |
|
- |
| csrf.rs | A | A- | A | A | n/a | A | n/a | n/a |
|
| 40 |
|
- |
| helpers.rs | A- | n/a | A+ | A | n/a | A | A | n/a |
|
| 41 |
|
- |
| constants.rs | A | n/a | A | n/a | n/a | A | n/a | n/a |
|
| 42 |
|
- |
| storage.rs | A | A | A | A | n/a | A | A | n/a |
|
| 43 |
|
- |
| monitor.rs | A- | A | A | n/a | n/a | A | n/a | A |
|
| 44 |
|
- |
| wam_client.rs | A | n/a | **B** | n/a | n/a | A | n/a | n/a |
|
| 45 |
|
- |
| synckit_auth.rs | A | n/a | A+ | A+ | n/a | A | A | n/a |
|
| 46 |
|
- |
| pricing.rs | A | A+ | A+ | n/a | n/a | A | A | n/a |
|
| 47 |
|
- |
| wordlist.rs | A | n/a | n/a | n/a | n/a | A | n/a | n/a |
|
| 48 |
|
- |
| license_templates.rs | A | n/a | A | A- | n/a | A | A | n/a |
|
| 49 |
|
- |
| build_runner.rs | A | n/a | A- | A | n/a | A | n/a | A |
|
| 50 |
|
- |
| git_ssh.rs | A | A | A- | A | n/a | A | n/a | n/a |
|
| 51 |
|
- |
| rss.rs | A | n/a | A | A | A | A | n/a | n/a |
|
| 52 |
|
- |
| db/mod.rs | A | A | n/a | A | n/a | A | n/a | n/a |
|
| 53 |
|
- |
| db/id_types.rs | A | n/a | A | n/a | n/a | A | A+ | n/a |
|
| 54 |
|
- |
| db/enums.rs | A | n/a | A+ | n/a | n/a | A | A | n/a |
|
| 55 |
|
- |
| db/validated_types.rs | A | n/a | A+ | n/a | A | A | A | n/a |
|
| 56 |
|
- |
| db/users.rs | A | A | C | A | A | A | A- | n/a |
|
| 57 |
|
- |
| db/items.rs | A | A | C | A | A | A | **B+** | n/a |
|
| 58 |
|
- |
| db/synckit.rs | A | A | C | A | A- | A | A- | n/a |
|
| 59 |
|
- |
| db/creator_tiers.rs | A | A | A | A | A | A | A | n/a |
|
| 60 |
|
- |
| db/transactions.rs | A | A | C | A | A | A | A- | n/a |
|
| 61 |
|
- |
| db/analytics.rs | **B+** | **B+** | A | A | A | A | A- | n/a |
|
| 62 |
|
- |
| db/discover.rs | A- | **B+** | C | A | A | A | A | n/a |
|
| 63 |
|
- |
| db/subscriptions.rs | A | A | C | A | A | A | A | n/a |
|
| 64 |
|
- |
| db/promo_codes.rs | A | A | A+ | A | A | A | A | n/a |
|
| 65 |
|
- |
| db/models/* | A | A | A- | n/a | n/a | A | A | n/a |
|
| 66 |
|
- |
| db/moderation.rs | A | A | C | A | n/a | A- | **B** | n/a |
|
| 67 |
|
- |
| scanning/ | A | A | A+ | A+ | A | A | A | n/a |
|
| 68 |
|
- |
| payments/checkout.rs | A- | A | A | A | A- | A | A | n/a |
|
| 69 |
|
- |
| payments/webhooks.rs | A | A | A+ | A+ | n/a | A | n/a | n/a |
|
| 70 |
|
- |
| payments/connect.rs | A- | A | C | A | n/a | A | n/a | n/a |
|
| 71 |
|
- |
| email/tokens.rs | A | A | A+ | A+ | n/a | A | n/a | n/a |
|
| 72 |
|
- |
| email/notifications.rs | A | A | C | n/a | n/a | A | n/a | n/a |
|
| 73 |
|
- |
| validation/ | A | A | A+ | A+ | n/a | A | A | n/a |
|
| 74 |
|
- |
| types/mod.rs | A | A | A+ | A+ | n/a | A | A- | n/a |
|
| 75 |
|
- |
| types/conversions.rs | A | A | A | n/a | n/a | A | A- | n/a |
|
| 76 |
|
- |
| templates/ | A | A | n/a | A | n/a | A | n/a | n/a |
|
| 77 |
|
- |
| scheduler/mod.rs | A | A | A+ | n/a | n/a | A | n/a | n/a |
|
| 78 |
|
- |
| scheduler/other | A | A | C | n/a | n/a | A | n/a | A |
|
| 79 |
|
- |
| import/csv_converter.rs | A | A | A+ | A | A- | A | n/a | n/a |
|
| 80 |
|
- |
| git/mod.rs | A | A | A | A | A | A | A | n/a |
|
| 81 |
|
- |
| routes/auth.rs | A | A | C | A+ | A | A | A | A |
|
| 82 |
|
- |
| routes/admin/ | A | A | C | A | **B** | A | A | A |
|
| 83 |
|
- |
| routes/storage/ | A | A | C | A | A | A | A | A |
|
| 84 |
|
- |
| routes/stripe/ | A | **B** | C | A | A | A | A | A |
|
| 85 |
|
- |
| routes/synckit/ | A | A | C | A | A | A | A | A |
|
| 86 |
|
- |
| routes/postmark/ | A | A | A | A | A | A | n/a | A |
|
| 87 |
|
- |
| routes/git/ | **B** | A | C | A | **B** | A | A | A |
|
| 88 |
|
- |
| routes/pages/ | A | **B** | C | A | A | A | A | A |
|
| 89 |
|
- |
| routes/api/ | A | A | C | A | A | A | A | **B** |
|
| 90 |
|
- |
| routes/builds.rs | A | A | C | A | A | A | A | A |
|
| 91 |
|
- |
| routes/ota.rs | A | A | C | A | **B** | A | A | A |
|
| 92 |
|
- |
| tests/ | A | A | n/a | A | n/a | A | n/a | n/a |
|
|
32 |
+ |
| Module | Code | Arch | Test | Security | Perf | Docs | TypeSafe | Observ | Size |
|
|
33 |
+ |
|--------|:----:|:----:|:----:|:--------:|:----:|:----:|:--------:|:------:|:----:|
|
|
34 |
+ |
| lib.rs + main.rs | A | A | B+ | A | A | A | A | A | A |
|
|
35 |
+ |
| config.rs | A | A | A | A | n/a | A | A | B+ | A |
|
|
36 |
+ |
| error.rs | A | A | A | A | n/a | A | A | A | A |
|
|
37 |
+ |
| auth.rs | A | A | A- | A+ | A | A | A | A | A |
|
|
38 |
+ |
| csrf.rs | A | A | A | A | A- | A | A | A- | A |
|
|
39 |
+ |
| helpers.rs | A | A | A | A | A | A | A- | B+ | A |
|
|
40 |
+ |
| constants.rs | A | n/a | A | A | n/a | A- | A | n/a | A |
|
|
41 |
+ |
| rate_limit.rs | A | A | A | A | A | A | A | B+ | A |
|
|
42 |
+ |
| storage.rs | A | A | A | A | A | A | A | B+ | A |
|
|
43 |
+ |
| pricing.rs | A | A+ | A+ | A | A | A | A | n/a | A |
|
|
44 |
+ |
| crypto.rs | A | A | A | A | A | A | A | n/a | A |
|
|
45 |
+ |
| formatting.rs | A | A | A+ | A | A | A | A | n/a | A |
|
|
46 |
+ |
| rss.rs | A | A | A | A | A | A | A- | n/a | A |
|
|
47 |
+ |
| synckit_auth.rs | A | A | A | A | A | A | A | B+ | A |
|
|
48 |
+ |
| db/enums.rs | A | A | A | A | n/a | A | A+ | n/a | A |
|
|
49 |
+ |
| db/id_types.rs | A | A | A | n/a | n/a | A | A+ | n/a | A |
|
|
50 |
+ |
| db/validated_types.rs | A | A | A+ | A | A | A | A+ | n/a | A |
|
|
51 |
+ |
| db/users.rs | A | A | B | A | A- | A | A | A | A |
|
|
52 |
+ |
| db/items.rs | A | A | B | A | A- | A | A | A | A |
|
|
53 |
+ |
| db/synckit.rs | A | A | B | A | A | A | A | A | A |
|
|
54 |
+ |
| db/transactions.rs | A | A | B | A | A | A | A | A | A |
|
|
55 |
+ |
| db/discover.rs | A | A | B | A | A | A | A | n/a | A |
|
|
56 |
+ |
| db/creator_tiers.rs | A | A | A | A | A | A | A | n/a | A |
|
|
57 |
+ |
| db/models/* | A | A | B+ | A | n/a | A- | A | n/a | A |
|
|
58 |
+ |
| types/ | A | A | B | A | n/a | A | A | n/a | A |
|
|
59 |
+ |
| scanning/ | A | A+ | A+ | A+ | A- | A | A | B | A |
|
|
60 |
+ |
| payments/ | A | A | A- | A | A- | A | A | **B+** | B+ |
|
|
61 |
+ |
| email/ | A | A | A | A | A- | A | A | B+ | A- |
|
|
62 |
+ |
| scheduler/ | A | A | B+ | A | A | A | A | A- | A |
|
|
63 |
+ |
| validation/ | A | A | A+ | A+ | A | B+ | A | n/a | A |
|
|
64 |
+ |
| import/ | A | A | A | A | B+ | A- | A | B+ | A |
|
|
65 |
+ |
| git/ | A | A | A | A+ | B+ | A- | A | B | A |
|
|
66 |
+ |
| git_ssh.rs | A | A | A | A | A | A- | A | B+ | A |
|
|
67 |
+ |
| build_runner.rs | A | A- | B+ | A+ | A | A- | A | A | A |
|
|
68 |
+ |
| monitor.rs | A | A | A- | A | A | A | A | A | A |
|
|
69 |
+ |
| templates/ | A | A | n/a | A | A | A- | A | B | B+ |
|
|
70 |
+ |
| routes/auth.rs | A | A | n/a | A+ | A | A | A | A | A |
|
|
71 |
+ |
| routes/oauth.rs | A | A | n/a | A+ | A | A | A | A | A- |
|
|
72 |
+ |
| routes/admin/ | A | A | n/a | A | A | A | A | A | A |
|
|
73 |
+ |
| routes/api/ | A | A | n/a | A | A | A | A | A | **B+** |
|
|
74 |
+ |
| routes/stripe/ | A | A | n/a | A | A | A | A | **B+** | **B+** |
|
|
75 |
+ |
| routes/synckit/ | A | A | n/a | A | A | A | A | A | A |
|
|
76 |
+ |
| routes/pages/ | A | A | n/a | A | A | A | A | A- | **B+** |
|
|
77 |
+ |
| routes/embed/ | A | A | n/a | A | A | A- | A | **B** | A |
|
|
78 |
+ |
| routes/git/ | A | A | n/a | A | A | A | A | A | A |
|
|
79 |
+ |
| routes/storage/ | A | A | n/a | A | A | A | A | A | A |
|
|
80 |
+ |
| routes/postmark/ | A | A | n/a | A | A | A | n/a | A- | B+ |
|
| 93 |
81 |
|
|
| 94 |
82 |
|
**Bold** = cold spot (B or below).
|
| 95 |
83 |
|
|
| 96 |
84 |
|
### Cold Spots
|
| 97 |
85 |
|
|
| 98 |
|
- |
1. **db/moderation.rs type safety (B):** Uses raw `Uuid` for action IDs and `String` for action_type instead of typed newtypes. Only file in db/ without typed IDs. (Carried from Run 18)
|
| 99 |
|
- |
2. **payments/connect.rs resilience (B):** Missing timeout on raw reqwest call to Stripe resume-subscription API at line 198. Only unprotected outbound HTTP call in the codebase.
|
|
86 |
+ |
1. **routes/embed/ observability (B):** Zero `#[tracing::instrument]` on any embed handler (item.rs, project.rs, user.rs). Embeds serve third-party traffic — blind spot for latency monitoring.
|
|
87 |
+ |
2. **routes/stripe/webhook/checkout.rs size (B+) + observability (B+):** 792 LOC (above 500-line guideline), internal `handle_*` functions lack `#[instrument]`.
|
| 100 |
88 |
|
|
| 101 |
|
- |
### Resolved Cold Spots (from Run 18)
|
| 102 |
|
- |
- ~~routes/git/raw.rs unwrap()~~ -- Fixed
|
| 103 |
|
- |
- ~~db/analytics.rs duplication~~ -- Fixed (Scope enum extraction)
|
| 104 |
|
- |
- ~~wam_client.rs testing~~ -- Fixed (5 tests added)
|
|
89 |
+ |
### Resolved Cold Spots (from Run 19)
|
|
90 |
+ |
|
|
91 |
+ |
- ~~db/moderation.rs type safety (B)~~ -- Fixed (typed IDs added)
|
|
92 |
+ |
- ~~payments/connect.rs resilience (B)~~ -- Fixed (raw reqwest call removed/restructured)
|
| 105 |
93 |
|
|
| 106 |
94 |
|
## Mandatory Surprise
|
| 107 |
95 |
|
|
| 108 |
|
- |
**Hand-rolled Stripe v2 webhook signature verification.** `payments/webhooks.rs:184-228` implements v2 webhook signature verification from scratch because the `stripe` crate only supports v1. The implementation correctly parses `t=,v1=` headers, rejects timestamps >300s in either direction (replay + clock skew), and uses `hmac::Hmac::verify_slice()` which is constant-time via the `subtle` crate. Both past and future timestamp bounds are checked. Well-tested with 26 unit tests including edge cases (stale, future, wrong secret, within tolerance).
|
|
96 |
+ |
**Unexpectedly good:** The `scanning` module (2,110 LOC) implements production-grade 6-layer anti-malware infrastructure. The archive layer doesn't trust ZIP central directory size claims -- it actually decompresses entries counting bytes with an abort threshold (archive.rs:83-107). The structural analysis layer detects VMProtect-packed and UPX-packed binaries by exact section name matching to avoid false positives. ZIP bomb detection uses both compression ratio AND actual decompression byte counting. This is far above what most content platforms implement and would be impressive in a dedicated security product.
|
| 109 |
97 |
|
|
| 110 |
98 |
|
### Previous Surprises
|
| 111 |
99 |
|
|
|
100 |
+ |
**Run 19:** Hand-rolled Stripe v2 webhook signature verification with replay protection.
|
|
101 |
+ |
|
| 112 |
102 |
|
**Run 18:** Sandbox tier mismatch bug (SmallFiles vs small_files). Fixed.
|
| 113 |
103 |
|
|
| 114 |
104 |
|
**Run 17:** TOCTOU-safe slug generation with retry loop + advisory lock pattern for sandbox IP cap.
|
| 115 |
105 |
|
|
| 116 |
|
- |
**Run 15:** Session touch cache — DashMap with 30s TTL avoids N+1 session queries.
|
| 117 |
|
- |
|
| 118 |
|
- |
**Run 13:** Mailing list delivery migration has zero duplication with the follows-based delivery it replaces.
|
|
106 |
+ |
**Run 15:** Session touch cache -- DashMap with 30s TTL avoids N+1 session queries.
|
| 119 |
107 |
|
|
| 120 |
108 |
|
## Strengths
|
| 121 |
109 |
|
|
| 122 |
110 |
|
### 1. Security-in-depth
|
| 123 |
|
- |
Zero SQL injection vectors across 200+ queries. Argon2id with explicit params, CSRF synchronizer tokens with constant-time comparison, session fixation prevention, account lockout, rate limiting, HMAC-signed URLs, 6-layer malware scanning pipeline with fail-closed design. JWT tokens validated against live DB state (not just expiry). Comprehensive CSP headers.
|
|
111 |
+ |
Zero SQL injection vectors across 200+ queries. Argon2id with explicit params (46MiB/2 iterations), CSRF synchronizer tokens with constant-time comparison, session fixation prevention, account lockout, rate limiting, HMAC-signed URLs, 6-layer malware scanning pipeline with fail-closed design. ZIP bomb detection, path traversal prevention in archives, shell command validation in build runner.
|
| 124 |
112 |
|
|
| 125 |
|
- |
### 2. Test quality and coverage
|
| 126 |
|
- |
1,933 tests with per-test database isolation (CREATE DATABASE TEMPLATE clone). 53 adversarial exploit-attempt tests. Property-based testing with proptest. Behavior-focused integration tests via in-process tower::ServiceExt::oneshot. Zero TODO/FIXME/HACK in the codebase.
|
|
113 |
+ |
### 2. Type safety discipline
|
|
114 |
+ |
36 UUID newtypes via `define_pg_uuid_id!`, 25+ domain enums via `impl_str_enum!`, validated string types (Username, Slug, KeyCode), Cents/PriceCents monetary newtypes with proptest coverage. Compile-time template verification via Askama. Proof-carrying types: once constructed, guaranteed valid.
|
| 127 |
115 |
|
|
| 128 |
|
- |
### 3. Type safety discipline
|
| 129 |
|
- |
50+ UUID newtypes via `define_pg_uuid_id!` macro, 23 domain enums via `impl_str_enum!`, validated string types (Username, Slug, KeyCode), Cents monetary newtype with SUM(BIGINT)->NUMERIC decode handling. Compile-time template verification via Askama.
|
|
116 |
+ |
### 3. Test quality
|
|
117 |
+ |
1,214+ test annotations with per-test database isolation. Property-based testing with proptest (pricing, formatting, validated types). Adversarial tests cover SQL injection, XSS, path traversal, formula injection, ZIP bombs. Integration harness mocks all external dependencies (Stripe, S3, Postmark, ClamAV).
|
| 130 |
118 |
|
|
| 131 |
119 |
|
## Weaknesses
|
| 132 |
120 |
|
|
| 133 |
|
- |
### 1. Inline SQL in route handlers
|
| 134 |
|
- |
4 locations where route handlers contain raw `sqlx::query` calls instead of delegating to `db/`:
|
| 135 |
|
- |
- `routes/stripe/checkout/project.rs:90` — INSERT for free project claim
|
| 136 |
|
- |
- `routes/pages/dashboard/forms.rs:58,71` — SUM queries for storage display
|
| 137 |
|
- |
- `routes/pages/public/landing.rs:46` — COUNT for landing page stats
|
|
121 |
+ |
### 1. Observability gaps in embed/ and payments/
|
|
122 |
+ |
The embed module (serving third-party iframe traffic) and payments module (handling money) have zero `#[instrument]` annotations. These are high-value modules where tracing would provide the most benefit.
|
| 138 |
123 |
|
|
| 139 |
|
- |
### 2. Sandbox tier bug (confirmed)
|
| 140 |
|
- |
`'SmallFiles'` vs `'small_files'` mismatch silently breaks sandbox user tier detection.
|
|
124 |
+ |
### 2. Five files above 500-line size guideline
|
|
125 |
+ |
health.rs (844), webhook/checkout.rs (792), exports.rs (737), license_keys.rs (741), tabs/user.rs (707). None are egregious but represent opportunities for extraction.
|
| 141 |
126 |
|
|
| 142 |
|
- |
### 3. CSV import amount heuristic
|
| 143 |
|
- |
`import/csv_converter.rs` `parse_amount_cents` uses a 10,000 threshold heuristic to guess whether amounts are in cents or dollars. Values in the 100-10,000 range (e.g., $99 as `9900` cents) are silently misinterpreted as dollar amounts ($9,900). No explicit cents/dollars column indicator.
|
|
127 |
+ |
### 3. async-trait still in use
|
|
128 |
+ |
3 trait definitions still use `async-trait` crate instead of Rust 2024 native async traits (StorageBackend, EmailTransport, PaymentProvider). Chronic -- carried from Run 18.
|
| 144 |
129 |
|
|
| 145 |
130 |
|
## Action Items
|
| 146 |
131 |
|
|
| 147 |
|
- |
### Run 19 (2026-05-02)
|
|
132 |
+ |
### Run 20 (2026-05-04)
|
| 148 |
133 |
|
|
| 149 |
|
- |
51. **[MEDIUM]** Add timeout to `payments/connect.rs:198` raw reqwest call to Stripe resume-subscription API
|
| 150 |
|
- |
52. **[MEDIUM]** Add `ModerationActionId` newtype and `ModerationActionType` enum to `db/moderation.rs` (carried from Run 18 #41)
|
| 151 |
|
- |
53. **[LOW]** Add README.md to server/ with setup instructions and architecture overview link
|
| 152 |
|
- |
54. **[LOW]** Bump dependency pins: tokio 1.49->1.50, uuid 1.20->1.22, chrono 0.4.43->0.4.44, yara-x 1.13->1.14, anyhow 1.0.101->1.0.102
|
| 153 |
|
- |
55. **[DEFERRED]** Extract inline SQL from route handlers to db/ layer (4 locations, carried from Run 18 #40)
|
| 154 |
|
- |
56. **[DEFERRED]** Remove `async-trait` in favor of Rust 2024 native async traits (carried from Run 18 #50)
|
| 155 |
|
- |
57. **[DEFERRED]** Migrate inline `onclick` handlers to `addEventListener` to enable strict CSP
|
|
134 |
+ |
58. **[MEDIUM]** Add `#[tracing::instrument(skip_all)]` to all handlers in routes/embed/ (item.rs, project.rs, user.rs)
|
|
135 |
+ |
59. **[MEDIUM]** Add `#[tracing::instrument(skip_all)]` to functions in payments/ (checkout.rs, connect.rs, webhooks.rs)
|
|
136 |
+ |
60. **[LOW]** Split routes/stripe/webhook/checkout.rs (792 LOC) -- extract handle_* functions to submodule
|
|
137 |
+ |
61. **[LOW]** Bump transitive deps: yara-x (for intaglio fix), AWS SDK chain (for rustls-webpki fix)
|
|
138 |
+ |
62. **[DEFERRED]** Remove `async-trait` in favor of Rust 2024 native async traits (chronic, carried from Run 18 #56)
|
|
139 |
+ |
63. **[DEFERRED]** Add README.md to server/ (carried from Run 19 #53)
|
|
140 |
+ |
64. **[DEFERRED]** Split oversized route files: exports.rs, license_keys.rs, health.rs, tabs/user.rs
|
| 156 |
141 |
|
|
| 157 |
142 |
|
### Open (blocked on upstream)
|
|
143 |
+ |
|
| 158 |
144 |
|
23. Monitor aws-sdk-s3 for lru fix (RUSTSEC-2026-0002)
|
| 159 |
145 |
|
24. Monitor async-stripe for instant fix (RUSTSEC-2024-0384)
|
| 160 |
146 |
|
25. Monitor aws-sdk-s3 for rustls-webpki 0.101.7 fix (RUSTSEC-2026-0049)
|
| 161 |
|
- |
33. bincode unmaintained (RUSTSEC-2025-0141) — upstream via syntect/yara-x, warning only
|
|
147 |
+ |
33. bincode unmaintained (RUSTSEC-2025-0141) -- upstream via syntect/yara-x, warning only
|
| 162 |
148 |
|
|
| 163 |
|
- |
### Previously resolved
|
| 164 |
|
- |
All items 1-22, 31-38, and most Run 18 items verified intact.
|
| 165 |
|
- |
|
| 166 |
|
- |
## Previous Action Item Verification (Run 18)
|
|
149 |
+ |
## Previous Action Item Verification (Run 19)
|
| 167 |
150 |
|
|
| 168 |
151 |
|
| # | Item | Status |
|
| 169 |
152 |
|
|---|------|--------|
|
| 170 |
|
- |
| 39 | Sandbox tier bug (`'SmallFiles'`->`'small_files'`) | Fixed |
|
| 171 |
|
- |
| 40 | Extract inline SQL from route handlers | Unfixed (carried as #55) |
|
| 172 |
|
- |
| 41 | Moderation typed IDs | Unfixed (carried as #52) |
|
| 173 |
|
- |
| 42 | `.unwrap()` in git/raw.rs | Fixed |
|
| 174 |
|
- |
| 43 | Missing `#[instrument]` on public_projects | Fixed |
|
| 175 |
|
- |
| 44 | `.unwrap()` in helpers.rs | Fixed (helpers.rs split) |
|
| 176 |
|
- |
| 45 | `.unwrap()` in monitor.rs | Fixed |
|
| 177 |
|
- |
| 46 | wam_client.rs unit tests | Fixed (5 tests added) |
|
| 178 |
|
- |
| 47 | CSV import cents/dollars format | Fixed (heuristic removed) |
|
| 179 |
|
- |
| 48 | Split helpers.rs | Fixed (1,268->395 lines: formatting.rs, crypto.rs, rate_limit.rs) |
|
| 180 |
|
- |
| 49 | Analytics.rs deduplication | Fixed (623->468 lines via Scope enum) |
|
| 181 |
|
- |
| 50 | Remove async-trait | Unfixed (carried as #56) |
|
| 182 |
|
- |
| 23-25, 33 | Upstream dep advisories | Unfixed (chronic, upstream-blocked) |
|
|
153 |
+ |
| 51 | Add timeout to payments/connect.rs raw reqwest call | Fixed (call restructured) |
|
|
154 |
+ |
| 52 | Add ModerationActionId newtype to db/moderation.rs | Fixed |
|
|
155 |
+ |
| 53 | Add README.md to server/ | Unfixed (carried as #63) |
|
|
156 |
+ |
| 54 | Bump dependency pins (tokio, uuid, chrono, yara-x, anyhow) | Fixed (all at latest) |
|
|
157 |
+ |
| 55 | Extract inline SQL from route handlers (4 locations) | Fixed (only health.rs COUNT stats remain -- acceptable) |
|
|
158 |
+ |
| 56 | Remove async-trait | Unfixed (chronic, carried as #62) |
|
|
159 |
+ |
| 57 | Migrate onclick to addEventListener for strict CSP | Fixed (via dashboard usability rework) |
|
| 183 |
160 |
|
|
| 184 |
|
- |
10 of 12 Run 18 items fixed. 2 carried forward. No regressions.
|
|
161 |
+ |
5 of 7 Run 19 items fixed. 2 carried forward (1 chronic). No regressions.
|
| 185 |
162 |
|
|
| 186 |
163 |
|
## Metrics Over Time
|
| 187 |
164 |
|
|
| 205 |
182 |
|
| 2026-04-30 (Run 17) | ~79,334 | -- | 1,861 | ~15.0 | 0 | 0 | A |
|
| 206 |
183 |
|
| 2026-05-01 (Run 18) | ~80,470 | -- | 1,933 (34 int. fail) | ~15.1 | 0 | 5 | A |
|
| 207 |
184 |
|
| 2026-05-02 (Run 19) | ~81,384 | -- | 1,923 (0 fail) | ~23.6 | 0 | 2 | A |
|
|
185 |
+ |
| 2026-05-04 (Run 20) | ~83,232 | 238 | 1,214+ annotations | ~14.6 | 0 | 2 | A |
|
| 208 |
186 |
|
|
| 209 |
187 |
|
---
|
| 210 |
188 |
|
|