# FOG Local Podman PoC Status: Runnable Fixture 0.2 Date: 2026-08-08 ## 1. Purpose and Claim Boundary `FOG-LOCAL-POC-1` is the first runnable local process, isolation, baseline, and failure-test boundary for FOG. It turns the architecture's role and reachability rules into a validated rootless Podman fixture. The machine-readable artifacts and validator are in `../deploy/podman/`. This definition is functional evidence only. It cannot demonstrate operator independence, infrastructure diversity, an anonymity set, traffic-analysis resistance, availability, capacity, production key handling, or a safe numeric protocol profile. All containers run on one host under one user and therefore share a host kernel, storage stack, management account, clock, and failure domain. The fixture does not activate FOG-WIRE, FOG-PKI, KEMSphinx, storage, messaging, cover, delay, polling, retry, or degraded-mode parameters. It does not implement or substitute for any protocol daemon. Its deliberately bounded and non-cryptographic transport is named `FOG-POC-FIXTURE-1`. ## 2. Requirements The PoC definition is governed by: - `ARC-001`, separate trust domains even when co-located; - `ARC-002`, a networkless Composer; - `ARC-003`, no data-plane bypass; - `ARC-005`, complete authenticated network views; - `ARC-007`, one private-key owner and no shared writable state; - `ARC-008`, bounded configuration, work, and state; - `ARC-009`, no privacy-weakening fallback; - `IF-06` through `IF-09`, exact online data-plane adjacencies; - `TM-NET-03`, `TM-NET-04`, `TM-PKI-02`, `TM-PKI-03`, `TM-ROLE-01`, `TM-ROLE-02`, `TM-ROLE-03`, `TM-CRYPTO-01`, and `TM-AVAIL-01`; - `PKI-INV-01`, `PKI-INV-03`, `PKI-INV-04`, and `PKI-INV-08`; - `WIRE-INV-07`, `WIRE-INV-08`, `WIRE-INV-09`, and `WIRE-INV-10`. Podman 5.8.3 and podman-compose 1.6.0 are present on the first local host. The runtime contract targets rootless Podman and internal bridge networks. Podman documents `network=none` as a network namespace without configured network interfaces and an internal bridge as restricting external access. These runtime properties remain acceptance-test subjects rather than assumptions. ## 3. Deployment Stages ### 3.1 Definition stage, completed The checked-in JSON plan and standard-library Go validator define roles, network edges, private state ownership, container hardening, resource containment, and the mandatory fault matrix. This stage prevented placeholder ports, fake cryptography, reusable example keys, or an unreviewed generic fixture protocol from becoming accidental implementation defaults. ### 3.2 Fixture stage, current The executable harness provides explicitly named PoC-only binaries. They exercise process lifecycle, exact opaque object geometry, network reachability, bounded connections and work, restart behavior, role-local state, secret isolation, and fault outcomes. They do not call their transport FOG-WIRE or their public data FOG-PKI. The stage builds one scratch image without build-time networking, addresses it by its local OCI manifest digest, and deterministically generates a Compose manifest from validated `topology.json`. The internal TCP port `17001` belongs only to the fixture harness and is not a selected FOG protocol port. ### 3.3 Protocol-functional stage Actual role executables replace the fixtures only after the relevant exact profiles, libraries, parsers, key formats, and conformance vectors are selected. Each replacement must retain the same state and network ownership contract and pass the same fault matrix. ## 4. Role Inventory | Instance | Executable contract | Purpose | Network state | | --- | --- | --- | --- | | `composer-fixture` | `fog-poc-composer-fixture` | Networkless public-fixture acceptance state | `none` | | `authority-fixture` | `fog-poc-authority-fixture` | Networkless authority-condition state | `none` | | `relay` | `fog-client-relay` | Opaque client queue and entry submission | private pairwise network | | `entry` | `fog-entry` | Entry boundary outside the mix layers | two private pairwise networks | | `mix-l1` | `fog-mix`, fixed layer 1 | First mix position | two private pairwise networks | | `mix-l2` | `fog-mix`, fixed layer 2 | Second mix position | two private pairwise networks | | `mix-l3` | `fog-mix`, fixed layer 3 | Third mix position | two private pairwise networks | | `courier` | `fog-courier` | Terminal request and replica mediation | five private pairwise networks | | `store-a` through `store-d` | `fog-store` | Four separate storage fixtures | one private pairwise network each | The three-node description refers to the three fixed mix positions. Entry and courier remain outside those three KEMSphinx delay layers. Four storage containers exist so the PoC does not normalize a smaller shared storage fixture into the intended architecture. The authority and Composer fixtures are networkless process and state boundaries. Fault flags model only coarse acceptance states such as quorum loss or conflicting public fixtures. They do not create signatures, consensus objects, identities, contacts, capabilities, or message secrets and supply no authority-independence claim. An observer is not in this first topology. `FOG-OBSERVABILITY-1` now defines the separate structural logging and aggregate contract, but no observer, numeric observability profile, or IF-11 codec is active in this fixture. No container may substitute ordinary logs or packet traces for `fog-observer`. ## 5. Network Segmentation Every declared network is internal and contains exactly two roles: ```text relay <-> entry <-> mix-l1 <-> mix-l2 <-> mix-l3 <-> courier |-- store-a |-- store-b |-- store-c `-- store-d ``` The nine networks are: | Network | Members | Interface | | --- | --- | --- | | `relay-entry` | relay, entry | `IF-06` | | `entry-l1` | entry, mix-l1 | `IF-07` | | `l1-l2` | mix-l1, mix-l2 | `IF-07` | | `l2-l3` | mix-l2, mix-l3 | `IF-07` | | `l3-courier` | mix-l3, courier | `IF-08` | | `courier-store-a` | courier, store-a | `IF-09` | | `courier-store-b` | courier, store-b | `IF-09` | | `courier-store-c` | courier, store-c | `IF-09` | | `courier-store-d` | courier, store-d | `IF-09` | There is no shared data-plane bridge. No role uses the host network. No container port is published to the host. The Composer and authority fixtures use `network=none`. Coarse public-data failure conditions are written only to the targeted role's private fixture state and contain no consensus bytes or cryptographic material. The runnable harness proves that containers cannot reach an external address, host-local services, or undeclared roles. Name resolution success is not sufficient evidence of an authorized protocol edge, and failure of one edge must never create another. ## 6. Filesystem, Keys, and Container Hardening Every role-container contract requires: - rootless execution as a dedicated non-root container user; - one digest-pinned immutable image; - a read-only root filesystem; - `no-new-privileges`; - all Linux capabilities dropped; - no privileged mode, device passthrough, host PID, host IPC, host UTS, or host network namespace; - private `/run` and `/tmp` tmpfs mounts with bounded sizes in the generated manifest; - exactly one role-owned writable state volume; - no source checkout, container socket, generic host directory, or other role's state mounted; - disabled core dumps and no secret-bearing diagnostic output; - explicit CPU, memory, PID, file-descriptor, connection, and queue limits. The checked-in CPU, memory, and PID values are harness containment limits, not capacity results or protocol profile parameters. Their only purpose is to make local fault tests bounded. One 32-byte non-cryptographic fixture token per role is generated in memory from the operating-system CSPRNG. It is streamed into a distinct Podman Secret object. The installed `podman-compose` plus `runc` combination cannot mount that file directly into a read-only role root filesystem, so a networkless, bounded, one-shot stager copies it into a newly created role-specific volume with mode `0400`. The Podman Secret source is removed immediately and the role mounts only its own secret volume read-only. Tokens never enter source, JSON plans, images, host-supplied files, command arguments, environment templates, logs, test reports, or public fixture objects. A constant-time runtime challenge confirms that each role received its intended token without reporting a value or digest. Teardown removes the disposable secret and state volumes. Destruction of the `mix-l2` replay fixture requires the separate `--allow-destructive` option and names the exact target first. ## 7. Baseline Functional Flow The runnable fixture performs these steps from clean role state: 1. Start the Composer and authority process fixtures without a configured network interface and validate their private state and token scope. 2. Generate one opaque fixed-size packet fixture with the current 16,150-byte candidate geometry, clearly labeled as non-cryptographic PoC data. 3. Admit the fixture only at relay, then traverse entry, mix-l1, mix-l2, mix-l3, and courier in that order. 4. Dispatch one bounded opaque operation from courier to the storage fixture set and collect only the modeled receipt result. 5. Return a bounded opaque result through the declared reverse adjacency, without creating a direct courier-to-relay connection. 6. Verify that no role mounted another role's state or token and that no container gained an undeclared network. 7. Report only the role names, scenario IDs, and coarse fixture outcomes. The successful first-host result is `complete-fixture`, four modeled fixture receipts, and four fixture hops after entry. These counts describe only this test transport and must not be read as storage durability or anonymity evidence. The harness keeps no packet transcript. Container logging is disabled and no result contains packet bytes, object identifiers, per-packet timing, keys, route secrets, capabilities, or source addresses. ## 8. Fault Matrix `fault-scenarios.json` defines fifteen mandatory scenarios: | Scenario | Expected invariant | | --- | --- | | `forbidden-role-edge` | Only declared pairwise reachability exists | | `entry-stop` | No relay-to-layer-1 fallback | | `mix-layer-two-stop` | No layer skip or courier delivery | | `layer-two-three-partition` | Bounded failure on the same adjacency | | `mix-replay-state-loss` | Same-epoch processing fails closed | | `stale-consensus` | New work stops at hard expiry | | `same-epoch-consensus-fork` | Consumers freeze instead of choosing a view | | `authority-quorum-loss` | Partial views and insufficient signatures fail | | `clock-uncertainty` | Time-sensitive acceptance stops | | `single-store-loss` | No false durability result | | `receipt-quorum-loss` | Required receipts cannot be fabricated | | `courier-stop` | No layer-3 or client connection to storage | | `entry-handshake-flood` | Work and responses remain bounded | | `cover-process-stop` | A cover-dependent claim cannot continue silently | | `role-secret-isolation` | No cross-role state or fixture-token access | Each scenario names target roles, the abstract action, expected behavior, explicitly prohibited fallback, requirement IDs, automation status, and whether it mutates role state. Abstract actions deliberately contain no shell command. The fault runner resolves container and volume targets from the validated plan, show destructive targets before execution, and start state-destructive tests from disposable snapshots. No scenario may run concurrently with another. Each begins from a documented clean baseline so an earlier partition, stopped role, or modified volume cannot make a later test pass for the wrong reason. On the first host, all fourteen automatable scenarios pass. The `cover-process-stop` row remains `not-automatable`: the fixture has no cover scheduler and therefore cannot silently retain a cover or unobservability claim. The effective runtime verifier completes 239 checks before the fault matrix begins. ## 9. Acceptance Gates ### 9.1 Definition gate, satisfied - The strict parser accepts the checked-in topology and fault plan. - Duplicate or unknown fields, trailing JSON, oversized or non-regular inputs fail. - Required roles, exact mix layers, four stores, pairwise internal networks, private state, private secret scopes, hardening flags, and resource bounds are enforced. - Forbidden edges, host exposure, shared volumes, missing faults, and invalid traceability references fail validation. - The validator uses only the Go standard library and performs no network or filesystem writes. ### 9.2 Runnable fixture gate, satisfied - One local scratch image is built and referenced by its OCI manifest digest. - PoC-only fixture roles and future online security roles have distinct executable entrypoints. - The generated Compose manifest derives from validated `topology.json`. - Effective Podman state, not only source YAML, passes 239 runtime checks. - Rootless operation, pairwise internal networks, failed host and external probes, no published ports, private volumes, read-only roots, zero process capability sets, and role-token isolation pass. - The baseline and all fourteen automatable fault scenarios pass. - Reports contain only coarse outcomes. The cover-only row is explicitly not automatable and grants no cover claim. ### 9.3 Protocol-functional gate, not yet satisfied - Replace fixtures with exact parsers, cryptographic profiles, key ownership, replay persistence, command policy, consensus transitions, and storage receipts from the normative specifications. - Pass the PKI and FOG-WIRE functional PoC gates. - Add parser conformance, fuzz, race, allocation, load, and mutation tests. - Demonstrate current and next epoch transition, rollback refusal, revocation, per-record rekey, fresh handshakes, exact packet geometry, and strict failure behavior. None of these gates creates an anonymity or production claim. ## 10. Validation Commands From `deploy/podman/`: ```sh gofmt -d cmd/fog-poc-plan/*.go internal/plan/*.go go test ./... go test -race ./... go vet ./... go run ./cmd/fog-poc-plan go run -buildvcs=false ./cmd/fog-poc-lab -action all -allow-destructive ``` The expected summary is twelve roles, three mix layers, four stores, nine internal pairwise networks, fifteen fault scenarios, and the claim `functional-only`. ## 11. Deferred Decisions This definition does not select: - a Noise or hybrid post-quantum construction, library, profile ID, port, record size, timer, socket profile, or command shape; - a PKI authentication suite, exact epoch schedule, topology shuffle, authority wire-key profile, or recovery ceremony; - an active KEMSphinx suite or entry capsule; - storage request geometry, durability profile, or receipt primitive; - cover, delay, loop, retry, polling, queue, or shutdown distributions; - observability fields, aggregation windows, release delays, or thresholds; - a production container base image, release channel, deployment user, host firewall, backup, or update mechanism. These remain explicit dependencies. The fixture generator supplies none of them. Any future protocol-functional manifest generator must fail when a required value is absent rather than converting fixture values into an undocumented protocol default. ## 12. References - FOG threat model: `FOG-THREAT-MODEL.md` - FOG architecture: `FOG-ARCHITECTURE.md` - FOG PKI: `FOG-PKI.md` - FOG wire protocol: `FOG-WIRE.md` - FOG traffic simulator: `FOG-SIMULATION.md` - Podman run and network modes: - Podman internal network option: - Podman secret management: