@@ -1846,6 +1846,39 @@ TEST(daemon_runtime_exact_hello_issues_connection_bound_identity) {
18461846 PASS ();
18471847}
18481848
1849+ /* Regression for #1383: an image-verification rejection must be ANSWERED, not
1850+ * silently dropped. The old path logged daemon.client_image_rejected and
1851+ * finished the worker without sending a hello response, so the client sat on
1852+ * "pending" indefinitely - indistinguishable from a slow cold start - with the
1853+ * reason visible only in the daemon log. */
1854+ TEST (daemon_runtime_image_rejection_reaches_client_issue1383 ) {
1855+ cbm_daemon_build_identity_t identity =
1856+ runtime_test_identity ("2.4.0" , runtime_test_self_build ());
1857+ runtime_test_fixture_t fixture ;
1858+ bool started = runtime_test_fixture_start (& fixture , "image-reject" , & identity );
1859+ cbm_daemon_runtime_connect_result_t result = {0 };
1860+ cbm_daemon_runtime_client_t * client = NULL ;
1861+
1862+ cbm_daemon_runtime_force_peer_image_unverified_for_testing (true);
1863+ if (started ) {
1864+ client = cbm_daemon_runtime_client_connect (fixture .endpoint , & identity ,
1865+ RUNTIME_TEST_TIMEOUT_MS , & result );
1866+ }
1867+ cbm_daemon_runtime_force_peer_image_unverified_for_testing (false);
1868+
1869+ bool rejected_with_reason = client == NULL &&
1870+ result .status == CBM_DAEMON_RUNTIME_CONNECT_REJECTED &&
1871+ strstr (result .message , "image_unverifiable" ) != NULL ;
1872+ if (client ) {
1873+ (void )cbm_daemon_runtime_client_close (client , RUNTIME_TEST_TIMEOUT_MS );
1874+ }
1875+ runtime_test_fixture_finish (& fixture );
1876+
1877+ ASSERT_TRUE (started );
1878+ ASSERT_TRUE (rejected_with_reason );
1879+ PASS ();
1880+ }
1881+
18491882TEST (daemon_runtime_unexpected_frame_payload_is_freed_once ) {
18501883 static const uint8_t unexpected_payload [] = {0xde , 0xad , 0xbe , 0xef };
18511884 cbm_daemon_build_identity_t identity =
@@ -4387,7 +4420,6 @@ TEST(daemon_runtime_process_fingerprint_never_hashes_replacement_path) {
43874420}
43884421#endif
43894422
4390-
43914423TEST (daemon_runtime_close_begin_releases_admission_with_inflight_request ) {
43924424 static const uint8_t request [] = {'b' , 'l' , 'o' , 'c' , 'k' };
43934425 cbm_daemon_build_identity_t identity =
@@ -4436,9 +4468,8 @@ TEST(daemon_runtime_close_begin_releases_admission_with_inflight_request) {
44364468 /* The parity contract: after close_begin alone — before the handle
44374469 * closes — the daemon has released this client's admission. POSIX learns
44384470 * through shutdown()/EOF; Windows through the CLOSE_INTENT frame. */
4439- admission_released_at_begin =
4440- close_begun &&
4441- cbm_daemon_runtime_service_wait_for_clients (fixture .service , 0 , RUNTIME_TEST_TIMEOUT_MS );
4471+ admission_released_at_begin = close_begun && cbm_daemon_runtime_service_wait_for_clients (
4472+ fixture .service , 0 , RUNTIME_TEST_TIMEOUT_MS );
44424473 if (request_thread_started ) {
44434474 request_thread_joined = cbm_thread_join (& request_thread ) == 0 ;
44444475 request_thread_started = false;
@@ -4449,9 +4480,8 @@ TEST(daemon_runtime_close_begin_releases_admission_with_inflight_request) {
44494480 call .status == CBM_DAEMON_RUNTIME_APPLICATION_CANCELLED ) &&
44504481 call .response == NULL && call .response_length == 0 ;
44514482 if (client ) {
4452- (void )(close_begun
4453- ? cbm_daemon_runtime_client_close_finish (client , RUNTIME_TEST_TIMEOUT_MS )
4454- : cbm_daemon_runtime_client_close (client , RUNTIME_TEST_TIMEOUT_MS ));
4483+ (void )(close_begun ? cbm_daemon_runtime_client_close_finish (client , RUNTIME_TEST_TIMEOUT_MS )
4484+ : cbm_daemon_runtime_client_close (client , RUNTIME_TEST_TIMEOUT_MS ));
44554485 client = NULL ;
44564486 }
44574487 if (started ) {
@@ -4584,6 +4614,7 @@ SUITE(daemon_runtime) {
45844614 RUN_TEST (daemon_runtime_convenience_service_owns_participant_guard );
45854615 RUN_TEST (daemon_runtime_rendezvous_layout_is_frozen_and_detailed_abi_independent );
45864616 RUN_TEST (daemon_runtime_exact_hello_issues_connection_bound_identity );
4617+ RUN_TEST (daemon_runtime_image_rejection_reaches_client_issue1383 );
45874618 RUN_TEST (daemon_runtime_unexpected_frame_payload_is_freed_once );
45884619 RUN_TEST (daemon_runtime_activation_rejects_forged_and_malformed_without_stop );
45894620 RUN_TEST (daemon_runtime_activation_ack_snapshots_then_interrupts_all_clients );
0 commit comments