Files
keep/AGENTS.md
Andrew Phillips 0af74000d2 fix: eliminate unsafe code via nix, command-fds, and thread-local cookie
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.
2026-03-14 16:01:54 -03:00

2.6 KiB

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.

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