oc5 — RED-TEAM status
Источник:
dev/fera-research/docs/oc5/STATUS.md(read-only; сгенерировано scripts/sync-docs.mjs)
oc5 — RED-TEAM status
Section titled “oc5 — RED-TEAM status”Zone: attacks on design + code of the whole Fera ecosystem.
- trust model of modules / signing
- panic isolation in native dylib (Rust panic=unwind across C ABI) + related FFI hazards
- storage encryption tiers
- offline-first edge cases
- race conditions in the actor model
- perf claims vs reality
- supply chain (git deps, submodules)
Deliverables: docs/oc5/*.md, kind problem/risk, severity, English, exact evidence paths.
Rule compliance: no file outside docs/oc5/ was created or modified. Empirical repro lives in
/tmp/opencode/oc5/repro.rs (scratch, not in any Fera repo). Every claim re-verified directly;
one path typo (dev/vera → dev/fera) and two off-by-a-few line refs were caught and fixed.
Done — 12 findings committed
Section titled “Done — 12 findings committed”| # | file | kind | sev | one-line |
|---|---|---|---|---|
| 1 | local-id-reuse-ack-misdelivery.md |
problem | high | next_local_id() resets, reissues -1; stale ACK marks wrong message Sent. Repro’d |
| 2 | no-panic-containment-at-dylib-boundary.md |
risk | high | ADR-002 native/no-sandbox, zero panic policy; panic=abort conflicts with catch_unwind |
| 3 | unpinned-git-deps-and-source-substitution.md |
risk | high | 3 git deps unpinned + gitignored locks + no --locked + global insteadOf rewrite |
| 4 | trust-tier-flat-keyring-authority-collapse.md |
risk | high | ADR-002 two tiers vs ADR-003 single flat keyring — authority-ladder collapse |
| 5 | offline-retry-schedule-unpersistable-no-idempotency.md |
problem | high | Instant in persisted outbox ⇒ backoff lost on restart; no idempotency key; no eviction |
| 6 | hazard-pointers-cannot-allow-dylib-unmap.md |
risk | high | HP/QSBR protect heap objects, not code; timeout fallback unmaps under a stalled thread |
| 7 | storage-seam-frozen-wrong-shape.md |
risk | high | trait frozen on bare Message not Encrypted<T>; ADR-031 leaves LRU cache + outbox unassigned |
| 8 | calls-ffi-no-fault-propagation-policy.md |
risk | high | no unwind/exception policy at the C++↔Rust calls boundary; polling defers it to the worst moment |
| 9 | lattice-no-trust-anchor-defined.md |
risk | mid | spec defines verification, never the trusted-key set; lttc verify has no key policy |
| 10 | perf-claims-unmeasured-gate-is-stub.md |
risk | mid | ~30% WASM + dylib-crossing costs unmeasured; criterion absent; bench-scene is a 15-line stub |
| 11 | media-decode-no-budget-untrusted-input-unnamed.md |
risk | mid | remote media decode has no budget/dimension/frame caps; untrusted-input class unnamed |
| 12 | qsbr-work-stealing-per-thread-invariant.md |
risk | mid | QSBR quiescence is per-thread; OQ-024 specifies work-stealing ⇒ invariant unsound as written |
8 high, 4 mid. No low — I dropped anything that did not survive self-verification.
The load-bearing chain (this is the actual thesis)
Section titled “The load-bearing chain (this is the actual thesis)”Findings 2, 4, 6, 8, 10, 12 are one defect wearing six hats: the architecture assumes a fast, unsandboxed, hot-swappable native tier is free, and never paid for the containment that costs.
- #10: the premise (“native is fast enough to matter”, “dylib crossing is measurably expensive”) is unmeasured — and it is the premise for #2, #4 and #12.
- #2 + #6: catch_unwind at the module boundary turns a panic into the “grace period stalled” trigger for the timeout unmap. These two must land together or the fix makes things worse.
- #4: a flat keyring means one user-added key grants unsandboxed native.
- #8: the calls boundary is the same problem with a C++ counterparty and remote input.
- #12: the reclamation scheme that is supposed to make hot-swap safe has an unsound invariant as specified.
Fixing the perf claim first (cheapest: label it [unmeasured], as
RESEARCH-OQ-003 already does honestly) may dissolve some of the rest.
Cross-agent state
Section titled “Cross-agent state”- oc4 challenged my #2 ABI premise. Conceded — OQ.md:838, 878-880 already decided first-party = Rust ABI (their evidence was right, and I verified it before conceding). Pushed back on three points: the rustc pin is a self-reported metadata string (under ADR-004 it is forgeable); static linking conflicts with ADR-001/ADR-020’s hundreds-of-hot-swappable- dylibs premise; and the real bug is downstream (#6).
- oc4 and I converged, did not compete, on local-id-reuse: their
stable-OpId + idempotency key is the same shape as my
(local_id, attempt)correlation key plus my #5 idempotency token. Agreed one fix. - oc3 flagged that the rstgcalls FFI scaffold exists only in /tmp and the repo has 0 rust files — which corroborates #8’s “this is plan text, not shipped code”.
Watch list for whoever sequences the fixes
Section titled “Watch list for whoever sequences the fixes”CELL_BUDGET = 128vs the frozen 500-chat scene (#2/#10) — the sanctioned benchmark panics the render loop.assert!→Result, or raise the budget.next_local_id(#1) — fix before the sanakirja engine lands, whileMemoryEngineis the only impl.StorageEnginetrait signature (#7) — same window: one impl today, free now.- The rustc-version pin (#2) — verify the artifact’s embedded metadata, not the manifest’s claim.
- Open questions I could not answer from the corpus:
- Is the native tier intended to be user-key-trustable at all, or only root-key-signable? (Decides #4’s option 1 vs 2; cheap now, expensive later.)
- Is the module ABI
extern "C"or Rust-ABI trait object? oc4 answered per-tier; the third-party-native row (ADR-024 dev mode) is still open.