using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace StellaOps.Scanner.Surface.Secrets.Providers; /// /// Wraps a secret provider with audit logging. Each secret access is logged with tenant, component, /// secret type, and provider metadata for observability and compliance. /// internal sealed class AuditingSurfaceSecretProvider : ISurfaceSecretProvider { private readonly ISurfaceSecretProvider _inner; private readonly TimeProvider _timeProvider; private readonly ILogger _logger; private readonly string _componentName; public AuditingSurfaceSecretProvider( ISurfaceSecretProvider inner, TimeProvider timeProvider, ILogger logger, string componentName) { _inner = inner ?? throw new ArgumentNullException(nameof(inner)); _timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _componentName = componentName ?? throw new ArgumentNullException(nameof(componentName)); } public SurfaceSecretHandle Get(SurfaceSecretRequest request) { var startTime = _timeProvider.GetUtcNow(); try { var handle = _inner.Get(request); var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, handle.Metadata, success: true, elapsed, error: null); return handle; } catch (SurfaceSecretNotFoundException) { var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, metadata: null, success: false, elapsed, error: "NotFound"); throw; } catch (Exception ex) { var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, metadata: null, success: false, elapsed, error: ex.GetType().Name); throw; } } public async ValueTask GetAsync( SurfaceSecretRequest request, CancellationToken cancellationToken = default) { var startTime = _timeProvider.GetUtcNow(); try { var handle = await _inner.GetAsync(request, cancellationToken).ConfigureAwait(false); var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, handle.Metadata, success: true, elapsed, error: null); return handle; } catch (SurfaceSecretNotFoundException) { var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, metadata: null, success: false, elapsed, error: "NotFound"); throw; } catch (Exception ex) { var elapsed = _timeProvider.GetUtcNow() - startTime; LogAuditEvent( request, metadata: null, success: false, elapsed, error: ex.GetType().Name); throw; } } private void LogAuditEvent( SurfaceSecretRequest request, IReadOnlyDictionary? metadata, bool success, TimeSpan elapsed, string? error) { // Structured log entry for audit trail. NEVER log secret contents. _logger.Log( success ? LogLevel.Information : LogLevel.Warning, "Surface secret access: " + "Component={Component}, " + "Tenant={Tenant}, " + "RequestComponent={RequestComponent}, " + "SecretType={SecretType}, " + "Name={Name}, " + "Success={Success}, " + "ElapsedMs={ElapsedMs}, " + "Provider={Provider}, " + "Error={Error}", _componentName, request.Tenant, request.Component, request.SecretType, request.Name ?? "default", success, elapsed.TotalMilliseconds, metadata?.GetValueOrDefault("source") ?? "unknown", error ?? "(none)"); } }