e0618af438
Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
5.0 KiB
5.0 KiB
REPORT — v0.125.0: .fab volume path-strand data loss FIXED (IA finding 1, HIGH)
Date: 2026-07-13 · Version: controller v0.125.0 (from v0.124.0) · MinAgent: 0.81.0 (UNCHANGED) · Floor: may advance to 0.125.0 on the next train (must NOT stop at >0.124.0 without this) · Controller-only. Disposition: closes the v0.124.0 REPORT's finding 1.
§3 live probe (ran FIRST, before any code)
On the drill guest: scratch volume seeded with a subdir, a file, a symlink, an empty file and a
non-root owner (1234:1234) → docker create -v fabprobe:/vol alpine true → docker cp <cid>:/vol/. - → tar (5120 B) → volume wiped → docker cp - <cid>:/vol → everything
byte-identical, symlink and uid/gid preserved. Zero surprises; transcript in the session
record. Green light for implementation.
What shipped (commit 466f427)
- Streaming legs —
dockerExecseam +withVolumeHelper(create → fn → ALWAYSrm -f, error paths included) +exportVolumeTar(cp <cid>:/vol/. -→ file) andimportVolumeTar(file →cp - <cid>:/vol). Zero shared paths: correct on bare metal AND containerized. - Scenario B — volume-export failure is FATAL;
assertBundleDataCompleteblocks packaging any bundle whose manifest claims a missing/empty tar (volumes + HDD; the HDD leg also stopped pre-claiming subdirs before the tar succeeds). - Scenario C —
validateBundleDataruns in import step 0, BEFORE the app is stopped or any volume removed; hollow bundles are refused with copy naming the ≤0.124.0-containerized-export cause and stating the app is untouched. Missing-tar soft-skips in both restore legs are hard errors now. - Scenario D —
scripts/docker_run_volume_path_gate.py: every"-v"arg in non-test Go needs an allowlist entry WITH ITS WHY. Gate output: 7 allowlisted usages, 0 violations. Tier-1/Tier-2 mechanism, proven by inspection:backup.go(dump) andbackup/restore.gomountdumpDir— always a registered-drive namespace path (/mnt/**,/opt/docker/**), which the golden deployment bind-mounts into the controller container at IDENTICAL paths (container-inspect verified), so the daemon resolves them correctly; their volume-side mounts are named volumes (daemon-side). They are NOT in the strand class; unchanged.
Tests + the three red-proofs (run → FAIL → restored)
- B:
TestExport_HollowVolumeTarAbortsExport(cp "succeeds" writing nothing → export fails naming vol1, no .fab). Red-proof: assertion disabled → "a hollow volume tar must FAIL the export — got success". - C:
TestImport_HollowBundleRefusedBeforeDestroy(handcrafted hollow bundle → refused; asserts stopped=0, removedVolumes=0, zero docker calls, app not started). Red-proof: pre-flight disabled →refusal happened AFTER destruction: removedVolumes=1— the exact pre-fix disaster shape. - D: violating
docker run -v /tmp/x:/outline added → gate exit 1; restored → 0. - Plus command-shape tests (create/cp/rm arg vectors pinned to the §3-probed shapes; import cp streams stdin; helper removed on cp failure; no partial tar left). Full green gate + all seven gates green.
§13 live validation (0.125.0 on drill + demo, both healthy)
- Supervised round-trip (Viktor GO), the EXACT leg that failed yesterday: demo ActualBudget
export → browser download (
actualbudget_20260713-085217.fab, 3762 B — the bundle now carries the 66048-byte volume tar; yesterday's was 2097 B with an EMPTY data/volumes) → sha256- identical after placement on felhom-usb/exports → import → "Importálás kész" → volume fingerprint after == before:ec8ea6cb…(2 files) → app Up (healthy) → zero leaked alpine helpers → bundle cleaned from the drive. - Scenario B live: a scratch stack whose compose declared the engine-invalid volume
"bad vol"(docker auto-creates nonexistent names, so engine-invalid is the honest live trigger) → export failed LOUD: "Kötet mentése sikertelen: volume scratchvol_bad vol export failed … invalid characters …" — zero bundles staged, zero leftover containers; scratch stack removed after.
Observations
- Hollow-bundle asymmetry (customer-facing docs line needed): any .fab exported by a CONTAINERIZED controller ≤0.124.0 has empty volume data while claiming it — treat as suspect and RE-EXPORT on ≥0.125.0. The import guard now refuses them loudly (app untouched) instead of silently importing emptiness. Bare-metal/felhotest exports were never affected; HDD-data apps were never affected.
- Spec §7B's "point a volume at a nonexistent volume" live construction doesn't fail under docker (named volumes auto-create; an empty volume exports as an honest small tar — correct behavior) — the live loud-fail used an engine-invalid name instead; the missing/empty-tar refusal is unit-pinned with red-proof.
- The one Windows-runner nuance: none — the docker seam keeps unit tests fully offline.