## 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
4.8 KiB
Implementation Plan: Secret Redaction Hardening & Snapshot Data Integrity
Branch: 120-secret-redaction-integrity | Date: 2026-03-06 | Spec: specs/120-secret-redaction-integrity/spec.md
Input: Feature specification from /specs/120-secret-redaction-integrity/spec.md
Summary
Harden persisted policy evidence by replacing broad substring-based masking with one exact/path-based classifier, moving protected snapshot ownership to VersionService, adding dedicated policy_versions.secret_fingerprints and policy_versions.redaction_version fields, and extending audit/output sanitizers to preserve safe configuration language.
Technical Context
Language/Version: PHP 8.4, Laravel 12, Filament v5, Livewire v4
Primary Dependencies: Laravel framework, Filament admin panels, Livewire, PostgreSQL JSONB persistence, Laravel Sail
Storage: PostgreSQL (policy_versions, operation_runs, audit_logs, related evidence tables)
Testing: Pest 4 feature/unit tests run via vendor/bin/sail artisan test --compact
Target Platform: Laravel Sail containers for local dev; web application with tenant /admin and workspace/admin monitoring surfaces
Project Type: Single Laravel web application
Performance Goals: Deterministic protected snapshot generation on every capture; monitoring pages remain DB-only; secret-only changes must not collapse during dedupe
Constraints: No new dependencies; no historical-data remediation workflow; workspace-scoped HMACs only; no raw substring redaction in persisted snapshot or audit paths
Scale/Scope: Touches all PolicyVersion writes, downstream drift/compare/restore consumers, audit/verification/ops sanitizers, and focused Pest regression coverage
Constitution Check
GATE: Passed before Phase 0 research. Re-checked after scope update: still passed.
- Inventory-first: PASS — inventory remains “last observed”; Spec 120 only hardens immutable snapshot protection.
- Read/write separation: PASS — writes are limited to protected snapshot persistence and existing user-initiated flows.
- Graph contract path: PASS — no new Graph endpoints or bypasses are introduced.
- Deterministic capabilities: PASS — capability logic is unchanged; regression work focuses on deterministic classifier output and version identity.
- RBAC / plane separation: PASS — tenant evidence remains under
/admin; no new cross-plane workflow remains in scope. - Workspace / tenant isolation: PASS — workspace-scoped HMAC derivation uses
workspace_id. - Destructive confirmation standard: PASS — no new destructive surfaces are introduced.
- Global search safety: PASS — no new searchable resources are added.
- Run observability: PASS — existing capture/compare/restore/export flows keep their current operations behavior.
- Ops-UX 3-surface feedback: PASS — existing operation starts remain unchanged.
- OperationRun lifecycle ownership: PASS — no direct status/outcome writes are introduced.
- Ops regression guards: PASS — the plan keeps regression tests for redaction and output behavior.
- Data minimization: PASS — fingerprint storage is non-reversible, logs/audit remain sanitized, and no raw secret material is persisted.
- BADGE-001 / Filament action surface / UX-001: PASS — the release changes existing read-only views only.
Project Structure
Documentation (this feature)
specs/[###-feature]/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
└── tasks.md
Source Code (repository root)
app/
├── Filament/
│ ├── Pages/Operations/
│ ├── Resources/FindingResource/
│ ├── Support/
│ └── Widgets/Tenant/
├── Models/
├── Services/
│ ├── Audit/
│ └── Intune/
└── Support/
├── Audit/
├── OpsUx/
└── Verification/
database/
├── factories/
└── migrations/
tests/
├── Feature/
│ ├── Audit/
│ ├── Intune/
│ ├── OpsUx/
│ ├── Operations/
│ └── Verification/
└── Unit/
├── Intune/
├── OpsUx/
└── Verification/
Structure Decision: Keep the existing single Laravel application structure. Implement the central classifier and protected snapshot DTO under app/Services/Intune, extend existing sanitizers in app/Support/*, evolve PolicyVersion persistence via migrations/model/factory updates, and cover the behavior with focused Pest tests under existing tests/Feature and tests/Unit namespaces.
Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|