Skip to main content

max / goingson

Add code fuzz findings doc, update audit and mobile todo - Add docs/flaws.md documenting all 37 findings from 2026-04-24 fuzz - Mark sync_service SQL safety doc comment as done in audit_review - Check off App ID registration in mobile todo Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-04-26 19:40 UTC
Commit: df750bc25d7df949c3b63a2424bc2cbecfad03b6
Parent: 47cb825
3 files changed, +141 insertions, -2 deletions
@@ -142,7 +142,7 @@ Outstanding work tracked in `docs/todo/todo.md`.
142 142 2. ~~**[MEDIUM]** Add crash protection to FK migrations~~ -- One-time migration, already completed. Non-issue.
143 143 3. ~~**[MEDIUM]** Add indexes for newer query patterns~~ -- Done (migration 040).
144 144 4. ~~**[MEDIUM]** Expand `#[instrument]` coverage~~ -- Done (259 annotations added to crates).
145 - 5. Add doc comment to sync_service.rs explaining format!() SQL safety pattern
145 + 5. ~~Add doc comment to sync_service.rs explaining format!() SQL safety pattern~~ -- Already done (mod.rs + apply.rs).
146 146
147 147 ### All resolved (previous audits)
148 148 - ~~Wire up `Validate::validate()` in command layer~~ -- Done
A docs/flaws.md +139
@@ -0,0 +1,139 @@
1 + # Flaws
2 +
3 + Code fuzz of GoingsOn, 2026-04-24. All 37 findings fixed.
4 +
5 + ## Serious
6 +
7 + ### 1. `truncate_text` panics on multi-byte UTF-8 -- FIXED
8 + - **File**: `src-tauri/src/notifications.rs`
9 + - Uses `char_indices()` to find last valid char boundary.
10 +
11 + ### 2. Push marks unpushed changelog entries as pushed -- FIXED
12 + - **File**: `src-tauri/src/sync_service/push.rs`
13 + - Tracks actual pushed IDs; UPDATE only those.
14 +
15 + ### 3. Backup restore creates dangling FK references -- FIXED
16 + - **File**: `crates/core/src/backup_restore.rs`
17 + - Builds old-to-new ID map during project restore; remaps `project_id` on tasks and events.
18 +
19 + ### 4. OAuth callback `code` not URL-decoded -- FIXED
20 + - **File**: `src-tauri/src/oauth/callback_server.rs`
21 + - URL-decodes `code` and `state`. Also fixed URL decoder for multi-byte UTF-8.
22 +
23 + ### 5. OAuth callback buffer too small -- FIXED
24 + - **File**: `src-tauri/src/oauth/callback_server.rs`
25 + - Buffer increased to 16 KB.
26 +
27 + ### 6. `UnifiedEmail` discards `is_read` flag -- FIXED
28 + - **File**: `src-tauri/src/email/provider.rs`
29 + - Uses `email.is_read`.
30 +
31 + ### 7. Negative urgency bonus for future `created_at` -- FIXED
32 + - **File**: `crates/core/src/urgency.rs`
33 + - Clamped `age_days` to `max(0.0)`.
34 +
35 + ### 8. "This week" boundary inconsistency -- FIXED
36 + - **File**: `crates/db-sqlite/src/repository/search_repo.rs`
37 + - SQL uses `weekday 1` (next Monday) with `<`, matching Rust's "through Sunday" boundary.
38 +
39 + ### 9. LIKE wildcard injection in tag search -- FIXED
40 + - **Files**: `search_repo.rs`, `contact_repo.rs`
41 + - Added `escape_like()` helper; applied to all 3 LIKE patterns with `ESCAPE '\'`.
42 +
43 + ### 10. Quick-add parser accepts negative relative dates -- FIXED
44 + - **File**: `crates/core/src/parser.rs`
45 + - Rejects `num < 1` in `parse_relative_date`.
46 +
47 + ## Minor
48 +
49 + ### 11. Plugin `read_file` has no size limit -- FIXED
50 + - **File**: `crates/plugin-runtime/src/api.rs`
51 + - Checks `fs::metadata` size; rejects files over 10 MB.
52 +
53 + ### 12. Plugin context not cleared on error -- FIXED
54 + - **File**: `crates/plugin-runtime/src/registry.rs`
55 + - RAII `ContextGuard` ensures cleanup on all paths.
56 +
57 + ### 13. IMAP UID overflow -- FIXED
58 + - **File**: `src-tauri/src/email/imap_client.rs`
59 + - Uses `saturating_add(1)`.
60 +
61 + ### 14. Invalid UID 0 fallback -- FIXED
62 + - **File**: `src-tauri/src/email/imap_client.rs`
63 + - Skips emails with no UID.
64 +
65 + ### 15. Search LIMIT overflow -- FIXED
66 + - **File**: `crates/db-sqlite/src/repository/search_repo.rs`
67 + - Uses `saturating_add()`.
68 +
69 + ### 16. iCal import drops timezone data -- FIXED
70 + - **File**: `src-tauri/src/external_sync/ical.rs`
71 + - Added `chrono-tz`. Resolves IANA timezone names and converts local time to UTC.
72 +
73 + ### 17. vCard quoted-printable decoder produces mojibake -- FIXED
74 + - **File**: `src-tauri/src/external_sync/vcard.rs`
75 + - Collects into `Vec<u8>`, then `String::from_utf8_lossy`.
76 +
77 + ### 18. CSV export: no formula injection protection -- FIXED
78 + - **File**: `src-tauri/src/export/csv.rs`
79 + - `sanitize_csv_field` prepends `'` to cells starting with formula characters.
80 +
81 + ### 19. Backup restore: no decompression size limit -- FIXED
82 + - **File**: `src-tauri/src/export/backup.rs`
83 + - Uses `Read::take(500 MB)`.
84 +
85 + ### 20. No file size limit on vCard/ICS import -- FIXED
86 + - **File**: `src-tauri/src/commands/import_external.rs`
87 + - `read_import_file()` rejects files over 50 MB.
88 +
89 + ### 21. Monthly recurrence day drift -- FIXED
90 + - **File**: `crates/core/src/recurrence.rs`
91 + - End-of-month heuristic targets day 31 for months that ended on their last day. Added `calculate_next_due_with_day()` for explicit control. Also fixed `add_months` to use `rem_euclid` for correctness with negative months.
92 +
93 + ### 22. Negative duration in day planning -- FIXED
94 + - **File**: `src-tauri/src/commands/day_planning.rs`
95 + - Clamps duration to `max(1)`.
96 +
97 + ## Notes
98 +
99 + ### 23. Custom URL decoder mojibake -- FIXED (with #4)
100 + ### 24. IMAP folder name not sanitized for CRLF -- FIXED
101 + - Control character validation on `archive_folder_name` in create/update email account commands.
102 +
103 + ### 25. Predictable temp filename for email preview -- FIXED
104 + - Added UUID v4 random suffix to temp filename.
105 +
106 + ### 26. Dedup DB error swallowed -- FIXED
107 + - Changed `unwrap_or_default()` to `?`.
108 +
109 + ### 27. Sync `total_applied` overcounts -- FIXED
110 + - Counts only `clean` + `resolved_entries` actually applied.
111 +
112 + ### 28. Silent fallback on malformed saved view filters -- FIXED
113 + - Added `tracing::warn!` on deserialization failure.
114 +
115 + ### 29. TOCTOU in task snooze -- FIXED
116 + - Atomic `AND status NOT IN (...)` in UPDATE WHERE clause.
117 +
118 + ### 30. `time_progress()` returns 0-255, documented as 0-100 -- FIXED
119 + - Changed `.min(255.0)` to `.min(100.0)`.
120 +
121 + ### 31. Negative plugin progress wraps to usize::MAX -- FIXED
122 + - Clamps negative values to 0 before cast.
123 +
124 + ### 32. `sort_by` parsing breaks on quotes -- FIXED
125 + - Uses `serde_json::Value::String` instead of manual quote wrapping.
126 +
127 + ### 33. `strip_html` leaves unclosed script/style content -- FIXED
128 + - Truncates from unclosed tag to end of string.
129 +
130 + ### 34. Import sub-collection errors silently discarded -- FIXED
131 + - Replaced `let _ =` with `if let Err(e)` and `tracing::warn!`.
132 +
133 + ### 35. `add_months` uses `%` instead of `rem_euclid` -- FIXED (with #21)
134 +
135 + ### 36. JMAP client silently falls back to no-timeout client -- FIXED
136 + - Changed `unwrap_or_default()` to `expect()`.
137 +
138 + ### 37. `delete_backup` doesn't validate file extension -- FIXED
139 + - Added `.json.gz` extension check before deletion.
@@ -36,7 +36,7 @@ Done: Phases 1-7 (CSS, touch, navigation, views, build config, tab bar, distribu
36 36 ./dist/release-ios.sh --upload-only # export + upload existing archive
37 37 ```
38 38 - [ ] Accept PLA at developer.apple.com/account
39 - - [ ] Register App ID for `com.goingson.app` (Certificates, Identifiers & Profiles)
39 + - [x] Register App ID for `com.goingson.app` (Certificates, Identifiers & Profiles)
40 40 - [ ] App Store Connect: create app record (name: GoingsOn, SKU: goingson)
41 41 - [ ] Upload to TestFlight via `dist/release-ios.sh`
42 42 - [ ] Add beta testers