test(marmot): pin the broker's certificate in the stream tests

Tests 18 and 19 failed inside TLS before a single frame was written:

  CRYPTO_ERROR (TLS alert 42): certificate chain validation failed:
  PKIX path building failed: unable to find valid certification path

The reference broker generates a self-signed certificate — its startup JSON
says so, `"tls":"generated_self_signed"` — and there is no CA anywhere in this
picture, so chaining it to the JDK trust store could never have worked. The
binding anticipates exactly this: a client MAY pin the endpoint certificate by
SHA-256 instead of chaining, which is what `--pin-sha256` and
`PinnedCertificateValidator` are for. The broker prints the fingerprint the
pin needs, in the same JSON line the harness already waits on; the harness
just never read it.

So `start_quic_broker` now captures `server_cert_sha256_fingerprint` and fails
loudly if it is absent, and the three `amy marmot stream send|watch` calls pass
it. `wn` reaches the same place with `--insecure-local`; pinning is the better
half of that trade, since the peer still has to sign the TLS transcript with
the pinned certificate's private key.

25 passed, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq
This commit is contained in:
Claude
2026-09-09 23:32:41 +00:00
parent b3b4fdaf43
commit 99433d9f5c
3 changed files with 19 additions and 4 deletions
@@ -61,6 +61,8 @@ BROKER_HOST="${BROKER_HOST:-127.0.0.1}"
BROKER_PORT="${BROKER_PORT:-4455}"
BROKER_URI="quic://$BROKER_HOST:$BROKER_PORT"
BROKER_PID=""
# SHA-256 of the broker's self-signed leaf, read from its startup JSON.
BROKER_PIN=""
# A loopback Blossom blob store for the encrypted-media tests. Ciphertext only:
# the file key comes from each group's MLS exporter and never reaches it.
+12 -1
View File
@@ -143,7 +143,18 @@ start_quic_broker() {
local deadline=$(( $(date +%s) + 15 ))
while [[ $(date +%s) -lt $deadline ]]; do
if grep -q '"local_addr"' "$STATE_DIR/broker/stdout.log" 2>/dev/null; then
info "broker pid $BROKER_PID ready"
# The broker generates a self-signed certificate and prints its
# fingerprint. `amy` pins that exact leaf rather than trusting a chain —
# there is no CA in this picture, and without the pin every stream test
# fails inside TLS before a single frame is written.
BROKER_PIN=$(sed -n 's/.*"server_cert_sha256_fingerprint":"\([0-9a-f]*\)".*/\1/p' \
"$STATE_DIR/broker/stdout.log" | head -1)
if [[ -z "$BROKER_PIN" ]]; then
fail_msg "broker printed no server_cert_sha256_fingerprint — cannot pin it"
BROKER_PID=""
return 1
fi
info "broker pid $BROKER_PID ready (cert ${BROKER_PIN:0:16}…)"
return 0
fi
if ! kill -0 "$BROKER_PID" 2>/dev/null; then break; fi
+5 -3
View File
@@ -456,7 +456,7 @@ test_18_agent_stream_amy_publishes() {
local send_json thash chunks
send_json=$(amy_json marmot stream send "$gid" --stream-id "$sid" --start-event-id "$seid" \
--broker "$BROKER_URI" "Hello " "from " "amethyst") || {
--broker "$BROKER_URI" --pin-sha256 "$BROKER_PIN" "Hello " "from " "amethyst") || {
record_result "$id" fail "amy stream send failed"; return
}
thash=$(printf '%s' "$send_json" | jq -r '.transcript_hash // empty')
@@ -466,7 +466,8 @@ test_18_agent_stream_amy_publishes() {
# Our own subscriber must recover the stream from the broker's replay window
# and fold it to the same transcript the publisher computed.
local watch_json
watch_json=$(amy_json marmot stream watch "$gid" --stream-id "$sid" --timeout 15) || {
watch_json=$(amy_json marmot stream watch "$gid" --stream-id "$sid" --timeout 15 \
--pin-sha256 "$BROKER_PIN") || {
record_result "$id" fail "amy stream watch failed"; return
}
printf 'stream18 watch=%s\n' "$watch_json" >>"$LOG_FILE"
@@ -535,7 +536,8 @@ test_19_agent_stream_wn_publishes() {
fi
local watch_out="$STATE_DIR/stream-19-watch.json"
( amy_a marmot stream watch "$gid" --stream-id "$wsid" --timeout 25 >"$watch_out" 2>>"$LOG_FILE" ) &
( amy_a marmot stream watch "$gid" --stream-id "$wsid" --timeout 25 \
--pin-sha256 "$BROKER_PIN" >"$watch_out" 2>>"$LOG_FILE" ) &
local watch_pid=$!
sleep 4