Files
git.stella-ops.org/docs/features/checked/policy/exception-application-audit-trail.md
2026-02-13 02:04:55 +02:00

3.4 KiB

Exception Application Audit Trail (policy.exception_applications)

Module

Policy

Status

IMPLEMENTED

Description

Records every instance of an exception being applied to a finding in a dedicated policy.exception_applications table, capturing exception ID, finding context, original and applied status, purl, vulnerability ID, and evaluation run ID. Exposed via ledger export for compliance.

Implementation Details

  • ExceptionApplication Model: src/Policy/__Libraries/StellaOps.Policy.Exceptions/Models/ExceptionApplication.cs
    • Sealed record with fields: Id (Guid), TenantId, ExceptionId, FindingId, VulnerabilityId, OriginalStatus, AppliedStatus, EffectName, EffectType, EvaluationRunId, PolicyBundleDigest, AppliedAt, Metadata
    • Create() static factory method enforces non-null ExceptionId/FindingId, accepts deterministic applicationId and appliedAt timestamps
    • Metadata stored as ImmutableDictionary<string, string> for extensibility
  • IExceptionApplicationRepository: src/Policy/__Libraries/StellaOps.Policy.Exceptions/Repositories/IExceptionApplicationRepository.cs
    • RecordAsync(application) -- persists a single application record
    • RecordBatchAsync(applications) -- bulk persist for batch evaluation
    • Query by ExceptionId, FindingId, VulnerabilityId, EvaluationRunId, TimeRange
    • GetStatisticsAsync(tenantId, filter?) returns ExceptionApplicationStatistics (TotalApplications, UniqueExceptions, UniqueFindings, UniqueVulnerabilities, ByEffectType counts, ByAppliedStatus counts, EarliestApplication, LatestApplication)
    • CountAsync(tenantId, filter?) for total count with optional filter
    • ExceptionApplicationFilter record supports paging (Limit/Offset), date range (FromDate/ToDate), and field filters
  • PostgresExceptionApplicationRepository: src/Policy/__Libraries/StellaOps.Policy.Exceptions/Repositories/PostgresExceptionApplicationRepository.cs -- Postgres persistence for the policy.exception_applications table
  • ExceptionEvaluator: src/Policy/__Libraries/StellaOps.Policy.Exceptions/Services/ExceptionEvaluator.cs -- creates ExceptionApplication records when exceptions match findings during policy evaluation

E2E Test Plan

  • Apply exception to finding; query GetByExceptionIdAsync(tenantId, exceptionId); verify record includes correct ExceptionId, FindingId, OriginalStatus, AppliedStatus, EffectName, EffectType
  • Apply exception with VulnerabilityId; query GetByVulnerabilityIdAsync(tenantId, vulnId); verify record returned with correct VulnerabilityId
  • Apply exception during batch evaluation; verify EvaluationRunId is populated; query GetByEvaluationRunIdAsync(tenantId, runId) and verify all applications for that run
  • Apply exception; verify AppliedAt timestamp matches evaluation time (deterministic)
  • Apply exception with PolicyBundleDigest; verify digest is recorded in the application record
  • Call RecordBatchAsync with 5 applications; verify all 5 are persisted
  • Call GetByTimeRangeAsync(tenantId, from, to) with a range encompassing 3 applications; verify exactly 3 returned
  • Call GetStatisticsAsync(tenantId) after 10 applications across 3 exceptions and 5 findings; verify TotalApplications=10, UniqueExceptions=3, UniqueFindings=5, ByEffectType counts sum to 10
  • Call CountAsync(tenantId, filter) with EffectType="suppress" filter; verify count matches expected