259 lines
14 KiB
PHP
259 lines
14 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\Audit;
|
|
|
|
enum AuditActionId: string
|
|
{
|
|
case WorkspaceMembershipAdd = 'workspace_membership.add';
|
|
case WorkspaceMembershipRoleChange = 'workspace_membership.role_change';
|
|
case WorkspaceMembershipRemove = 'workspace_membership.remove';
|
|
case WorkspaceMembershipLastOwnerBlocked = 'workspace_membership.last_owner_blocked';
|
|
case WorkspaceMembershipBreakGlassAssignOwner = 'workspace_membership.break_glass.assign_owner';
|
|
|
|
case TenantArchived = 'tenant.archived';
|
|
case TenantRestored = 'tenant.restored';
|
|
case TenantReturnedToDraft = 'tenant.returned_to_draft';
|
|
|
|
case TenantMembershipAdd = 'tenant_membership.add';
|
|
case TenantMembershipRoleChange = 'tenant_membership.role_change';
|
|
case TenantMembershipRemove = 'tenant_membership.remove';
|
|
case TenantMembershipLastOwnerBlocked = 'tenant_membership.last_owner_blocked';
|
|
|
|
// Not part of the v1 contract, but used in codebase.
|
|
case TenantMembershipBootstrapRecover = 'tenant_membership.bootstrap_recover';
|
|
|
|
// Diagnostics / repair actions.
|
|
case TenantMembershipDuplicatesMerged = 'tenant_membership.duplicates_merged';
|
|
|
|
// Managed tenant onboarding wizard.
|
|
case ManagedTenantOnboardingStart = 'managed_tenant_onboarding.start';
|
|
case ManagedTenantOnboardingResume = 'managed_tenant_onboarding.resume';
|
|
case ManagedTenantOnboardingDraftSelected = 'managed_tenant_onboarding.draft_selected';
|
|
case ManagedTenantOnboardingDraftUpdated = 'managed_tenant_onboarding.draft_updated';
|
|
case ManagedTenantOnboardingProviderConnectionChanged = 'managed_tenant_onboarding.provider_connection_changed';
|
|
case ManagedTenantOnboardingVerificationStart = 'managed_tenant_onboarding.verification_start';
|
|
case ManagedTenantOnboardingVerificationPersisted = 'managed_tenant_onboarding.verification_persisted';
|
|
case ManagedTenantOnboardingBootstrapStarted = 'managed_tenant_onboarding.bootstrap_started';
|
|
case ManagedTenantOnboardingCancelled = 'managed_tenant_onboarding.cancelled';
|
|
case ManagedTenantOnboardingActivationOverrideUsed = 'managed_tenant_onboarding.activation_override_used';
|
|
case ManagedTenantOnboardingActivation = 'managed_tenant_onboarding.activation';
|
|
case VerificationCompleted = 'verification.completed';
|
|
case VerificationCheckAcknowledged = 'verification.check_acknowledged';
|
|
|
|
case AlertDestinationCreated = 'alert_destination.created';
|
|
case AlertDestinationUpdated = 'alert_destination.updated';
|
|
case AlertDestinationDeleted = 'alert_destination.deleted';
|
|
case AlertDestinationEnabled = 'alert_destination.enabled';
|
|
case AlertDestinationDisabled = 'alert_destination.disabled';
|
|
case AlertDestinationTestRequested = 'alert_destination.test_requested';
|
|
|
|
case AlertRuleCreated = 'alert_rule.created';
|
|
case AlertRuleUpdated = 'alert_rule.updated';
|
|
case AlertRuleDeleted = 'alert_rule.deleted';
|
|
case AlertRuleEnabled = 'alert_rule.enabled';
|
|
case AlertRuleDisabled = 'alert_rule.disabled';
|
|
|
|
case WorkspaceSettingUpdated = 'workspace_setting.updated';
|
|
case WorkspaceSettingReset = 'workspace_setting.reset';
|
|
|
|
case BaselineProfileCreated = 'baseline_profile.created';
|
|
case BaselineProfileUpdated = 'baseline_profile.updated';
|
|
case BaselineProfileArchived = 'baseline_profile.archived';
|
|
case BaselineCaptureStarted = 'baseline_capture.started';
|
|
case BaselineCaptureCompleted = 'baseline_capture.completed';
|
|
case BaselineCaptureFailed = 'baseline_capture.failed';
|
|
case BaselineCompareStarted = 'baseline_compare.started';
|
|
case BaselineCompareCompleted = 'baseline_compare.completed';
|
|
case BaselineCompareFailed = 'baseline_compare.failed';
|
|
case BaselineAssignmentCreated = 'baseline_assignment.created';
|
|
case BaselineAssignmentUpdated = 'baseline_assignment.updated';
|
|
case BaselineAssignmentDeleted = 'baseline_assignment.deleted';
|
|
|
|
// Workspace selection / switch events (Spec 107).
|
|
case WorkspaceAutoSelected = 'workspace.auto_selected';
|
|
case WorkspaceSelected = 'workspace.selected';
|
|
|
|
/**
|
|
* @return array<string>
|
|
*/
|
|
public static function knownValues(): array
|
|
{
|
|
return array_map(
|
|
static fn (self $case): string => $case->value,
|
|
self::cases(),
|
|
);
|
|
}
|
|
|
|
public static function labelFor(string|self $action): string
|
|
{
|
|
$value = $action instanceof self ? $action->value : trim($action);
|
|
|
|
return self::labels()[$value] ?? self::humanize($value);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $context
|
|
*/
|
|
public static function summaryFor(
|
|
string|self $action,
|
|
?string $targetLabel = null,
|
|
?string $targetType = null,
|
|
array $context = [],
|
|
): string {
|
|
$value = $action instanceof self ? $action->value : trim($action);
|
|
$summary = self::summaries()[$value] ?? self::labelFor($value);
|
|
|
|
if ($targetLabel !== null && $targetLabel !== '' && ! str_contains($summary, $targetLabel)) {
|
|
$summary .= ' for '.$targetLabel;
|
|
} elseif (($targetLabel === null || $targetLabel === '') && filled($targetType)) {
|
|
$summary .= ' for '.self::humanize((string) $targetType);
|
|
}
|
|
|
|
if (($context['after_status'] ?? null) !== null && ($context['before_status'] ?? null) !== null && ! str_contains($summary, 'status')) {
|
|
return sprintf(
|
|
'%s (%s -> %s)',
|
|
$summary,
|
|
(string) $context['before_status'],
|
|
(string) $context['after_status'],
|
|
);
|
|
}
|
|
|
|
return $summary;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
private static function labels(): array
|
|
{
|
|
return [
|
|
self::WorkspaceMembershipAdd->value => 'Workspace member add',
|
|
self::WorkspaceMembershipRoleChange->value => 'Workspace member role change',
|
|
self::WorkspaceMembershipRemove->value => 'Workspace member removal',
|
|
self::WorkspaceMembershipLastOwnerBlocked->value => 'Workspace last-owner protection',
|
|
self::TenantArchived->value => 'Tenant archived',
|
|
self::TenantRestored->value => 'Tenant restored',
|
|
self::TenantReturnedToDraft->value => 'Tenant returned to draft',
|
|
self::TenantMembershipAdd->value => 'Tenant member add',
|
|
self::TenantMembershipRoleChange->value => 'Tenant member role change',
|
|
self::TenantMembershipRemove->value => 'Tenant member removal',
|
|
self::TenantMembershipLastOwnerBlocked->value => 'Tenant last-owner protection',
|
|
self::ManagedTenantOnboardingStart->value => 'Managed tenant onboarding start',
|
|
self::ManagedTenantOnboardingResume->value => 'Managed tenant onboarding resume',
|
|
self::ManagedTenantOnboardingDraftSelected->value => 'Managed tenant onboarding draft selected',
|
|
self::ManagedTenantOnboardingDraftUpdated->value => 'Managed tenant onboarding draft updated',
|
|
self::ManagedTenantOnboardingProviderConnectionChanged->value => 'Managed tenant onboarding provider connection changed',
|
|
self::ManagedTenantOnboardingVerificationStart->value => 'Managed tenant onboarding verification start',
|
|
self::ManagedTenantOnboardingVerificationPersisted->value => 'Managed tenant onboarding verification persisted',
|
|
self::ManagedTenantOnboardingBootstrapStarted->value => 'Managed tenant onboarding bootstrap started',
|
|
self::ManagedTenantOnboardingCancelled->value => 'Managed tenant onboarding cancelled',
|
|
self::ManagedTenantOnboardingActivationOverrideUsed->value => 'Managed tenant onboarding activation override used',
|
|
self::ManagedTenantOnboardingActivation->value => 'Managed tenant onboarding activation',
|
|
self::VerificationCompleted->value => 'Verification completed',
|
|
self::VerificationCheckAcknowledged->value => 'Verification check acknowledged',
|
|
self::AlertDestinationCreated->value => 'Alert destination created',
|
|
self::AlertDestinationUpdated->value => 'Alert destination updated',
|
|
self::AlertDestinationDeleted->value => 'Alert destination deleted',
|
|
self::AlertDestinationEnabled->value => 'Alert destination enabled',
|
|
self::AlertDestinationDisabled->value => 'Alert destination disabled',
|
|
self::AlertDestinationTestRequested->value => 'Alert destination test requested',
|
|
self::AlertRuleCreated->value => 'Alert rule created',
|
|
self::AlertRuleUpdated->value => 'Alert rule updated',
|
|
self::AlertRuleDeleted->value => 'Alert rule deleted',
|
|
self::AlertRuleEnabled->value => 'Alert rule enabled',
|
|
self::AlertRuleDisabled->value => 'Alert rule disabled',
|
|
self::WorkspaceSettingUpdated->value => 'Workspace setting updated',
|
|
self::WorkspaceSettingReset->value => 'Workspace setting reset',
|
|
self::BaselineProfileCreated->value => 'Baseline profile created',
|
|
self::BaselineProfileUpdated->value => 'Baseline profile updated',
|
|
self::BaselineProfileArchived->value => 'Baseline profile archived',
|
|
self::BaselineCaptureStarted->value => 'Baseline capture started',
|
|
self::BaselineCaptureCompleted->value => 'Baseline capture completed',
|
|
self::BaselineCaptureFailed->value => 'Baseline capture failed',
|
|
self::BaselineCompareStarted->value => 'Baseline compare started',
|
|
self::BaselineCompareCompleted->value => 'Baseline compare completed',
|
|
self::BaselineCompareFailed->value => 'Baseline compare failed',
|
|
self::BaselineAssignmentCreated->value => 'Baseline assignment created',
|
|
self::BaselineAssignmentUpdated->value => 'Baseline assignment updated',
|
|
self::BaselineAssignmentDeleted->value => 'Baseline assignment deleted',
|
|
self::WorkspaceAutoSelected->value => 'Workspace auto-selected',
|
|
self::WorkspaceSelected->value => 'Workspace selected',
|
|
'finding.triaged' => 'Finding triaged',
|
|
'finding.in_progress' => 'Finding moved to in progress',
|
|
'finding.assigned' => 'Finding assignment updated',
|
|
'finding.resolved' => 'Finding resolved',
|
|
'finding.closed' => 'Finding closed',
|
|
'finding.risk_accepted' => 'Finding risk accepted',
|
|
'finding.reopened' => 'Finding reopened',
|
|
'baseline.capture.started' => 'Baseline capture started',
|
|
'baseline.capture.completed' => 'Baseline capture completed',
|
|
'baseline.capture.failed' => 'Baseline capture failed',
|
|
'baseline.compare.started' => 'Baseline compare started',
|
|
'baseline.compare.completed' => 'Baseline compare completed',
|
|
'baseline.compare.failed' => 'Baseline compare failed',
|
|
'baseline.evidence.resume.started' => 'Baseline evidence capture resumed',
|
|
'backup.created' => 'Backup set created',
|
|
'backup.updated' => 'Backup set updated',
|
|
'backup.archived' => 'Backup set archived',
|
|
'backup.items_added' => 'Backup set items added',
|
|
'backup.assignments.included' => 'Backup set assignments included',
|
|
'backup_schedule.run_started' => 'Backup schedule run started',
|
|
'backup_schedule.run_finished' => 'Backup schedule run finished',
|
|
'backup_schedule.run_failed' => 'Backup schedule run failed',
|
|
'backup_schedule.run_skipped' => 'Backup schedule run skipped',
|
|
'backup_schedule.retention_applied' => 'Backup schedule retention applied',
|
|
'restore.started' => 'Restore started',
|
|
'restore.previewed' => 'Restore preview completed',
|
|
'restore.executed' => 'Restore executed',
|
|
'restore.failed' => 'Restore failed',
|
|
'restore.assignments.summary' => 'Restore assignment summary recorded',
|
|
'restore.group_mapping.applied' => 'Restore group mapping applied',
|
|
'operation.completed' => 'Operation completed',
|
|
'operation.failed' => 'Operation failed',
|
|
'operation.partial' => 'Operation partially completed',
|
|
'operation.blocked' => 'Operation blocked',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
private static function summaries(): array
|
|
{
|
|
return [
|
|
self::WorkspaceMembershipAdd->value => 'Workspace member added',
|
|
self::WorkspaceMembershipRoleChange->value => 'Workspace member role changed',
|
|
self::WorkspaceMembershipRemove->value => 'Workspace member removed',
|
|
self::WorkspaceMembershipLastOwnerBlocked->value => 'Workspace last-owner protection triggered',
|
|
self::TenantArchived->value => 'Tenant archived',
|
|
self::TenantRestored->value => 'Tenant restored',
|
|
self::TenantReturnedToDraft->value => 'Tenant returned to draft',
|
|
self::TenantMembershipAdd->value => 'Tenant member added',
|
|
self::TenantMembershipRoleChange->value => 'Tenant member role changed',
|
|
self::TenantMembershipRemove->value => 'Tenant member removed',
|
|
self::TenantMembershipLastOwnerBlocked->value => 'Tenant last-owner protection triggered',
|
|
self::WorkspaceSettingUpdated->value => 'Workspace setting updated',
|
|
self::WorkspaceSettingReset->value => 'Workspace setting reset',
|
|
self::BaselineProfileCreated->value => 'Baseline profile created',
|
|
self::BaselineProfileUpdated->value => 'Baseline profile updated',
|
|
self::BaselineProfileArchived->value => 'Baseline profile archived',
|
|
self::AlertDestinationCreated->value => 'Alert destination created',
|
|
self::AlertDestinationUpdated->value => 'Alert destination updated',
|
|
self::AlertDestinationDeleted->value => 'Alert destination deleted',
|
|
self::AlertRuleCreated->value => 'Alert rule created',
|
|
self::AlertRuleUpdated->value => 'Alert rule updated',
|
|
self::AlertRuleDeleted->value => 'Alert rule deleted',
|
|
];
|
|
}
|
|
|
|
private static function humanize(string $value): string
|
|
{
|
|
$normalized = str_replace(['.', '_', '-'], ' ', trim($value));
|
|
$normalized = preg_replace('/\s+/', ' ', $normalized) ?? $normalized;
|
|
|
|
return ucfirst($normalized);
|
|
}
|
|
}
|