Peering dogfood: second instance on k3s + live A↔B e2e #106

Closed
opened 2026-08-04 11:04:52 +00:00 by Cordy · 2 comments
Owner

Peering cannot be dogfooded against itself — we need a second live instance. Deploy cairn-peer on k3s next to the existing enc dogfood (.249): MetalLB has exactly one address left in the pool (192.168.10.250, pool .240–.250), same Keycloak realm is fine (different users make the test more honest — e.g. only zeus321 on the peer), own Garage bucket (cairn-peer), own config secret. Manifests in homelab-config k3s/cairn/.

e2e (one-shot workflow interop-peering.yml, runner as LAN test host, like interop-rclone.yml):

  1. Admin flow via API on both instances: generate key on B for A, register B on A (and reverse).
  2. Send a file A→B to a user that exists on B → arrives in their Inbox, correct bytes, correct owner, encrypted to the B-recipient's key (pull the raw Garage object, prove it's an age file the sender's key can NOT open, recovery can).
  3. Negative matrix: revoked key → refused; unknown recipient → refused; oversized declared size → refused pre-flight; replayed transfer id → idempotent.
  4. Audit trails on both sides show the transfer.

Open questions:

  • Gateway API: Manuel's condition — "Wenn Kubernetes mit der Gateway API deployed ist könnts klappen." For LAN dogfood a plain MetalLB LoadBalancer suffices; Gateway API (Traefik's GRPCRoute/HTTPRoute) is the story for routing gRPC/h2 PUBLICLY. Do we make Gateway API part of the v0.5 acceptance (install + route the peering port through it on the homelab), or note it as deployment documentation and keep dogfood on LoadBalancer? Depends on #100's transport decision (GRPCRoute only matters if gRPC wins). ➤ Manuel to check "aktuellen Stand" as he said; k3s ships Traefik ≥3 with Gateway API support that must be explicitly enabled.
  • Public path: real-world peering crosses the internet. Our own public chain is VPS Caddy + WireGuard (CGNAT). gRPC needs end-to-end h2 — verify Caddy's reverse_proxy h2c/grpc config on the VPS, or decide peering rides a dedicated port. Ties into the external-exposure work (#22) — same TLS story files.c0rdyceps.ch needs anyway.
  • Resource budget: pi cluster runs everything — does cairn-peer get the same 500m/256Mi limits (and does a big transfer trip CPUThrottlingHigh like homelab-config #5)?
  • Second instance lifetime: keep permanently as the standing peer-test target, or tear down after each e2e run (recommend: keep — it doubles as the upgrade-canary).
Peering cannot be dogfooded against itself — we need a second live instance. Deploy **cairn-peer** on k3s next to the existing enc dogfood (.249): MetalLB has exactly one address left in the pool (192.168.10.250, pool .240–.250), same Keycloak realm is fine (different users make the test more honest — e.g. only `zeus321` on the peer), own Garage bucket (`cairn-peer`), own config secret. Manifests in homelab-config `k3s/cairn/`. **e2e (one-shot workflow `interop-peering.yml`, runner as LAN test host, like `interop-rclone.yml`):** 1. Admin flow via API on both instances: generate key on B for A, register B on A (and reverse). 2. Send a file A→B to a user that exists on B → arrives in their Inbox, correct bytes, correct owner, **encrypted to the B-recipient's key** (pull the raw Garage object, prove it's an age file the sender's key can NOT open, recovery can). 3. Negative matrix: revoked key → refused; unknown recipient → refused; oversized declared size → refused pre-flight; replayed transfer id → idempotent. 4. Audit trails on both sides show the transfer. **Open questions:** - **Gateway API:** Manuel's condition — "Wenn Kubernetes mit der Gateway API deployed ist könnts klappen." For LAN dogfood a plain MetalLB LoadBalancer suffices; Gateway API (Traefik's GRPCRoute/HTTPRoute) is the story for routing gRPC/h2 PUBLICLY. Do we make Gateway API part of the v0.5 acceptance (install + route the peering port through it on the homelab), or note it as deployment documentation and keep dogfood on LoadBalancer? Depends on #100's transport decision (GRPCRoute only matters if gRPC wins). ➤ Manuel to check "aktuellen Stand" as he said; k3s ships Traefik ≥3 with Gateway API support that must be explicitly enabled. - **Public path:** real-world peering crosses the internet. Our own public chain is VPS Caddy + WireGuard (CGNAT). gRPC needs end-to-end h2 — verify Caddy's `reverse_proxy` h2c/grpc config on the VPS, or decide peering rides a dedicated port. Ties into the external-exposure work (#22) — same TLS story `files.c0rdyceps.ch` needs anyway. - Resource budget: pi cluster runs everything — does cairn-peer get the same 500m/256Mi limits (and does a big transfer trip CPUThrottlingHigh like homelab-config #5)? - Second instance lifetime: keep permanently as the standing peer-test target, or tear down after each e2e run (recommend: keep — it doubles as the upgrade-canary).
Author
Owner

Done — first real A↔B transfer succeeded 2026-08-09. Executed leaner than originally sketched, per Nikola's call: a temporary 1-day second instance (not a standing peer), manual admin flows through the real panel instead of a scripted e2e workflow — which proved the right choice, because the panel's own UX turned out to be part of what needed testing. The deep matrix (negative cases, encryption proof, audit) moves to the v0.7 closed beta as planned.

Setup: cairn-beta at 192.168.10.247 (the freed IP, not .250), posix driver on its own PVC, local auth via the first-run /setup flow — no Keycloak changes, no Garage bucket, torn down completely afterwards (manifest deleted, kubectl delete of deploy/svc/pvc/secret). Deliberately minimal: encryption parity was not the goal of this pass; connectivity, trust exchange, and delivery were.

Result: mutual key exchange via the panels, Mülltrennung.docx sent from cairn-enc and delivered into /home/Niko-test/Inbox/dogfood/ on beta.

The dogfood earned its keep — every layer between panel and delivery had a real defect:

  1. #140 (fixed, v0.4.9): gRPC dialed port 443 for portless plain-HTTP peer URLs — gRPC's resolver defaults to 443 regardless of scheme.
  2. #143 (fixed, v0.4.10): the cleartext listener never spoke h2c, so single-port gRPC over plain HTTP was impossible at all; the loopback test's injected dialer had hidden both transport bugs.
  3. #145 (filed): issued-key name and peer-entry name silently form one relationship — mismatch (dogfood vs Main-Cairn) fails closed as STATUS_UNKNOWN_RECIPIENT on the sender's side.
  4. #146 (filed): homes aren't materialized at login, so fresh users — and unscoped admins permanently — fail the residency check.
  5. #147 (built, v0.4.11): delivery was silent; notification bell shipped and verified on both instances.
  6. #142 (filed): per-peer "Test connection" button — would have caught 1 and 2 at registration time.

Also validated in passing: the #134 runtime toggle (beta's 503 while off, panel re-enable), the #136 key display/copy flow (used for all four issued keys), #129's receivers lists and both-direction row display, and the PVC persistence work (peering state survived four redeploys mid-test).

Open questions from this issue's body (Gateway API for public gRPC, Caddy h2 on the VPS public path, resource budget under big transfers) are explicitly NOT answered by this LAN pass — they carry to the v0.7 beta / #22 external-exposure work.

Remaining open in v0.5: #124 (README/ARCHITECTURE peering description — this issue passing was its trigger), #142, #145, #146. (Correction: an earlier revision listed #117 here — the OCM adapter was deferred to the closed-beta milestone on 2026-08-05 and is tracked there, now v0.7 after the renumbering.)

**Done — first real A↔B transfer succeeded 2026-08-09.** Executed leaner than originally sketched, per Nikola's call: a **temporary** 1-day second instance (not a standing peer), manual admin flows through the real panel instead of a scripted e2e workflow — which proved the right choice, because the panel's own UX turned out to be part of what needed testing. The deep matrix (negative cases, encryption proof, audit) moves to the v0.7 closed beta as planned. **Setup:** `cairn-beta` at 192.168.10.247 (the freed IP, not .250), posix driver on its own PVC, **local auth** via the first-run `/setup` flow — no Keycloak changes, no Garage bucket, torn down completely afterwards (manifest deleted, `kubectl delete` of deploy/svc/pvc/secret). Deliberately minimal: encryption parity was not the goal of this pass; connectivity, trust exchange, and delivery were. **Result:** mutual key exchange via the panels, `Mülltrennung.docx` sent from `cairn-enc` and delivered into `/home/Niko-test/Inbox/dogfood/` on beta. **The dogfood earned its keep — every layer between panel and delivery had a real defect:** 1. **#140 (fixed, v0.4.9):** gRPC dialed port 443 for portless plain-HTTP peer URLs — gRPC's resolver defaults to 443 regardless of scheme. 2. **#143 (fixed, v0.4.10):** the cleartext listener never spoke h2c, so single-port gRPC over plain HTTP was impossible at all; the loopback test's injected dialer had hidden both transport bugs. 3. **#145 (filed):** issued-key name and peer-entry name silently form one relationship — mismatch (`dogfood` vs `Main-Cairn`) fails closed as `STATUS_UNKNOWN_RECIPIENT` on the *sender's* side. 4. **#146 (filed):** homes aren't materialized at login, so fresh users — and unscoped admins *permanently* — fail the residency check. 5. **#147 (built, v0.4.11):** delivery was silent; notification bell shipped and verified on both instances. 6. **#142 (filed):** per-peer "Test connection" button — would have caught 1 and 2 at registration time. Also validated in passing: the #134 runtime toggle (beta's 503 while off, panel re-enable), the #136 key display/copy flow (used for all four issued keys), #129's receivers lists and both-direction row display, and the PVC persistence work (peering state survived four redeploys mid-test). **Open questions from this issue's body** (Gateway API for public gRPC, Caddy h2 on the VPS public path, resource budget under big transfers) are explicitly NOT answered by this LAN pass — they carry to the v0.7 beta / #22 external-exposure work. Remaining open in v0.5: **#124** (README/ARCHITECTURE peering description — this issue passing was its trigger), **#142**, **#145**, **#146**. *(Correction: an earlier revision listed #117 here — the OCM adapter was deferred to the closed-beta milestone on 2026-08-05 and is tracked there, now v0.7 after the renumbering.)*
Cordy closed this issue 2026-08-09 02:29:47 +00:00
Author
Owner

First real A↔B transfer completed end to end (2026-08-15 dogfood)

files/enc ↔ files-bao/openbao, both live per-user-encrypted instances over the public HTTPS domains.

Proven end to end (files-bao → files): Andrej-karpathy-skills.md (5.4 KB) sent to nikola-test@files, group-authorized via cairn-admins, delivered to /home/nikola-test/Inbox/bao/ and readable there. Every layer exercised on the real modes:

  • relationship-card setup + key exchange (#150/#176/#136/#134);
  • control-plane handshake over the Caddy reverse proxy — required a Caddy fix to carry gRPC (h2c matcher for application/grpc; server-side transparent proxy was downgrading HTTP/1.1 and 401-ing the peering RPC);
  • recipient discovery picker (#125) — works; group-only receivers correctly degrade to free-text (see #234);
  • delivery encryption to the recipient's own key (#237, shipped v0.6.23) — was the last blocker; a resident group-member with no explicit user entry receives and can decrypt.

Remaining before closing #106:

  • spot-check the reverse direction (files → files-bao) with a real file — control plane is already green both ways and delivery uses the same fixed path, so this is a confirmation, not new work;
  • open v0.5 peering items: #117, #129 (group-only-receivers admin warning);
  • product fork #238 (client-side E2E for cross-instance) — deliberately out of scope for #106.

Findings filed head-first this session: #234 (group-receiver expansion), #235 (editable peer URL), #236 (replace outbound key), #238 (E2E direction). Net: peering genuinely moves files now, not just handshakes.

## First real A↔B transfer completed end to end (2026-08-15 dogfood) files/enc ↔ files-bao/openbao, both live per-user-encrypted instances over the public HTTPS domains. **Proven end to end (files-bao → files):** `Andrej-karpathy-skills.md` (5.4 KB) sent to `nikola-test@files`, group-authorized via `cairn-admins`, delivered to `/home/nikola-test/Inbox/bao/` and readable there. Every layer exercised on the real modes: - relationship-card setup + key exchange (#150/#176/#136/#134); - **control-plane handshake over the Caddy reverse proxy** — required a Caddy fix to carry gRPC (h2c matcher for `application/grpc`; server-side transparent proxy was downgrading HTTP/1.1 and 401-ing the peering RPC); - **recipient discovery** picker (#125) — works; group-only receivers correctly degrade to free-text (see #234); - **delivery encryption** to the recipient's own key (#237, shipped v0.6.23) — was the last blocker; a resident group-member with no explicit user entry receives and can decrypt. **Remaining before closing #106:** - spot-check the **reverse direction** (files → files-bao) with a real file — control plane is already green both ways and delivery uses the same fixed path, so this is a confirmation, not new work; - open v0.5 peering items: **#117**, **#129** (group-only-receivers admin warning); - product fork **#238** (client-side E2E for cross-instance) — deliberately out of scope for #106. Findings filed head-first this session: #234 (group-receiver expansion), #235 (editable peer URL), #236 (replace outbound key), #238 (E2E direction). Net: peering genuinely moves files now, not just handshakes.
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#106
No description provided.