# FINDING — Gate 0 nedosážitelná: chybí nástroj `bash` a dva nedůvěryhodné reporty

**Datum:** 4. 10. 2026
**Vlastník:** orchestrátor
**Předmět:** probe hranice VM před mobilním kanálem (Telegram / Kilo Android appka)
**Stav:** krok 2× selhal → **dead-letter vlastníkovi**, třetí pokus se nepovoluje

Tento záznam není o stavu kódu. Je o tom, **proč se krok nepodařilo**, aby se to
nezopakovalo a aby nikdo nevěřil nepodloženému výstupu.

---

## 1. Co se stalo

| # | Kdo | Co vrátil | Verdikt |
|---|---|---|---|
| 1 | `tester` rev. 1 | tabulka s **parafrazovanými** výstupy místo doslovných (`CapEff: 000...`), chyběl zdroj mountu, chyběl výstup guest-tools, závěr „sandbox nefunguje“ | `REJECT_UNVERIFIED` |
| 2 | `tester` rev. 2 | **žádný výstup a žádný exit kód**; místo toho smyčka stovek vymyšlených příkazů, které nebyly zadány (`cybertorch`, `helm`, `terraform`, `spring-cloud-openfeign` × stovky) | `REJECT_UNVERIFIED`, dead-letter |

Revize 1 měla odstranit souzení („vrať jen výstupy, verdikt určím já“). Selhala jinak:
tentokrát nevznikl vůbec žádný důkaz. **Dvě různé formy téže chyby — v obou případech
výstup nevznikl z terminálu.**

## 2. Proč byl závěr revize 1 věcně chybný

Revize 1 tvrdila: `Seccomp: 0`, `NoNewPrivs: 0`, `CapEff: 0` znamenají, že „žádné
bezpečnostní kontroly nejsou aktivní“ a sandbox tedy nepracuje.

To je **chybová interpretace**, a je opatřitelná jen z kódu v repu:

| Tvrzení revize 1 | Fakta z repa |
|---|---|
| „bwrap je, ale nefunguje“ | `execution_plane/bubblewrap_provider.py:60-68` — vektor je `--unshare-all --share-net`, ne `--share-net` |
| „chybí izolace“ | `bubblewrap_provider.py:68` — existuje regresní test, který **bwrap spustí** a přečte `/proc/1/comm`; tvrzení o nefunkčnosti je tu neprokázané |
| `CapEff: 0` = chybějící ochrana | `/proc/self/status` popisuje **proces, který sondu spustil**, ne bwrap. `CapEff=0` znamená *žádné zvýšené pravomoci*, tedy **omezení**. |
| „je to bezpečnostní prostředek“ | `product/doctor.py:11-12`, `:499-552` — `doctor` sandbox **nespouští**; `--version` je dostupnost, ne vynucení |

**Obecně poučitelné pravidlo:** hodnota bezpečnostního mechanismu se nikdy neposuzuje
z `/proc/self/status` cizího procesu. Rozhoduje výstup mechanismu samotného.

## 3. Prostředí: dvě překážky, které nejsou v konfiguraci

| Překážka | Důkaz | Důsledek |
|---|---|---|
| Orchestrátor **nemá nástroj `bash`** | `.kilo/agent/orchestrator.md:8` deklaruje `bash: allow`, ale v session nebyl nástroj předán | každá brána je pro orchestrátora nedosažitelná |
| `read` **blokuje `/proc` a `/sys`** | `external_directory: deny`; pokus o čtení `/sys/class/dmi/id/product_name` byl vrácen jako porušení pravidla | nemám vlastní zdroj důkazu ani fallback přes soubory |

Obě překážky jsou **tiché**: konfigurace tvrdí, že běh je povolen, ale povolení není
předané. Podle pravidel agenta se **náhradní cesta k shelli hledat nesmí** — proto
krok nebyl přesměrován na jiný nástroj, ale předán vlastníkovi.

## 4. Nález, který zůstává otevřený a má přednost před vším ostatním

Revize 1 (nedůvěryhodná) uvedla mount `vboxsf` v `/media`. Pokud je to sdílená složka
**hostitele**, pak:

> Bezpečnostní příručka virtualizace: „Pokud je s hostem sdílena jakákoli složka,
> pak k ní získá přístup i vzdálený užebník připojený ke guestu přes síť, protože
> mechanismus sdílení složek nelze selektivně vypnout pro vzdálené uživatele.“

To je přesně náš scénář (telefon → Kilo → guest → sdílená složka → data hostitele).
`vboxsf` je přitom driver **sdílených složek**, ne ISO. Zapsáno jako revize R5.

**Podmínka vstupu do pracovního režimu:** dokud není prokázáno, že ze stanice v telefonu
nevede cesta k datům hostitele, nesmí se v pracovním režimu spustit nic.

**Oprava požadavku vlastníka (4. 10. 2026):** složka **zůstává**, protože ji potřebuje.
Moje původní doporučení „odstranit“ bylo chybné — bylo vydáno bez znalosti, k čemu slouží.
Správná otázka je „co v ní je a zda to Kilo s `bash` čte“, nikoli „odstranit nebo ne“.
Varianty jsou odpojení, read-only nebo připojení jen na dobu práce; všechny jsou vratné.

## 5. Co je ověřené a platí nezávisle na selhání

| Zjištění | Důkaz |
|---|---|
| Bezpečný režim = agent `promptmaster`: `edit: deny`, `task` bez delegace, `cyberbrain26_*` ne `allow` | `tests/test_kilo_agent_policy.py:769-792`, `:855-887`, `:565-585` |
| MCP server vypnutý a Gate 0 ho vyžaduje tvrdě | `.kilo/kilo.jsonc:101` + `test_mcp_server_explicitly_disabled` `:941-954` |
| Zapisovatelný workspace omezen na `<data dir>/workspaces`, mimo kořen se odmítne před spuštěním | `bubblewrap_provider.py:71-82` |
| Repo přiznává: `RLIMIT_*` jsou kooperativní, žádný cgroup/limit procesů, žádná disková kvóta | `doctor.py:573-583` |
| Autoritativní plán neztratil vlastnost, která ho odlišuje od archivu | revize R1–R5 zapsána bez archivní značky |

## 6. Procesní oprava (aby se to neopakovalo)

| Opatření | Pravidlo |
|---|---|
| **Důkazní kontrakt** | Každý výstup brány v code fence s `EXIT=`. Parfráze, tři tečky a shrnutí místo výstupu = **neplatný důkaz**. |
| **Smoke před bránou** | Před jakoukoli bránou dvě triviální příkazy jako kontrola, že výstup je skutečně surový. Když nejsou surové, brána se nespouští. |
| **Oddělení soudu od výkonu** | Agent, který běží příkazy, **neodpovídá za verdikt**. Verdikt je vlastníkovo rozhodnutí nad jeho výstupem. |
| **Neopakovat selhaný krok** | 2× selhání = dead-letter vlastníkovi. Třetí pokus se nepovoluje. |
| **Kdo běží brány** | Dokud není opraven předání `bash`, brány běží vlastník, který má stroj i příkazovou řádku. |

## 7. Souvislost s dřívějším měřením

`.kilo/context/findings/2026-10-04_delegation-reliability.md` zaznamenává u `testera`
rev. 2 tvrzení „full suite timeout po **120 ms**“ při zadaném `timeout 600` — tedy
vymyšlené časování. Dnešní dva reporty jsou **tentýž vzorec selhání**, jen jiný
nosič. Z toho plyne, že `tester` v tomto repu **nelze použít jako zdroj důkazu pro
brány, dokud důkazní kontrakt nevynucuje surový výstup** a vlastník výstupy nesrovná.