new git integraton code
This commit is contained in:
@@ -64,16 +64,6 @@ final class GitWebhookController
|
||||
$deliveryId = $this->deliveryId($request, $provider);
|
||||
$rawPayload = $request->getContent();
|
||||
|
||||
if (! $this->hasValidGiteaAuthorization($request)) {
|
||||
return response()->json([
|
||||
'status' => 'rejected',
|
||||
'message' => 'Gitea webhook authorization failed.',
|
||||
'commit_count' => 0,
|
||||
'linked_count' => 0,
|
||||
'ignored_count' => 1,
|
||||
], 403);
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var array<string, mixed> $payload */
|
||||
$payload = json_decode($rawPayload, true, 512, JSON_THROW_ON_ERROR);
|
||||
@@ -99,9 +89,9 @@ final class GitWebhookController
|
||||
], 404);
|
||||
}
|
||||
|
||||
if (! $this->hasValidSignature($request, $repository, $provider, $rawPayload)) {
|
||||
if (! $this->hasValidGiteaSecurity($request, $repository, $provider, $rawPayload)) {
|
||||
$result = ['status' => 'rejected', 'message' => 'Git webhook signature or token validation failed.', 'commit_count' => 0, 'linked_count' => 0, 'ignored_count' => 1];
|
||||
$service->logWebhook($repository, $provider, $deliveryId, $event, $result);
|
||||
$service->logWebhook($repository, $provider, $deliveryId, $event, $result, $payload);
|
||||
|
||||
return response()->json($result, 403);
|
||||
}
|
||||
@@ -198,6 +188,19 @@ final class GitWebhookController
|
||||
|| hash_equals('sha1=' . hash_hmac('sha1', $rawPayload, $secret), $signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Gitea webhook security without allowing an optional Authorization
|
||||
* header mismatch to hide otherwise valid signed push deliveries.
|
||||
*/
|
||||
private function hasValidGiteaSecurity(Request $request, GitRepository $repository, string $provider, string $rawPayload): bool
|
||||
{
|
||||
if ($this->hasValidSignature($request, $repository, $provider, $rawPayload)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasValidGiteaAuthorization($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the optional Authorization header configured for the local Gitea webhook.
|
||||
*/
|
||||
|
||||
@@ -221,7 +221,7 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_gitea_local_webhook_rejects_invalid_authorization_without_creating_commits(): void
|
||||
public function test_gitea_local_webhook_rejects_invalid_signature_and_authorization_without_creating_commits(): void
|
||||
{
|
||||
config()->set('services.gitea.webhook_authorization', 'YWxhZGRpbjpvcGVuc2VzYW1l');
|
||||
|
||||
@@ -242,7 +242,7 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
'HTTP_ACCEPT' => 'application/json',
|
||||
'HTTP_AUTHORIZATION' => 'Basic invalid',
|
||||
'HTTP_X_GITEA_EVENT' => 'push',
|
||||
'HTTP_X_GITEA_SIGNATURE' => hash_hmac('sha256', $json, 'gitea-secret'),
|
||||
'HTTP_X_GITEA_SIGNATURE' => hash_hmac('sha256', $json, 'wrong-secret'),
|
||||
], $json);
|
||||
|
||||
$response->assertForbidden()->assertJsonPath('status', 'rejected');
|
||||
@@ -250,6 +250,37 @@ final class GitWebhookIngestionTest extends TestCase
|
||||
self::assertSame(0, GitCommit::query()->count());
|
||||
}
|
||||
|
||||
public function test_gitea_local_webhook_accepts_valid_signature_when_optional_authorization_header_differs(): void
|
||||
{
|
||||
config()->set('services.gitea.webhook_authorization', 'expected-basic-token');
|
||||
|
||||
$repository = $this->repository([
|
||||
'provider' => 'gitea',
|
||||
'remote_url' => 'http://git.vm:3000/Admin/WMS-Core.git',
|
||||
'webhook_secret' => 'gitea-secret',
|
||||
]);
|
||||
$payload = [
|
||||
'ref' => 'refs/heads/main',
|
||||
'repository' => ['clone_url' => 'http://git.vm:3000/Admin/WMS-Core.git'],
|
||||
'commits' => [['id' => str_repeat('b', 40), 'message' => 'Valid signed Gitea push']],
|
||||
];
|
||||
$json = json_encode($payload, JSON_THROW_ON_ERROR);
|
||||
|
||||
$response = $this->call('POST', route('api.git.gitea.webhook'), [], [], [], [
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
'HTTP_ACCEPT' => 'application/json',
|
||||
'HTTP_AUTHORIZATION' => 'Basic something-different-from-gitea-ui',
|
||||
'HTTP_X_GITEA_EVENT' => 'push',
|
||||
'HTTP_X_GITEA_SIGNATURE' => hash_hmac('sha256', $json, 'gitea-secret'),
|
||||
], $json);
|
||||
|
||||
$response->assertStatus(202)->assertJsonPath('status', 'accepted')->assertJsonPath('commit_count', 1);
|
||||
|
||||
$this->assertDatabaseHas('helpdesk_git_commits', [
|
||||
'repository_id' => $repository->id,
|
||||
'hash' => str_repeat('b', 40),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_gitea_local_webhook_accepts_prefixed_signature_and_case_insensitive_provider(): void
|
||||
{
|
||||
|
||||
@@ -480,3 +480,14 @@
|
||||
- Reset the optional local Gitea Authorization config inside the prefixed-signature regression test so prior authorization tests cannot leak state into it.
|
||||
- Preserved the existing local Gitea webhook runtime handling, routes, repository matching and ingestion logic.
|
||||
- Preserved append-only changelog history.
|
||||
|
||||
- version: 1.10.20
|
||||
date: 2026-06-24
|
||||
type: bugfix
|
||||
summary: Prevent optional Gitea Authorization header mismatches from hiding valid signed push deliveries.
|
||||
changes:
|
||||
- Changed the local Gitea webhook security flow so a valid repository HMAC signature accepts the push even when the optional Authorization header differs from the configured value.
|
||||
- Kept invalid Gitea deliveries rejected when both the signature and optional Authorization validation fail.
|
||||
- Logged rejected Gitea deliveries against the matched repository after payload parsing so future webhook failures are visible in Helpdesk Git webhook logs.
|
||||
- Added regression coverage for valid signed Gitea pushes with a mismatched optional Authorization header.
|
||||
- Preserved append-only changelog history.
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.10.18"
|
||||
"version": "1.10.20"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user