Two resource-exhaustion fixes from Opus Rust + Sonnet Rust audits. 1. kei-cortex per_user_locks DashMap unbounded growth (HIGH) File: kei-cortex/src/state.rs Bug: per_user_locks: DashMap<String, Arc<Mutex<()>>> inserted on every distinct user_id; never evicted. Auth'd attacker with 1M unique user_ids could OOM the daemon (~150 bytes/entry = 15GB at 100M entries). Fix: replaced DashMap with tokio::sync::Mutex<LruCache<String, Arc<TokioMutex<()>>>> capped at PER_USER_LOCK_CAP = 1024. Eviction is safe because callers hold their own Arc clone for their critical section; dropping the registry slot retires only the registry's reference. Used tokio::sync::Mutex for the registry because LruCache::get mutates the recency list and requires &mut self. Constructor Pattern: state.rs split into state.rs (184 LOC) + state_factories.rs (64 LOC, new). Tests added: user_lock_evicts_past_cap (registry stays ≤1024 after 2048 inserts), user_lock_keeps_most_recent (LRU recency preserved). Existing user_lock_is_stable_per_user + user_lock_differs_per_user updated to async — sole call site (handlers/portrait.rs) gains .await. 2. kei-runtime stdout/stderr cap was post-hoc (HIGH) File: kei-runtime/src/invoke.rs Bug: wait_with_output() buffered ALL child stdout/stderr; only cap_bytes truncated AFTER the child finished. A malicious atom writing 10 GB stdout (or a buggy one looping infinitely) OOM'd the runtime BEFORE the cap fired. Fix: replaced wait_with_output() with two reader threads sharing KillHandle = Arc<Mutex<Option<Child>>>. Each reader appends bytes up to STREAM_CAP = 16 MiB; on cap exceedance the reader KILLS the child from inside the reader thread (critical — otherwise the unbounded writer would never EOF and a post-hoc kill would never fire). Both readers drain the closing pipe to EOF and return. Truncation surfaces as InvokeError::SubprocessError with explicit "exceeded N byte cap" message. Constructor Pattern: invoke.rs decomposed into invoke.rs (159 LOC) + invoke_io.rs (146 LOC, new) + invoke_error.rs (54 LOC, new). Test added: invoke_kills_runaway_atom — stages a kei-flood script running cat /dev/zero, verifies (a) non-zero exit, (b) stdout < 18 MiB, (c) "cap"/"subprocess" in stderr. cargo check --workspace: clean. cargo test -p kei-cortex -p kei-runtime --test-threads=1: 471 pass / 0 fail. Pre-existing openai_loop_wiring.rs parallel-run flake (state collision when test-threads>1) is unrelated and unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| _rust | ||
| templates | ||
| design-scrape.sh | ||
| figma-tokens.sh | ||
| frontend-inspect.sh | ||
| harden-base.sh | ||
| kei-ci-lint.sh | ||
| kei-docs-scaffold.sh | ||
| kei-doctor.sh | ||
| kei-sleep-queue.sh | ||
| kei-sleep-setup.sh | ||
| kei-sleep-sync.sh | ||
| live-preview.sh | ||
| log-ship.sh | ||
| MANIFEST.toml | ||
| metrics-scrape.sh | ||
| provision-hetzner.sh | ||
| provision-vultr.sh | ||
| README.md | ||
| screenshot-decode.sh | ||
| tomd.sh | ||
_primitives — first-class building blocks
_primitives/ holds standalone utilities that agents, hooks, and skills
(including /compose-solution) depend on. Unlike _blocks/ (behavioral
markdown) or _manifests/ (agent TOML), primitives are executable shell
programs installed at $HOME/.claude/agents/_primitives/ by install.sh.
Current primitives
| Primitive | Purpose | Invocation |
|---|---|---|
tomd.sh |
Universal non-native-format → markdown converter (PDF, DOCX, XLSX, PPTX, CSV, images, code). | ~/.claude/agents/_primitives/tomd.sh <file> |
tomd.sh is a first-class primitive. Universal non-native-format →
markdown converter with configurable cache directory
(KEISEI_TOMD_CACHE) and KeiSeiKit-style error tags ([tomd]).
Hook integration
hooks/tomd-preread.sh is a PreToolUse(Read) hook that auto-redirects
Claude to the converted markdown when a Read targets .docx / .doc / .xlsx / .pptx / .csv. Cached under $KEISEI_TOMD_CACHE (default
/tmp/keisei-tomd-cache).
/compose-solution discovery
Phase 3 prior-art sweep greps _primitives/ alongside _blocks/,
_manifests/, skills/, _bridges/, hooks/. If a user task involves
file-format parsing, the meta-composer surfaces tomd automatically —
reuse over rewrite (RULE "No Patching").