V0.1.1 release, close to actual release. Bug & security fixes/improvements.
This commit is contained in:
125
agent4_batch5_9.md
Normal file
125
agent4_batch5_9.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Batch 5–9 QA Report
|
||||
|
||||
## Build Results
|
||||
|
||||
| Check | Result | Notes |
|
||||
|---|---|---|
|
||||
| `cargo check --workspace` | ✅ PASS | All 10 crates compile cleanly |
|
||||
| `cargo test --workspace` | ✅ PASS | 0 tests exist; 0 failures. **Note: test coverage is zero across the workspace** |
|
||||
| `cargo clippy --workspace -- -D warnings` | ✅ PASS | Fixed multiple lint issues during this run |
|
||||
| `cd frontend && npm run build` | ✅ PASS | Built in 2.67s. Chunk size warning (>500KB) is non-blocking |
|
||||
|
||||
### Lint Fixes Applied
|
||||
- `cgcx-config`: `manual_range_contains` → used `!(MIN..=MAX).contains(&chunk)`
|
||||
- `cgcx-db`: `explicit_auto_deref` → `&mut conn`; `too_many_arguments` on `ForwardRepo::insert`
|
||||
- `cgcx-file-pipeline`: `collapsible_else_if` (2×), `clone_on_copy` on `Header`
|
||||
- `cgcx-bot`: `useless_vec`, `redundant_closure` (auto-fixed), `collapsible_else_if`, `manual_strip`, `too_many_arguments` on `propagate_punishment`
|
||||
- `cgcx-server`: `redundant_closure` (auto-fixed), `collapsible_else_if` (auto-fixed), `match` equality (auto-fixed)
|
||||
|
||||
---
|
||||
|
||||
## Regression Checklist
|
||||
|
||||
### 1. Review Buttons Work (approve, ignore, ban, blacklist, ban+blacklist)
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| `[ Approve ]` callback | ✅ | `main.rs:1910` — sets password hash, forwards media to destination, DMs user, edits review message to `[ APPROVED ]` |
|
||||
| `[ Ignore ]` callback | ✅ | `main.rs:2067` — DMs user rejection, edits review message to `[ IGNORED ]` |
|
||||
| `[ Blackl. ]` callback | ✅ | `main.rs:2079` — adds user to forward blacklist, edits review message to `[ BLACKLISTED ]` |
|
||||
| `[ Ban ]` callback | ✅ | `main.rs:2087` — bans user in destination + review groups, inserts punishments, edits review message to `[ BANNED ]` |
|
||||
| `[ Ban/BL u. ]` callback | ✅ | `main.rs:2102` — bans + blacklists, edits review message to `[ BAN/BL ]` |
|
||||
| Admin permission gate | ✅ | `main.rs:1903` — checks `is_admin_in_chat` for review group before processing action |
|
||||
|
||||
**Risk:** None of these flows have unit/integration tests.
|
||||
|
||||
---
|
||||
|
||||
### 2. GLOBAL_BAN Config Propagates Punishments When True
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Config field present | ✅ | `GroupsConfig.global_ban: bool` with `default_global_ban() -> false` |
|
||||
| Propagation logic | ✅ | `propagate_punishment()` in `cgcx-bot/src/main.rs:2253` — early returns if `!global_ban` |
|
||||
| Target chats | ✅ | Admin groups + review groups + all active forward destination chats |
|
||||
| Bot admin check | ✅ | Skips chats where the bot is not an admin (`is_admin`) |
|
||||
| Supported actions | ✅ | `ban`, `mute`, `kick` with duration propagation |
|
||||
| DB recording | ✅ | Propagated punishments are inserted into `punishments` table per chat |
|
||||
|
||||
---
|
||||
|
||||
### 3. Author Visibility Toggle Works During Upload
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Upload option exists | ✅ | `UploadOptions.show_author: bool`, default `true` |
|
||||
| Bot toggle callback | ✅ | `"v1:opt:toggle_author"` → flips `show_author`, refreshes options message |
|
||||
| Stored in DB | ✅ | `contents.show_author` INTEGER NOT NULL DEFAULT 1 (migration 005) |
|
||||
| Respected in upload result | ✅ | `main.rs:1346` — `author_text` only shown when `options.show_author` is true |
|
||||
| Respected in forward post | ✅ | `main.rs:1937` — `author_line` respects `content.show_author` |
|
||||
|
||||
---
|
||||
|
||||
### 4. Metadata (date, size, author) Displays Correctly on View Page
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Date | ✅ | `new Date(metadata.created_at).toLocaleString()` in `ViewContent.svelte:121` |
|
||||
| Size | ✅ | `formatSize(metadata.total_size)` in `ViewContent.svelte:122` |
|
||||
| Author (visible) | ✅ | `metadata.author` rendered as `@username [user_id]` with Telegram link when `show_author=true` |
|
||||
| Author (hidden) | ✅ | Server returns `author: null` when `show_author=false` (`main.rs:534`) |
|
||||
| Server-side gating | ✅ | `get_metadata` only resolves `AuthorInfo` when `content.show_author` is true |
|
||||
| View count / max views | ✅ | `metadata.current_views / metadata.max_views` displayed conditionally |
|
||||
|
||||
---
|
||||
|
||||
### 5. Deduplication Reuses Existing Encrypted Files for Identical Uploads
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Hashing | ✅ | `blake3::Hasher` computes `plaintext_hash` during ingestion |
|
||||
| Reuse logic | ✅ | `FilePipeline::ingest_file` checks `find_active_by_plaintext_hash` (line 138) |
|
||||
| Ref count increment | ✅ | `increment_ref_count(&existing.content_id, existing.file_index)` called |
|
||||
| New entry created | ✅ | A new `ContentFile` row is inserted pointing to the existing `stored_path` |
|
||||
| Temp file dropped | ✅ | `drop(named_temp)` on dedup path avoids writing duplicate ciphertext |
|
||||
| Migration present | ✅ | `006_dedup.sql` adds `plaintext_hash` and `ref_count` columns |
|
||||
|
||||
---
|
||||
|
||||
### 6. Hash Blacklist Blocks Re-Uploads of Banned Content
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Blacklist table | ✅ | `hash_blacklist` table created by migration 007 |
|
||||
| Check before store | ✅ | `HashBlacklistRepo::contains(hash_bytes)` called in `ingest_file` before dedup (line 132) |
|
||||
| Error type | ✅ | Returns `CgcxError::BlockedHash` when blacklisted |
|
||||
| Moderator API | ✅ | `HashBlacklistRepo::insert(hash, reason)` available for adding entries |
|
||||
|
||||
---
|
||||
|
||||
### 7. Username Changes Are Logged to Configured JSON File
|
||||
| Item | Status | Evidence |
|
||||
|---|---|---|
|
||||
| Config path | ✅ | `Config.uname_changes_path`, default `"data/uname_changes.json"` |
|
||||
| Tracking trigger | ✅ | `UserRepo::ensure_exists` logs when `old_username != new_username` |
|
||||
| Log format | ✅ | JSON line per change: `{timestamp, user_id, old_username, new_username, chat_id}` |
|
||||
| File mode | ✅ | `OpenOptions::new().create(true).append(true)` |
|
||||
| Called on every interaction | ✅ | Bot calls `user_repo.ensure_exists(..., Some(&uname_changes_path))` on messages and callbacks |
|
||||
|
||||
---
|
||||
|
||||
## Blockers / Risks
|
||||
|
||||
1. **Zero Test Coverage**
|
||||
- No unit or integration tests exist in any crate. All verification above is static code review.
|
||||
- **Recommendation:** Add at least integration tests for `FilePipeline::ingest_file` (dedup + blacklist paths) and the server metadata/password flows.
|
||||
|
||||
2. **View Count Increment Location (Minor)**
|
||||
- `serve_file` and `serve_raw_file` both increment views. A HEAD request or 304 Not Modified response correctly skips the increment.
|
||||
- Range requests (`is_range`) also skip increment. This is intentional but worth noting.
|
||||
|
||||
3. **Chunk Size Warning (Non-blocking)**
|
||||
- Frontend build warns about a >500KB JS chunk. This is a performance consideration, not a functional blocker.
|
||||
|
||||
4. **Clippy Cleanliness**
|
||||
- Workspace now passes `clippy -- -D warnings`. This was not true before this QA run.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
All requested features (review buttons, GLOBAL_BAN propagation, author toggle, metadata display, deduplication, hash blacklist, username tracking) are **implemented and appear correct** based on static analysis. The workspace compiles, tests pass (trivially), clippy is clean, and the frontend builds successfully. The primary risk is the complete absence of automated tests.
|
||||
Reference in New Issue
Block a user