From db91b88cc4cbfd7d44f064063f462bd47e3efe8b Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Tue, 4 Aug 2026 04:56:32 +0200 Subject: [PATCH] fix(test): stop asserting a scheduling race in the forged-identity test daemon_runtime_rejects_forged_identity_extension failed on the macos-15-intel CI leg. The suite is untouched by this branch and no daemon production code changed here; the leg flakes on main too, so this is a pre-existing defect the lane surfaced rather than a regression. The test asserted that transmitting the forged frame SUCCEEDS. It cannot be relied on to. The forged HELLO is 149 bytes against the 137-byte first-frame envelope cap, so the worker rejects it from the header and closes without ever reading the payload -- deliberately, so that no attacker-controlled bytes are read. send_frame writes the header and the payload as two separate writes, so whether the payload write lands before that close is pure scheduling: it wins on an idle host and loses on a loaded 4-vCPU runner. Both outcomes ARE the rejection, so the transmit result is now recorded and not asserted. Anti-vacuousness is preserved rather than dropped: the test now asserts it connected at all, and the drain check waits for the state it asserts (wait_for_clients 0) instead of sampling the count once, so the bound is a liveness backstop and never the verdict. Verified by mutation, not just by passing: with the envelope cap raised to 512 and the exact-length check removed -- a daemon that accepts the forged identity -- the repaired test goes RED on ASSERT(rejected). The mutation was reverted and the suite is 43/43 green. Signed-off-by: Martin Vogel --- tests/test_daemon_runtime.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/test_daemon_runtime.c b/tests/test_daemon_runtime.c index bc9504d82..b567ef2fa 100644 --- a/tests/test_daemon_runtime.c +++ b/tests/test_daemon_runtime.c @@ -2666,6 +2666,7 @@ TEST(daemon_runtime_rejects_forged_identity_extension) { uint64_t forged_client_id = UINT64_MAX - 1; uint64_t forged_process_id = UINT64_MAX; bool encoded = false; + bool connected = false; bool sent = false; bool rejected = false; cbm_daemon_frame_t response_frame = {0}; @@ -2679,12 +2680,27 @@ TEST(daemon_runtime_rejects_forged_identity_extension) { &forged_process_id, sizeof(forged_process_id)); raw = cbm_daemon_ipc_connect(fixture.endpoint, RUNTIME_TEST_TIMEOUT_MS); } + connected = raw != NULL; if (raw && encoded) { + /* The forged HELLO is 149 bytes against the 137-byte first-frame + * envelope cap, so the worker rejects it from the HEADER and closes + * without ever reading the payload -- deliberately, so that no + * attacker-controlled bytes are read (cbm_daemon_ipc_receive_frame_bounded). + * send_frame writes the header and the payload as two separate writes, + * so whether the payload write lands before that close is pure + * scheduling: it wins on an idle host and loses on a loaded one. Both + * outcomes ARE the rejection, so the transmit result is recorded and + * NOT asserted -- asserting it made the verdict a coin flip. */ sent = cbm_daemon_ipc_send_frame(raw, CBM_DAEMON_FRAME_REQUEST, CBM_DAEMON_RUNTIME_OP_HELLO, forged, (uint32_t)sizeof(forged)); - int received = cbm_daemon_ipc_receive_frame(raw, RUNTIME_TEST_TIMEOUT_MS, &response_frame, - &response_payload); - rejected = received != 1 && cbm_daemon_runtime_service_active_clients(fixture.service) == 0; + int received = sent ? cbm_daemon_ipc_receive_frame(raw, RUNTIME_TEST_TIMEOUT_MS, + &response_frame, &response_payload) + : 0; + /* Wait for the state actually asserted instead of sampling it once: the + * forged peer is the only client, so the count is monotonic here and the + * bound is a liveness backstop, never the verdict. */ + rejected = received != 1 && cbm_daemon_runtime_service_wait_for_clients( + fixture.service, 0, RUNTIME_TEST_TIMEOUT_MS); } free(response_payload); cbm_daemon_ipc_connection_close(raw); @@ -2715,7 +2731,7 @@ TEST(daemon_runtime_rejects_forged_identity_extension) { ASSERT_TRUE(started); ASSERT_TRUE(encoded); - ASSERT_TRUE(sent); + ASSERT_TRUE(connected); ASSERT_TRUE(rejected); ASSERT_TRUE(valid_after_rejection); ASSERT_TRUE(exited);