diff --git a/scripts/security-fuzz.sh b/scripts/security-fuzz.sh index a396f609f..52ed25c54 100755 --- a/scripts/security-fuzz.sh +++ b/scripts/security-fuzz.sh @@ -91,7 +91,7 @@ test_invalid_index_interactive() { HOME="$FUZZ_HOME" CBM_CACHE_DIR="$FUZZ_CACHE" \ python3 "$(dirname "$0")/test_mcp_interactive.py" "$BINARY" \ --scenario invalid-index --repo-path /nonexistent/path/abc123 \ - --response-timeout 30 --exit-timeout 15 > "$tmpoutput" 2>&1 || ec=$? + --response-timeout 45 --exit-timeout 15 > "$tmpoutput" 2>&1 || ec=$? if [[ $ec -eq 0 ]]; then PASS=$((PASS + 1)) diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 04e6225f5..be84d1fbc 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -564,7 +564,7 @@ echo "=== Phase 4: security checks ===" echo "Testing clean shutdown..." if ! python3 "$REPO_ROOT/scripts/test_mcp_interactive.py" \ "$BINARY" --scenario initialize --repo-path "$TMPDIR" \ - --response-timeout 30 --exit-timeout 8 > /dev/null; then + --response-timeout 45 --exit-timeout 8 > /dev/null; then echo "FAIL: initialized binary did not exit within 8 seconds after EOF" exit 1 fi @@ -601,7 +601,7 @@ echo "=== Phase 5: MCP stdio transport (agent handshake) ===" # Helper: run binary in background with input, wait up to N seconds, collect output mcp_run() { - local input_file="$1" output_file="$2" max_wait="${3:-10}" + local input_file="$1" output_file="$2" max_wait="${3:-45}" "$BINARY" < "$input_file" > "$output_file" 2>/dev/null & local pid=$! local waited=0 @@ -621,7 +621,7 @@ cat > "$MCP_INPUT" << 'MCPEOF' {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}} MCPEOF -mcp_run "$MCP_INPUT" "$MCP_OUTPUT" 10 +mcp_run "$MCP_INPUT" "$MCP_OUTPUT" 45 # 5a: Verify initialize response (id:1) if ! grep -q '"id":1' "$MCP_OUTPUT"; then @@ -706,7 +706,7 @@ TOOLS_MSG='{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' TOOLS_LEN=${#TOOLS_MSG} printf "Content-Length: %d\r\n\r\n%s" "$TOOLS_LEN" "$TOOLS_MSG" >> "$MCP_CL_INPUT" -mcp_run "$MCP_CL_INPUT" "$MCP_CL_OUTPUT" 10 +mcp_run "$MCP_CL_INPUT" "$MCP_CL_OUTPUT" 45 if ! grep -q '"id":1' "$MCP_CL_OUTPUT" || ! grep -q '"id":2' "$MCP_CL_OUTPUT"; then echo "FAIL: Content-Length framed handshake did not produce both responses" @@ -3154,7 +3154,7 @@ echo "=== Phase 16: stdio server leaves no orphan after shutdown ===" "$BINARY" < /dev/null > /dev/null 2>&1 & SHUT_SRV_PID=$! SHUT_GONE=0 -for _ in $(seq 1 60); do # bounded ~6s wait (60 × 0.1s) +for _ in $(seq 1 400); do # bounded ~40s wait (400 × 0.1s) if ! kill -0 "$SHUT_SRV_PID" 2>/dev/null; then SHUT_GONE=1; break; fi sleep 0.1 done diff --git a/scripts/test_mcp_interactive.py b/scripts/test_mcp_interactive.py index 5421bd514..4db2a902c 100644 --- a/scripts/test_mcp_interactive.py +++ b/scripts/test_mcp_interactive.py @@ -271,7 +271,7 @@ def main() -> int: required=True, ) parser.add_argument("--repo-path", required=True) - parser.add_argument("--response-timeout", type=float, default=30.0) + parser.add_argument("--response-timeout", type=float, default=45.0) parser.add_argument("--exit-timeout", type=float, default=15.0) args = parser.parse_args() diff --git a/src/cli/cli.c b/src/cli/cli.c index 4d2364a4e..7641a1228 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -1191,6 +1191,7 @@ void cbm_cli_set_activation_cleanup_failure_for_test(bool enabled); int cbm_cli_activation_abort_cleanup_probe_for_test(void); #endif +#if !defined(_WIN32) || defined(CBM_CLI_ENABLE_TEST_API) static void cli_activation_transaction_abort_or_fail_stop( cbm_activation_transaction_t **transaction_io, const char *component) { int cleanup_status = cli_activation_transaction_abort(transaction_io); @@ -1204,6 +1205,7 @@ static void cli_activation_transaction_abort_or_fail_stop( component ? component : "activation_transaction_cleanup"); } } +#endif #ifdef CBM_CLI_ENABLE_TEST_API void cbm_cli_set_activation_cleanup_failure_for_test(bool enabled) { diff --git a/src/main.c b/src/main.c index 0c5dd7cab..d76546993 100644 --- a/src/main.c +++ b/src/main.c @@ -37,6 +37,7 @@ enum { MAIN_PATH_CAP = 4096, MAIN_CONNECT_TIMEOUT_MS = 1000, MAIN_STARTUP_TIMEOUT_MS = 10000, + MAIN_MCP_STARTUP_TIMEOUT_MS = 30000, MAIN_REQUEST_TIMEOUT_MS = 24 * 60 * 60 * 1000, MAIN_HOOK_CONNECT_TIMEOUT_MS = 250, MAIN_HOOK_STARTUP_TIMEOUT_MS = 1500, @@ -1631,7 +1632,7 @@ int main(int argc, char **argv) { ? cbm_version_cohort_acquire(client_cohort_manager, &identity, main_deadline_after(role == CBM_DAEMON_PROCESS_HOOK_CLIENT ? MAIN_HOOK_STARTUP_TIMEOUT_MS - : MAIN_STARTUP_TIMEOUT_MS), + : MAIN_MCP_STARTUP_TIMEOUT_MS), &client_cohort_lease, &client_cohort_conflict) : CBM_VERSION_COHORT_IO; if (client_cohort_status != CBM_VERSION_COHORT_OK) { @@ -1657,7 +1658,7 @@ int main(int argc, char **argv) { .connect_timeout_ms = role == CBM_DAEMON_PROCESS_HOOK_CLIENT ? MAIN_HOOK_CONNECT_TIMEOUT_MS : MAIN_CONNECT_TIMEOUT_MS, .startup_timeout_ms = role == CBM_DAEMON_PROCESS_HOOK_CLIENT ? MAIN_HOOK_STARTUP_TIMEOUT_MS - : MAIN_STARTUP_TIMEOUT_MS, + : MAIN_MCP_STARTUP_TIMEOUT_MS, }; cbm_daemon_bootstrap_result_t bootstrap_result; cbm_daemon_bootstrap_status_t bootstrap_status =