Replace 4 unsafe sites with safe wrappers: - libc::pipe2 → nix::unistd::pipe2 (safe OwnedFd return) - File::from_raw_fd → File::from(OwnedFd) (safe ownership transfer) - unsafe impl Send for SendCookie → thread_local! lazy Cookie (each thread gets its own independent Cookie, no Send needed) - pre_exec + libc::fcntl → command-fds crate fd_mappings() (handles CLOEXEC clearing safely, also fixes potential fd leak on spawn failure via OwnedFd RAII) Only libc::umask remains as a single unavoidable unsafe site (no safe Rust wrapper exists for the umask syscall). Also updates AGENTS.md to remove stale SendCookie exception.
56 lines
2.6 KiB
Markdown
56 lines
2.6 KiB
Markdown
# Agent Configuration
|
|
|
|
**IMPORTANT:** `xxx | keep | zzz` must be as performant as possible in all situations.
|
|
|
|
## Build/Test Commands
|
|
|
|
**IMPORTANT**: Do not run the application, start the web server, or the trunk server.
|
|
**IMPORTANT:** Cargo commands cannot be run in parallel. Prefix all commands with `TERM=dumb`.
|
|
|
|
```bash
|
|
TERM=dumb cargo check # Fast compile check
|
|
TERM=dumb cargo build # Build project
|
|
TERM=dumb cargo test # Run all tests
|
|
TERM=dumb cargo test test_name # Run specific test by name substring
|
|
TERM=dumb cargo test -- --nocapture # Verbose test output
|
|
TERM=dumb cargo fmt --check # Check formatting
|
|
TERM=dumb cargo fmt # Apply formatting
|
|
TERM=dumb cargo clippy -- -D warnings # Lint (warnings are errors)
|
|
TERM=dumb cargo build --release # Release build
|
|
TERM=dumb cargo build --features server # With server feature
|
|
```
|
|
|
|
## Code Conventions
|
|
|
|
- `anyhow::Result` for error handling; `thiserror` for custom error types (`src/services/error.rs`)
|
|
- Plugin traits: `CompressionEngine`, `FilterPlugin`, `MetaPlugin`
|
|
- Dynamic trait objects use `clone_box()` for `Clone` on `Box<dyn Trait>`
|
|
- Plugin registration uses `ctor` constructors at module load time
|
|
- Filter plugins must implement `filter()`, `clone_box()`, and `options()`
|
|
- Meta plugins extend `BaseMetaPlugin` for boilerplate reduction
|
|
- Enum string representations: `#[strum(serialize_all = "snake_case")]`
|
|
- Lint rules: `deny(clippy::all)`, `deny(unsafe_code)` (except `libc::umask` in main.rs)
|
|
- Feature flags: `default = ["magic", "lz4", "gzip"]`; optional: `server`, `swagger`
|
|
|
|
## Testing
|
|
|
|
- Tests in `src/tests/` mirroring `src/` structure; shared helpers in `src/tests/common/test_helpers.rs`
|
|
- Key helpers: `create_temp_dir()`, `create_temp_db()`, `test_compression_engine()`
|
|
- Test naming: `test_<feature>_<scenario>`
|
|
|
|
## Streaming Constraint
|
|
|
|
**At no point should the whole file be in memory at once.** All I/O must use fixed-size buffers:
|
|
|
|
- `PIPESIZE` = 8192 bytes (`src/common/mod.rs:10`)
|
|
- Server POST body streams through `save_item_raw_streaming` via `MpscReader`
|
|
- Server GET content streams via streaming reader (not `read_to_end`)
|
|
- When `max_body_size` is exceeded, return `413` but keep the partial item (nonfatal by design)
|
|
- Filter/meta plugins use `PIPESIZE`-sized buffers
|
|
|
|
## HTML Rendering
|
|
|
|
- Use `html_escape` crate for all user-controlled data in HTML pages
|
|
- `esc()` for text content, `esc_attr()` for HTML attributes
|
|
- Security headers middleware: `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: strict-origin-when-cross-origin`
|