mirror of
https://github.com/tiennm99/coolify.git
synced 2026-08-06 02:23:03 +00:00
feat(observability): add structured audit log channel for API and webhook events
Introduce a dedicated `audit` log channel (daily rotation, configurable retention via LOG_AUDIT_DAYS) and a small `auditLog()` / `auditLogWebhookFailure()` helper used to record state-changing API operations and webhook events. Instrumented: - API mutation endpoints (create / update / delete / start / stop / restart) across applications, services, databases (incl. backups, env vars, storage), servers, projects + environments, scheduled tasks, private keys, GitHub apps, cloud provider tokens, Hetzner server provisioning, instance enable/disable. - Webhook signature verification outcomes for GitHub, GitLab, Bitbucket, Gitea and Stripe, plus the Sentinel push endpoint. - Authentication and authorization outcomes via the global exception handler and the `ApiAbility` middleware (unauthenticated, ability-denied, policy-denied). The helper is wrapped in try/catch so logging failures never affect the request path. Successful operations log at `info`; suspicious/denied requests log at `warning`. Operators wanting a failures-only feed can set `LOG_AUDIT_LEVEL=warning`. Includes a feature test suite covering the helper, the webhook providers and the new auth/authorization log paths. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
923525a310
commit
a2096c6f68
@@ -58,6 +58,12 @@ class Bitbucket extends Controller
|
||||
foreach ($applications as $application) {
|
||||
$webhook_secret = data_get($application, 'manual_webhook_secret_bitbucket');
|
||||
if (empty($webhook_secret)) {
|
||||
auditLogWebhookFailure('bitbucket', 'webhook_secret_missing', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'application_name' => $application->name,
|
||||
'repository' => $full_name ?? null,
|
||||
'event' => $x_bitbucket_event,
|
||||
]);
|
||||
$return_payloads->push([
|
||||
'application' => $application->name,
|
||||
'status' => 'failed',
|
||||
@@ -70,6 +76,12 @@ class Bitbucket extends Controller
|
||||
|
||||
$parts = explode('=', $x_bitbucket_token, 2);
|
||||
if (count($parts) !== 2 || $parts[0] !== 'sha256') {
|
||||
auditLogWebhookFailure('bitbucket', 'malformed_signature', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'application_name' => $application->name,
|
||||
'repository' => $full_name ?? null,
|
||||
'event' => $x_bitbucket_event,
|
||||
]);
|
||||
$return_payloads->push([
|
||||
'application' => $application->name,
|
||||
'status' => 'failed',
|
||||
@@ -81,6 +93,12 @@ class Bitbucket extends Controller
|
||||
$hash = $parts[1];
|
||||
$payloadHash = hash_hmac('sha256', $payload, $webhook_secret);
|
||||
if (! hash_equals($hash, $payloadHash) && ! isDev()) {
|
||||
auditLogWebhookFailure('bitbucket', 'invalid_signature', [
|
||||
'application_uuid' => $application->uuid,
|
||||
'application_name' => $application->name,
|
||||
'repository' => $full_name ?? null,
|
||||
'event' => $x_bitbucket_event,
|
||||
]);
|
||||
$return_payloads->push([
|
||||
'application' => $application->name,
|
||||
'status' => 'failed',
|
||||
@@ -118,6 +136,15 @@ class Bitbucket extends Controller
|
||||
'message' => $result['message'],
|
||||
]);
|
||||
} else {
|
||||
auditLog('webhook.deployment.queued', [
|
||||
'provider' => 'bitbucket',
|
||||
'mode' => 'manual',
|
||||
'application_uuid' => $application->uuid,
|
||||
'application_name' => $application->name,
|
||||
'deployment_uuid' => $deployment_uuid->toString(),
|
||||
'commit' => $commit,
|
||||
'repository' => $full_name ?? null,
|
||||
]);
|
||||
$return_payloads->push([
|
||||
'application' => $application->name,
|
||||
'status' => 'success',
|
||||
|
||||
Reference in New Issue
Block a user