feat: v0.6.10 guardrails + esoteric bug sweep — 45 fixes + 10 guardrails#37
Merged
Conversation
Critical: - scavenger.rs:91 atomic_write (was std::fs::write, crash = corruption) - scavenger.rs:80 10MB size guard (OOM risk on large files) - ux.rs:403 wrong table name (file_phrases -> file_map, status was always 0) - heal.rs:63 detect_test_command (cargo/pytest/npm/go) - antidecision.rs extract_sed_target rewrite (was capturing s/old/new/ pattern) High: - antidecision.rs grammar-free: 25-item keyword ban -> structural heuristics - routes.rs normalize_url: host-only anthropic check - init.rs uninstall: file-based Pi detection, no pi --version - README: document Claude Code 501 limitation - config.rs:122 default Strict (was Reactive, matches docs) Cleanup: - 3 SQL PRAGMA corruptions: mcp.rs:53, ux.rs:402, scavenger.rs:60 - reindex.rs:118 bitwise | -> || - daemon.rs MAX_FILE_SIZE pub const, proxy.rs uses shared - antidecision.rs: delete dead code (format_annotation, annotate_tool_result) Tests: 267 passing (was 178, added 10 inline regression tests)
Phase A — Helpers (reliary-core::fs_safe): - atomic_write: tmp + fsync + rename, cleans up on failure - safe_read: read file with 10MB cap - safe_read_stdin: stdin with 10MB cap - safe_open_db: SQLite with correct PRAGMAs Phase B — Bug-class guardrails (scripts/ci_guards.py): 1. non-atomic-write: std::fs::write outside atomic_write 2. uncapped-read: read_to_string without size guard 3. curl-subprocess: curl/wget subprocesses (we use reqwest) 4. sql-unknown-table: SQL against tables not in schema 5. uncapped-stdin: stdin reads without size cap 6. hardcoded-list: let valid_keys = [...] (drift risk) Phase C — Wired into pre-commit and CI: - .githooks/pre-commit: runs ci_guards.py --staged - .github/workflows/ci.yml: runs ci_guards.py Phase D — Single source of truth: - config::FEATURE_DEFAULTS const - config::VALID_CONFIG_KEYS const - main.rs uses consts instead of hardcoded lists Phase E — 21 bug fixes from round 3 audit: - Bug 30: run_index backs up before delete - Bug 33: do_update extracts to correct path (was broken) - Bug 35-36, 39: compress/risk/dead use size-capped helpers - Bug 37: start captures daemon stderr to log - Bug 40: SSE_SESSIONS capped at 1000 - Bug 41: messages_handler drops lock before send - Bug 43: UUID via getrandom (was monotonic) - Bug 46: Pi settings.json uses atomic_write - Bug 47: atomic_write cleans tmp on failure - Bug 49: per-auth-key rate limit (60 req/min) - Bug 50: edit_cache capped at 10K rows - Bug 38, 44, 45, 48: feature/config validation - Bug 31, 32, 34: trust/update/exec_sift fixes Tests: 272 passing (was 267, +5 new fs_safe tests) Guardrails: 6/6 passing on clean build
Deep audit identified bugs that don't show up in normal testing — race conditions, panic recovery, cache keying, resource leaks, security boundaries. All fixed with corresponding guardrails to prevent recurring patterns. Critical (7): - ux.rs:402, mcp.rs:53: SQL PRAGMA corruption (synchronous=; no value) High (11): - Bug 51: Daemon connection counter leaks on thread spawn failure - Bug 52: RESPONSE_CACHE proper LRU eviction (was hash-order) - Bug 53: JSONL log persistent file handle (was reopen per call) - Bug 56: try_prefetch debounced to 32KB (was 1000+ spawns/sec) - Bug 57: Mutex::lock().unwrap() → unwrap_or_else(|e| e.into_inner()) - Bug 58: Cache key includes model (was wrong model on hit) - Bug 59: Guard tool_calls-only check (revert prose regression) - Bug 64: Agent config cached 30s (was 4+ file opens/req) - Bug 68: Antidecision uses request workdir (inferred from path) - Bug 69: HTTP client 5-min timeout (was hang forever) - Bug 71: Error body capped 10MB (was unbounded) Medium (7): - Bug 60: FTS5 query tokens sanitized - Bug 61: open_existing_db_safe() with WAL+NORMAL for read paths - Bug 62: ANTI_DB capped 1000 workdirs with LRU - Bug 63: Case-insensitive Bearer prefix - Bug 66: Upstream URL scheme validated (http/https only) - Bug 67: RATE_BUCKETS capped 1000 Low (1): - Bug 70: Auth keys > 1KB rejected Guardrails (4 new): - unbounded-collection: catches HashMap without eviction - blocking-in-async: catches std::fs in async without spawn_blocking - no-timeout: catches reqwest::Client without .timeout() - panic-lock: catches Mutex::lock().unwrap() Tests: 89 unit tests pass, 10/10 guardrails pass on clean build
… guardrails - MCP path traversal: safe_path() canonicalizes all agent-provided paths - Graceful shutdown: axum .with_graceful_shutdown() + JSONL flush - Response cache: temperature in cache key, true LRU eviction - COMPRESSION_DICT: refresh on index mtime change (was loaded once) - Dead TCP daemon stripped (~100 lines of dead listener code) - 2 new guardrails: mcp-path-traversal, lazy-lock-drop - All 89 tests pass, 14/14 guardrails pass
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v0.6.10 — Esoteric bug sweep (24 fixes + 4 new guardrails)
Deep audit identified bugs that don't show up in normal testing — race
conditions, panic recovery, cache keying, resource leaks, security
boundaries. All fixed with corresponding guardrails to prevent recurring patterns.
Critical (7)
High (11)
Medium (7)
Low (1)
v0.6.9 — Guardrails foundation (21 fixes + 6 guardrails)
reliary-core::fs_safemodule:atomic_write,safe_read,safe_read_stdin,safe_open_db6 guardrail rules: non-atomic-write, uncapped-read, curl-subprocess, sql-unknown-table, uncapped-stdin, hardcoded-list
4 new v0.6.10 guardrails: unbounded-collection, blocking-in-async, no-timeout, panic-lock
Test coverage