Consolidate audit permissions to audit namespace

This commit is contained in:
2026-04-24 14:46:38 +02:00
parent e9f210decb
commit 4b9ce4bbad
8 changed files with 227 additions and 19 deletions

View File

@@ -1,5 +1,13 @@
{
"Telemetry helps detect recurring UI issues and failed requests in production.": "Telemetry hilft, wiederkehrende UI-Probleme und fehlgeschlagene Requests in Produktion zu erkennen.",
"perm.audit.api.view": "API-Protokolle anzeigen",
"perm.audit.api.purge": "API-Protokolle bereinigen",
"perm.audit.system.view": "System-Protokolle anzeigen",
"perm.audit.system.purge": "System-Protokolle bereinigen",
"perm.audit.imports.view": "Import-Protokolle anzeigen",
"perm.audit.imports.purge": "Import-Protokolle bereinigen",
"perm.audit.user_lifecycle.view": "Benutzer-Lifecycle-Protokolle anzeigen",
"perm.audit.user_lifecycle.restore": "Benutzer aus Lifecycle-Protokoll wiederherstellen",
"perm.user_lifecycle_audit.view": "Benutzer-Lifecycle-Protokolle anzeigen",
"perm.users.lifecycle_restore": "Benutzer aus Lifecycle-Protokoll wiederherstellen",
"User lifecycle": "Benutzer-Lebenszyklus",

View File

@@ -1,5 +1,13 @@
{
"Telemetry helps detect recurring UI issues and failed requests in production.": "Telemetry helps detect recurring UI issues and failed requests in production.",
"perm.audit.api.view": "View API logs",
"perm.audit.api.purge": "Purge API logs",
"perm.audit.system.view": "View system logs",
"perm.audit.system.purge": "Purge system logs",
"perm.audit.imports.view": "View import audit logs",
"perm.audit.imports.purge": "Purge import audit logs",
"perm.audit.user_lifecycle.view": "View user lifecycle logs",
"perm.audit.user_lifecycle.restore": "Restore users from lifecycle audit",
"perm.user_lifecycle_audit.view": "View user lifecycle logs",
"perm.users.lifecycle_restore": "Restore users from lifecycle audit",
"User lifecycle": "User lifecycle",

View File

@@ -18,14 +18,14 @@ final class AuditAuthorizationPolicy implements AuthorizationPolicyInterface
public const ABILITY_USER_LIFECYCLE_RESTORE = 'audit.user_lifecycle.restore';
private const ABILITY_PERMISSION_MAP = [
self::ABILITY_API_AUDIT_VIEW => 'api_audit.view',
self::ABILITY_API_AUDIT_VIEW => 'audit.api.view',
self::ABILITY_API_AUDIT_PURGE => 'audit.api.purge',
self::ABILITY_SYSTEM_AUDIT_VIEW => 'system_audit.view',
self::ABILITY_SYSTEM_AUDIT_PURGE => 'system_audit.purge',
self::ABILITY_IMPORTS_AUDIT_VIEW => 'imports.audit.view',
self::ABILITY_SYSTEM_AUDIT_VIEW => 'audit.system.view',
self::ABILITY_SYSTEM_AUDIT_PURGE => 'audit.system.purge',
self::ABILITY_IMPORTS_AUDIT_VIEW => 'audit.imports.view',
self::ABILITY_IMPORTS_AUDIT_PURGE => 'audit.imports.purge',
self::ABILITY_USER_LIFECYCLE_VIEW => 'user_lifecycle_audit.view',
self::ABILITY_USER_LIFECYCLE_RESTORE => 'users.lifecycle_restore',
self::ABILITY_USER_LIFECYCLE_VIEW => 'audit.user_lifecycle.view',
self::ABILITY_USER_LIFECYCLE_RESTORE => 'audit.user_lifecycle.restore',
];
public function __construct(

View File

@@ -0,0 +1,103 @@
<?php
namespace MintyPHP\Tests\Module\Audit;
use MintyPHP\Module\Audit\AuditAuthorizationPolicy;
use MintyPHP\Service\Access\PermissionService;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
final class AuditAuthorizationPolicyTest extends TestCase
{
private PermissionService&MockObject $permissionService;
private AuditAuthorizationPolicy $policy;
protected function setUp(): void
{
$this->permissionService = $this->createMock(PermissionService::class);
$this->policy = new AuditAuthorizationPolicy($this->permissionService);
}
public static function abilityPermissionProvider(): array
{
return [
[AuditAuthorizationPolicy::ABILITY_API_AUDIT_VIEW, 'audit.api.view'],
[AuditAuthorizationPolicy::ABILITY_API_AUDIT_PURGE, 'audit.api.purge'],
[AuditAuthorizationPolicy::ABILITY_SYSTEM_AUDIT_VIEW, 'audit.system.view'],
[AuditAuthorizationPolicy::ABILITY_SYSTEM_AUDIT_PURGE, 'audit.system.purge'],
[AuditAuthorizationPolicy::ABILITY_IMPORTS_AUDIT_VIEW, 'audit.imports.view'],
[AuditAuthorizationPolicy::ABILITY_IMPORTS_AUDIT_PURGE, 'audit.imports.purge'],
[AuditAuthorizationPolicy::ABILITY_USER_LIFECYCLE_VIEW, 'audit.user_lifecycle.view'],
[AuditAuthorizationPolicy::ABILITY_USER_LIFECYCLE_RESTORE, 'audit.user_lifecycle.restore'],
];
}
#[DataProvider('abilityPermissionProvider')]
public function testSupportsAllAuditAbilities(string $ability, string $permission): void
{
self::assertTrue($this->policy->supports($ability));
self::assertNotSame('', $permission);
}
public function testSupportsRejectsUnknownAbility(): void
{
self::assertFalse($this->policy->supports('audit.unknown.ability'));
}
#[DataProvider('abilityPermissionProvider')]
public function testAuthorizeUsesMappedPermissionKey(string $ability, string $permission): void
{
$this->permissionService->expects($this->once())
->method('userHas')
->with(17, $permission)
->willReturn(true);
$decision = $this->policy->authorize($ability, ['actor_user_id' => 17]);
self::assertTrue($decision->isAllowed());
}
public function testAuthorizeDeniesMissingActorIdWithoutPermissionLookup(): void
{
$this->permissionService->expects($this->never())->method('userHas');
$decision = $this->policy->authorize(AuditAuthorizationPolicy::ABILITY_API_AUDIT_VIEW, []);
self::assertFalse($decision->isAllowed());
self::assertSame(403, $decision->status());
}
public function testAuthorizeDeniesUnknownAbilityWithoutPermissionLookup(): void
{
$this->permissionService->expects($this->never())->method('userHas');
$decision = $this->policy->authorize('audit.unknown.ability', ['actor_user_id' => 17]);
self::assertFalse($decision->isAllowed());
self::assertSame(403, $decision->status());
}
public function testPolicyPermissionKeysMatchManifestPermissionKeys(): void
{
$manifest = require dirname(__DIR__, 3) . '/module.php';
$manifestPermissions = is_array($manifest['permissions'] ?? null) ? $manifest['permissions'] : [];
$manifestKeys = [];
foreach ($manifestPermissions as $permission) {
if (is_array($permission) && isset($permission['key'])) {
$manifestKeys[] = (string) $permission['key'];
}
}
sort($manifestKeys);
$policyKeys = [];
foreach (self::abilityPermissionProvider() as $pair) {
$policyKeys[] = $pair[1];
}
$policyKeys = array_values(array_unique($policyKeys));
sort($policyKeys);
self::assertSame($manifestKeys, $policyKeys);
}
}