From 77ac7a47560e9ca80a61a0f4f06aa960a6d72ab7 Mon Sep 17 00:00:00 2001 From: zzstoatzz Date: Thu, 9 Jul 2026 12:24:25 -0500 Subject: [PATCH] deploy: SSRF boundary (plc-only resolution) + linux packaging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit did:web DIDs pass unverified rather than making stream fetch attacker-named hosts (lesson #10); did:plc talks only to the operator-configured PLC. deploy/README.md captures the node requirements (MALLOC_ARENA_MAX=4, probe placement, build_info canary, disk sizing note) and `just package` produces the ReleaseSafe x86_64-linux-gnu binary — fully static of system deps thanks to vendored zstd/xxhash. Co-Authored-By: Claude Fable 5 --- deploy/README.md | 33 +++++++++++++++++++++++++++++++++ justfile | 5 +++++ src/internal/verify.zig | 5 +++++ 3 files changed, 43 insertions(+) create mode 100644 deploy/README.md diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..017f7c2 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,33 @@ +# deploying stream + +target: k3s on the relay node, beside (eventually replacing) the legacy +jetstream sidecar at jetstream.waow.tech. build natively on the server or +cross-compile — no system libraries needed (zstd/xxhash are vendored). + +```sh +just package # ReleaseSafe x86_64-linux-gnu binary in zig-out/bin/ +``` + +## required environment (docs/lessons-from-zlay.md #8, #9) +- `MALLOC_ARENA_MAX=4` — the highest-leverage glibc RSS knob for + thread-heavy services (per-thread arena fragmentation) +- probes must hit the concurrent ws/http port (`/healthz` on :6008), + never a single-purpose port +- immutable image tags (git SHA); confirm what's running via the + `stream_build_info{git_sha,optimize}` metric + +## flags for production +``` +--upstream=wss://relay.waow.tech +--plc=https://plc.directory +--data-dir=/data +``` +disk sizing: the archive stores every event (zstd ~4-27x on simulator +payloads); size /data from relay-eval's observed daily volume before +first deploy. + +## known pre-deploy gaps (tracked in project memory) +- did:web accounts pass unverified (SSRF boundary until the resolver + is hardened); watch stream_verify_total{result="unverified"} +- absolute throughput not yet validated above the local simulator's + per-client delivery ceiling — soak on the node before cutover diff --git a/justfile b/justfile index db51c1c..e7c8fee 100644 --- a/justfile +++ b/justfile @@ -33,3 +33,8 @@ e2e: zig build ./zig-out/bin/stream & echo $! > /tmp/stream-e2e.pid; sleep 2 uv run tests/e2e.py; status=$?; kill $(cat /tmp/stream-e2e.pid); exit $status + +# ReleaseSafe linux binary (musl breaks C++ deps upstream; gnu per zlay) +package: + zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-linux-gnu + @ls -lh zig-out/bin/stream diff --git a/src/internal/verify.zig b/src/internal/verify.zig index 3d1cede..3607501 100644 --- a/src/internal/verify.zig +++ b/src/internal/verify.zig @@ -118,6 +118,11 @@ pub const Verifier = struct { /// resolve on the caller's own resolver, outside the cache lock fn resolveAndCache(self: *Verifier, resolver: *zat.DidResolver, did: []const u8) ?CachedKey { + // SSRF boundary (docs/lessons-from-zlay.md #10): did:plc resolves + // against the operator-configured PLC only; did:web would make us + // fetch an attacker-named host, so those pass unverified until the + // resolver grows private-host rejection + DNS preflight + no-redirect + if (!std.mem.startsWith(u8, did, "did:plc:")) return null; const doc_or_null: ?zat.DidDocument = doc: { const parsed = zat.Did.parse(did) orelse break :doc null; break :doc resolver.resolve(parsed) catch |err| { -- 2.51.2