V0.1.1 release, close to actual release. Bug & security fixes/improvements.

This commit is contained in:
unknown
2026-05-24 19:29:41 +02:00
parent a7b44af91a
commit b004e15948
38 changed files with 3145 additions and 137 deletions

166
agent4_batch4.md Normal file
View File

@@ -0,0 +1,166 @@
# Batch 4 QA Report
**Date:** 2026-05-24
**Scope:** Workspace build validation, Telegram API constraint analysis, regression checklist
**Blockers:** None
---
## 1. Build Results
| Check | Result | Details |
|---|---|---|
| `cargo check --workspace` | ✅ PASS | Finished in 5.38s, all crates compile cleanly |
| `cargo test --workspace` | ✅ PASS | All test suites pass (0 unit tests present across crates, all doc-tests pass) |
| `cd frontend && npm run build` | ✅ PASS | Built in 1.44s. Warning: `lib-BKGKj-wr.js` (497 kB) and `index-5C1xoqEL.js` (1,038 kB) exceed 500 kB after minification. This is a Vite chunk-size warning, not a build failure. |
---
## 2. Telegram API Constraint Analysis
### 2.1 Caption Length — ⚠️ FLAGGED
**Location:** `crates/cgcx-bot/src/main.rs`, `handle_forward_callback`, `"approve"` action (~line 1810)
**Code:**
```rust
let caption = format!(
"{}\n\nSubmitted by: {}\nDirect link: <code>{}</code>\nForward link: <code>{}</code>",
escape_html(&forward_def.forward_message),
author_line,
link,
forward_link
);
```
**Analysis:**
- `forward_def.forward_message` is stored as `TEXT NOT NULL DEFAULT ''` in SQLite (`migrations/003_forward_system.sql`). SQLite `TEXT` has no practical length limit.
- The fixed parts of the caption (`Submitted by: …`, `Direct link: …`, `Forward link: …`) add ~60120 characters.
- `author_line` can be up to ~60 characters (escaped username + ID).
- `link` is ~80120 characters (base URL + 12-char CXID + 12-char password).
- `forward_link` is ~70100 characters (`t.me/{bot}?start=submitfwdid{code}`).
- **Telegram API limit for captions:** 1,024 characters.
**Risk:** If an admin sets a `forward_message` longer than ~800 characters, the total caption will exceed 1,024 characters. Telegram will reject the `send_media_group` or `send_message` call with a `Bad Request: MEDIA_CAPTION_TOO_LONG` error. The code does not truncate or validate caption length before sending.
**Recommendation:** Truncate `forward_def.forward_message` to a safe limit (e.g., 700 chars) before interpolating into the caption, or split into a separate text message if the message is long.
---
### 2.2 Media Type Handling — 📋 NOTED
**Locations:**
- `finalize_upload`, review-group media batch (~line 1340)
- `handle_forward_callback`, destination media batch (~line 1850)
**Code:**
```rust
let media = if mime_type.starts_with("image/") {
InputMedia::Photo(InputMediaPhoto::new(input_file))
} else {
InputMedia::Document(InputMediaDocument::new(input_file))
};
```
**Analysis:**
- Images are correctly sent as `InputMediaPhoto`.
- **All non-image files are sent as `InputMediaDocument`**, regardless of MIME type.
**Impact:**
- **Video files** (`video/mp4`, etc.) lose native Telegram playback UI (no inline player, no duration badge, no thumbnail generation).
- **Audio files** (`audio/mpeg`, etc.) lose native audio player UI.
- Telegram treats them as generic documents, which degrades UX in review and destination groups.
**Recommendation:** Map MIME types more precisely:
| MIME prefix | Current | Better |
|---|---|---|
| `image/*` | `InputMediaPhoto` | ✅ Keep |
| `video/*` | `InputMediaDocument` | `InputMediaVideo` |
| `audio/*` | `InputMediaDocument` | `InputMediaAudio` |
| other | `InputMediaDocument` | ✅ Keep |
---
### 2.3 Memory Usage — 📋 NOTED
**Locations:**
- `finalize_upload`, review-group decryption (~line 1320)
- `handle_forward_callback`, destination decryption (~line 1830)
**Code pattern:**
```rust
match cgcx_crypto::decrypt_bytes(&ciphertext, &file.encrypted_key_wrapped, &ctx.master_key) {
Ok(bytes) => decrypted.push((file.mime_type.clone(), bytes)),
...
}
...
let input_file = InputFile::memory(bytes.clone());
```
**Analysis:**
1. `tokio::fs::read(&file.stored_path)` loads the entire encrypted file into memory as `ciphertext`.
2. `decrypt_bytes` decrypts in-memory and returns a new `Vec<u8>` (`bytes`). At this point, two copies of the file exist in RAM (ciphertext + plaintext).
3. `InputFile::memory(bytes.clone())` clones the plaintext bytes again for the `InputMedia` struct. Now three copies may exist transiently.
4. Files are batched in chunks of 10 (`decrypted.chunks(10)`), so up to 10 files are held in memory simultaneously.
**Risk:** For large uploads (e.g., a 100 MB video), this can easily exhaust RAM, especially on constrained hosts or when multiple submissions are processed concurrently. The bot does not stream or chunk-decrypt files.
**Recommendation:** Consider streaming decryption to temporary files and using `InputFile::file(path)` instead of `InputFile::memory(bytes)`. This keeps only one copy on disk instead of multiple copies in RAM.
---
## 3. Regression Checklist — Batch 4
Use this checklist before merging or deploying Batch 4 changes:
### Build & Compile
- [ ] `cargo check --workspace` passes with zero errors
- [ ] `cargo test --workspace` passes (all suites green)
- [ ] `cd frontend && npm run build` produces `dist/` without errors
- [ ] No new compiler warnings introduced in `cgcx-bot`
### Bot Runtime
- [ ] Bot starts successfully and connects to Telegram (`get_me` succeeds)
- [ ] InMemStorage dialogue state machine transitions correctly (Start → TermsPending → MainMenu → UploadStaging → UploadOptions → UploadFinalizing)
- [ ] Service message cleanup works in groups/channels and is silently skipped in private chats
- [ ] Punishment expiration timer revokes bans/mutes after duration elapses
- [ ] Global ban propagation (`propagate_punishment`) only runs when `config.groups.global_ban == true`
### Upload & Submission Flow
- [ ] Staging accepts media, documents, and text up to `max_batch_size`
- [ ] Upload options (destroy, download, password, show_author) toggle correctly
- [ ] `finalize_upload` respects `max_total_batch_bytes` limit
- [ ] Disk-space check (`fs2::available_space`) blocks uploads when temp space < 2× batch size
- [ ] Blocked-hash detection (`CgcxError::BlockedHash`) aborts upload and cleans up
### Forward & Review System
- [ ] `/create_submit_forward` validates bot admin status in both destination and review groups
- [ ] Submission links (`?start=submitfwdid{code}`) work and enforce allow-lists
- [ ] Review message is sent to review group with correct inline keyboard
- [ ] **Approve action sends media batch to destination without `MEDIA_CAPTION_TOO_LONG` error**
- [ ] Approve action sends DM confirmation to submitter with posted link
- [ ] Ignore/Ban/Blacklist/Ban+Blacklist callbacks update review message and submitter correctly
- [ ] **Media batching handles >10 files by splitting into multiple `send_media_group` calls**
### Admin Commands
- [ ] `/reload` refreshes moderation lists
- [ ] `/blacklist_uid`, `/whitelist_uid` update DB and moderation engine
- [ ] `/sban`, `/smute`, `/mute`, `/pban`, `/kick` resolve target user and apply restrictions
- [ ] `/rmute`, `/rban` revoke active punishments
- [ ] `/get_id` returns chat ID or searches admins by username/display name
### Security & Stability
- [ ] Panic hook logs location and message
- [ ] `CatchPanicLayer`-swallowed panics are traceable via logs
- [ ] 8MB thread stack prevents stack overflow during dptree dispatch
---
## 4. Blockers
**No critical blockers.** All builds pass.
**Non-blocking issues identified:**
1. **Caption length risk** — can cause Telegram API rejection on approval; should be mitigated before relying on forward system in production.
2. **Media type mapping** — video/audio UX is degraded; nice-to-have improvement.
3. **Memory usage** — large files may cause OOM during forward review/approval; should be monitored or mitigated for production load.