fix(git): parse generic scp-style SSH URLs with custom users

Centralize scp-style Git URL parsing so user@host:path (including custom
usernames and embedded ports) is accepted and converted to HTTPS for
public clones, API create, webhooks, validation, and commit/branch links.
This commit is contained in:
Andras Bacsai
2026-09-08 20:33:45 +02:00
parent e9bf2551ed
commit 83714ea395
15 changed files with 361 additions and 41 deletions
@@ -1460,7 +1460,13 @@ class ApplicationsController extends Controller
$application->docker_compose_domains = json_encode($dockerComposeDomainsJson);
$application->domain_port_overrides = $domainPortOverrides;
}
$repository_url_parsed = Url::fromString($request->git_repository);
$gitRepository = $application->git_repository;
$httpsRepository = scpStyleGitUrlToHttps($gitRepository);
if (is_string($httpsRepository)) {
$gitRepository = $httpsRepository;
$application->git_repository = $httpsRepository;
}
$repository_url_parsed = Url::fromString($gitRepository);
$git_host = $repository_url_parsed->getHost();
if ($git_host === 'github.com') {
$application->source_type = GithubApp::class;
@@ -1622,11 +1628,7 @@ class ApplicationsController extends Controller
return response()->json(['message' => 'Failed to generate Github App token.'], 400);
}
$gitRepository = $request->git_repository;
if (str($gitRepository)->startsWith('http') || str($gitRepository)->contains('github.com')) {
$gitRepository = str($gitRepository)->replace('https://', '')->replace('http://', '')->replace('github.com/', '');
}
$gitRepository = str($gitRepository)->trim('/')->replaceEnd('.git', '')->toString();
$gitRepository = gitRepositorySlug($request->git_repository);
// Use direct API call to verify repository access instead of loading all repositories
// This is much faster and avoids timeouts for GitHub Apps with many repositories
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Webhook\Concerns;
use App\Models\Application;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
trait MatchesManualWebhookApplications
{
@@ -79,12 +78,8 @@ trait MatchesManualWebhookApplications
if (is_array($parts) && isset($parts['scheme'])) {
$path = data_get($parts, 'path');
} elseif (preg_match('/^[A-Za-z0-9._-]+@[^:]+:/', $gitRepository) === 1) {
$path = Str::after($gitRepository, ':');
// scp-style SSH URLs embed a custom port as "user@host:2222/owner/repo".
// Strip the leading numeric port segment so the path matches the webhook
// payload's owner/repo, consistent with convertGitUrl() in shared.php.
$path = preg_replace('#^\d+/#', '', $path) ?? $path;
} elseif (($scp = parseScpStyleGitUrl($gitRepository)) !== null) {
$path = $scp['path'];
} else {
$path = $gitRepository;
}