## Summary - replace broad substring-based masking with a shared exact/path-based secret classifier and workspace-scoped fingerprint hashing - persist protected snapshot metadata on `policy_versions` and keep secret-only changes visible in compare, drift, restore, review, verification, and ops surfaces - add Spec 120 artifacts, audit documentation, and focused Pest regression coverage for snapshot, audit, verification, review-pack, and notification behavior ## Validation - `vendor/bin/sail artisan test --compact tests/Feature/Intune/PolicySnapshotRedactionTest.php tests/Feature/Intune/PolicySnapshotFingerprintIsolationTest.php tests/Feature/ReviewPack/ReviewPackRedactionIntegrityTest.php tests/Feature/OpsUx/OperationRunNotificationRedactionTest.php tests/Feature/Verification/VerificationReportViewerDbOnlyTest.php` - `vendor/bin/sail bin pint --dirty --format agent` ## Spec / checklist status | Checklist | Total | Completed | Incomplete | Status | |-----------|-------|-----------|------------|--------| | requirements.md | 16 | 16 | 0 | ✓ PASS | - `tasks.md`: T001-T032 complete - `tasks.md`: T033 manual quickstart validation is still open and noted for follow-up ## Filament / platform notes - Livewire v4 compliance is unchanged - no panel provider changes; `bootstrap/providers.php` remains the registration location - no new globally searchable resources were introduced, so global search requirements are unchanged - no new destructive Filament actions were added - no new Filament assets were added; no `filament:assets` deployment change is required ## Testing coverage touched - snapshot persistence and fingerprint isolation - compare/drift protected-change evidence - audit, verification, review-pack, ops-failure, and notification sanitization - viewer/read-only Filament presentation updates Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #146
89 lines
3.0 KiB
PHP
89 lines
3.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Support\Verification\VerificationReportSanitizer;
|
|
|
|
it('preserves safe evidence pointer kinds for app diagnostics', function (): void {
|
|
$report = [
|
|
'schema_version' => '1',
|
|
'flow' => 'managed_tenant_onboarding',
|
|
'generated_at' => now()->toIso8601String(),
|
|
'summary' => [
|
|
'overall' => 'warn',
|
|
'counts' => [
|
|
'total' => 1,
|
|
'pass' => 0,
|
|
'fail' => 0,
|
|
'warn' => 1,
|
|
'skip' => 0,
|
|
'running' => 0,
|
|
],
|
|
],
|
|
'checks' => [
|
|
[
|
|
'key' => 'permissions.admin_consent',
|
|
'title' => 'Admin consent granted',
|
|
'status' => 'warn',
|
|
'severity' => 'medium',
|
|
'blocking' => false,
|
|
'reason_code' => 'permissions_inventory_empty',
|
|
'message' => 'No permissions detected.',
|
|
'evidence' => [
|
|
['kind' => 'app_id', 'value' => '00000000-0000-0000-0000-000000000000'],
|
|
['kind' => 'observed_permissions_count', 'value' => 0],
|
|
['kind' => 'client_secret', 'value' => 'nope'],
|
|
],
|
|
'next_steps' => [],
|
|
],
|
|
],
|
|
];
|
|
|
|
$sanitized = VerificationReportSanitizer::sanitizeReport($report);
|
|
|
|
$evidence = $sanitized['checks'][0]['evidence'] ?? null;
|
|
|
|
expect($evidence)->toBeArray();
|
|
expect($evidence)->toContain(['kind' => 'app_id', 'value' => '00000000-0000-0000-0000-000000000000']);
|
|
expect($evidence)->toContain(['kind' => 'observed_permissions_count', 'value' => 0]);
|
|
expect($evidence)->not->toContain(['kind' => 'client_secret', 'value' => 'nope']);
|
|
});
|
|
|
|
it('keeps safe configuration phrases in verification messages', function (): void {
|
|
$report = [
|
|
'schema_version' => '1',
|
|
'flow' => 'managed_tenant_onboarding',
|
|
'generated_at' => now()->toIso8601String(),
|
|
'summary' => [
|
|
'overall' => 'warn',
|
|
'counts' => [
|
|
'total' => 1,
|
|
'pass' => 0,
|
|
'fail' => 0,
|
|
'warn' => 1,
|
|
'skip' => 0,
|
|
'running' => 0,
|
|
],
|
|
],
|
|
'checks' => [
|
|
[
|
|
'key' => 'password.policy',
|
|
'title' => 'Password policy',
|
|
'status' => 'warn',
|
|
'severity' => 'medium',
|
|
'blocking' => false,
|
|
'reason_code' => 'password_policy_warning',
|
|
'message' => 'passwordMinimumLength remains visible while password=super-secret is hidden.',
|
|
'evidence' => [],
|
|
'next_steps' => [],
|
|
],
|
|
],
|
|
];
|
|
|
|
$sanitized = VerificationReportSanitizer::sanitizeReport($report);
|
|
$message = $sanitized['checks'][0]['message'] ?? null;
|
|
|
|
expect($message)->toContain('passwordMinimumLength');
|
|
expect($message)->not->toContain('super-secret');
|
|
});
|