@@ -561,11 +561,13 @@ int ssh_test_connection(const account_t *account, const char *host) { |
| 561 | 561 | |
| 562 | 562 | log_debug("Testing SSH connection to: %s", host); |
| 563 | 563 | |
| 564 | | - /* Build SSH test command */ |
| 564 | + /* Build SSH test command using -T (no TTY) for git hosting services |
| 565 | + * GitHub/GitLab/Bitbucket don't allow shell commands, they return a |
| 566 | + * greeting message on successful auth (exit code 1 but with success message) */ |
| 565 | 567 | if (strlen(account->ssh_host_alias) > 0) { |
| 566 | 568 | /* Use host alias */ |
| 567 | | - if ((size_t)snprintf(command, sizeof(command), |
| 568 | | - "ssh -o ConnectTimeout=5 -o BatchMode=yes %s echo 'SSH connection test successful'", |
| 569 | + if ((size_t)snprintf(command, sizeof(command), |
| 570 | + "ssh -T -o ConnectTimeout=5 -o BatchMode=yes %s 2>&1", |
| 569 | 571 | account->ssh_host_alias) >= sizeof(command)) { |
| 570 | 572 | set_error(ERR_INVALID_ARGS, "SSH test command too long"); |
| 571 | 573 | return -1; |
@@ -576,28 +578,31 @@ int ssh_test_connection(const account_t *account, const char *host) { |
| 576 | 578 | if (expand_path(account->ssh_key_path, expanded_key_path, sizeof(expanded_key_path)) != 0) { |
| 577 | 579 | return -1; |
| 578 | 580 | } |
| 579 | | - |
| 581 | + |
| 580 | 582 | if ((size_t)snprintf(command, sizeof(command), |
| 581 | | - "ssh -o ConnectTimeout=5 -o BatchMode=yes -i '%s' %s echo 'SSH connection test successful'", |
| 583 | + "ssh -T -o ConnectTimeout=5 -o BatchMode=yes -i '%s' %s 2>&1", |
| 582 | 584 | expanded_key_path, host) >= sizeof(command)) { |
| 583 | 585 | set_error(ERR_INVALID_ARGS, "SSH test command too long"); |
| 584 | 586 | return -1; |
| 585 | 587 | } |
| 586 | 588 | } |
| 587 | | - |
| 588 | | - /* Execute SSH test */ |
| 589 | | - if (execute_ssh_command(command, output, sizeof(output)) != 0) { |
| 590 | | - set_error(ERR_SSH_CONNECTION_FAILED, "SSH connection test failed to %s: %s", host, output); |
| 591 | | - return -1; |
| 592 | | - } |
| 593 | | - |
| 594 | | - if (!strstr(output, "SSH connection test successful")) { |
| 595 | | - set_error(ERR_SSH_CONNECTION_FAILED, "SSH connection test did not return expected output"); |
| 596 | | - return -1; |
| 589 | + |
| 590 | + /* Execute SSH test - for git hosts, check output for success indicators |
| 591 | + * Note: GitHub returns exit code 1 even on success (no shell access) */ |
| 592 | + (void)execute_ssh_command(command, output, sizeof(output)); |
| 593 | + |
| 594 | + /* Check for authentication success messages from common git hosting services */ |
| 595 | + if (strstr(output, "successfully authenticated") || /* GitHub */ |
| 596 | + strstr(output, "Welcome to GitLab") || /* GitLab */ |
| 597 | + strstr(output, "logged in as") || /* Bitbucket */ |
| 598 | + strstr(output, "Hi ") || /* GitHub greeting */ |
| 599 | + strstr(output, "authentication successful")) { /* Generic */ |
| 600 | + log_debug("SSH authentication successful to %s", host); |
| 601 | + return 0; |
| 597 | 602 | } |
| 598 | | - |
| 599 | | - log_info("SSH connection test successful to: %s", host); |
| 600 | | - return 0; |
| 603 | + |
| 604 | + log_debug("SSH connection test failed to %s: %s", host, output); |
| 605 | + return -1; |
| 601 | 606 | } |
| 602 | 607 | |
| 603 | 608 | /* Internal helper functions */ |