up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-13 00:20:26 +02:00
parent e1f1bef4c1
commit 564df71bfb
2376 changed files with 334389 additions and 328032 deletions

View File

@@ -1,95 +1,95 @@
using System;
using System.Collections.Generic;
namespace StellaOps.Cryptography.Audit;
/// <summary>
/// Represents a structured security event emitted by the Authority host and plugins.
/// </summary>
public sealed record AuthEventRecord
{
/// <summary>
/// Canonical event identifier (e.g. <c>authority.password.grant</c>).
/// </summary>
public required string EventType { get; init; }
/// <summary>
/// UTC timestamp captured when the event occurred.
/// </summary>
public DateTimeOffset OccurredAt { get; init; } = DateTimeOffset.UtcNow;
/// <summary>
/// Stable correlation identifier that links the event across logs, traces, and persistence.
/// </summary>
public string? CorrelationId { get; init; }
/// <summary>
/// Outcome classification for the audited operation.
/// </summary>
public AuthEventOutcome Outcome { get; init; } = AuthEventOutcome.Unknown;
/// <summary>
/// Optional human-readable reason or failure descriptor.
/// </summary>
public string? Reason { get; init; }
/// <summary>
/// Identity of the end-user (subject) involved in the event, when applicable.
/// </summary>
public AuthEventSubject? Subject { get; init; }
/// <summary>
/// OAuth/OIDC client metadata associated with the event, when applicable.
/// </summary>
public AuthEventClient? Client { get; init; }
/// <summary>
/// Tenant identifier associated with the authenticated principal or client.
/// </summary>
public ClassifiedString Tenant { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Project identifier associated with the authenticated principal or client (optional).
/// </summary>
public ClassifiedString Project { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Granted or requested scopes tied to the event.
/// </summary>
public IReadOnlyList<string> Scopes { get; init; } = Array.Empty<string>();
/// <summary>
/// Network attributes (remote IP, forwarded headers, user agent) captured for the request.
/// </summary>
public AuthEventNetwork? Network { get; init; }
/// <summary>
/// Additional classified properties carried with the event.
/// </summary>
public IReadOnlyList<AuthEventProperty> Properties { get; init; } = Array.Empty<AuthEventProperty>();
}
/// <summary>
/// Describes the outcome of an audited flow.
/// </summary>
public enum AuthEventOutcome
{
/// <summary>
/// Outcome has not been set.
/// </summary>
Unknown = 0,
/// <summary>
/// Operation succeeded.
/// </summary>
Success,
/// <summary>
/// Operation failed (invalid credentials, configuration issues, etc.).
/// </summary>
Failure,
/// <summary>
using System;
using System.Collections.Generic;
namespace StellaOps.Cryptography.Audit;
/// <summary>
/// Represents a structured security event emitted by the Authority host and plugins.
/// </summary>
public sealed record AuthEventRecord
{
/// <summary>
/// Canonical event identifier (e.g. <c>authority.password.grant</c>).
/// </summary>
public required string EventType { get; init; }
/// <summary>
/// UTC timestamp captured when the event occurred.
/// </summary>
public DateTimeOffset OccurredAt { get; init; } = DateTimeOffset.UtcNow;
/// <summary>
/// Stable correlation identifier that links the event across logs, traces, and persistence.
/// </summary>
public string? CorrelationId { get; init; }
/// <summary>
/// Outcome classification for the audited operation.
/// </summary>
public AuthEventOutcome Outcome { get; init; } = AuthEventOutcome.Unknown;
/// <summary>
/// Optional human-readable reason or failure descriptor.
/// </summary>
public string? Reason { get; init; }
/// <summary>
/// Identity of the end-user (subject) involved in the event, when applicable.
/// </summary>
public AuthEventSubject? Subject { get; init; }
/// <summary>
/// OAuth/OIDC client metadata associated with the event, when applicable.
/// </summary>
public AuthEventClient? Client { get; init; }
/// <summary>
/// Tenant identifier associated with the authenticated principal or client.
/// </summary>
public ClassifiedString Tenant { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Project identifier associated with the authenticated principal or client (optional).
/// </summary>
public ClassifiedString Project { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Granted or requested scopes tied to the event.
/// </summary>
public IReadOnlyList<string> Scopes { get; init; } = Array.Empty<string>();
/// <summary>
/// Network attributes (remote IP, forwarded headers, user agent) captured for the request.
/// </summary>
public AuthEventNetwork? Network { get; init; }
/// <summary>
/// Additional classified properties carried with the event.
/// </summary>
public IReadOnlyList<AuthEventProperty> Properties { get; init; } = Array.Empty<AuthEventProperty>();
}
/// <summary>
/// Describes the outcome of an audited flow.
/// </summary>
public enum AuthEventOutcome
{
/// <summary>
/// Outcome has not been set.
/// </summary>
Unknown = 0,
/// <summary>
/// Operation succeeded.
/// </summary>
Success,
/// <summary>
/// Operation failed (invalid credentials, configuration issues, etc.).
/// </summary>
Failure,
/// <summary>
/// Operation failed due to a lockout policy.
/// </summary>
LockedOut,
@@ -108,171 +108,171 @@ public enum AuthEventOutcome
/// Operation was rejected due to rate limiting or throttling.
/// </summary>
RateLimited,
/// <summary>
/// Operation encountered an unexpected error.
/// </summary>
Error
}
/// <summary>
/// Represents a string value enriched with a data classification tag.
/// </summary>
public readonly record struct ClassifiedString(string? Value, AuthEventDataClassification Classification)
{
/// <summary>
/// An empty classified string.
/// </summary>
public static ClassifiedString Empty => new(null, AuthEventDataClassification.None);
/// <summary>
/// Indicates whether the classified string carries a non-empty value.
/// </summary>
public bool HasValue => !string.IsNullOrWhiteSpace(Value);
/// <summary>
/// Creates a classified string for public/non-sensitive data.
/// </summary>
public static ClassifiedString Public(string? value) => Create(value, AuthEventDataClassification.None);
/// <summary>
/// Creates a classified string tagged as personally identifiable information (PII).
/// </summary>
public static ClassifiedString Personal(string? value) => Create(value, AuthEventDataClassification.Personal);
/// <summary>
/// Creates a classified string tagged as sensitive (e.g. credentials, secrets).
/// </summary>
public static ClassifiedString Sensitive(string? value) => Create(value, AuthEventDataClassification.Sensitive);
private static ClassifiedString Create(string? value, AuthEventDataClassification classification)
{
return new ClassifiedString(Normalize(value), classification);
}
private static string? Normalize(string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : value;
}
}
/// <summary>
/// Supported classifications for audit data values.
/// </summary>
public enum AuthEventDataClassification
{
/// <summary>
/// Data is not considered sensitive.
/// </summary>
None = 0,
/// <summary>
/// Personally identifiable information (PII) that warrants redaction in certain sinks.
/// </summary>
Personal,
/// <summary>
/// Highly sensitive information (credentials, secrets, tokens).
/// </summary>
Sensitive
}
/// <summary>
/// Captures subject metadata for an audit event.
/// </summary>
public sealed record AuthEventSubject
{
/// <summary>
/// Stable subject identifier (PII).
/// </summary>
public ClassifiedString SubjectId { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Username or login name (PII).
/// </summary>
public ClassifiedString Username { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Optional display name (PII).
/// </summary>
public ClassifiedString DisplayName { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Optional plugin or tenant realm controlling the subject namespace.
/// </summary>
public ClassifiedString Realm { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Additional classified attributes (e.g. email, phone).
/// </summary>
public IReadOnlyList<AuthEventProperty> Attributes { get; init; } = Array.Empty<AuthEventProperty>();
}
/// <summary>
/// Captures OAuth/OIDC client metadata for an audit event.
/// </summary>
public sealed record AuthEventClient
{
/// <summary>
/// Client identifier (PII for confidential clients).
/// </summary>
public ClassifiedString ClientId { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Friendly client name (may be public).
/// </summary>
public ClassifiedString Name { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Identity provider/plugin originating the client.
/// </summary>
public ClassifiedString Provider { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Captures network metadata for an audit event.
/// </summary>
public sealed record AuthEventNetwork
{
/// <summary>
/// Remote address observed for the request (PII).
/// </summary>
public ClassifiedString RemoteAddress { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Forwarded address supplied by proxies (PII).
/// </summary>
public ClassifiedString ForwardedFor { get; init; } = ClassifiedString.Empty;
/// <summary>
/// User agent string associated with the request.
/// </summary>
public ClassifiedString UserAgent { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Represents an additional classified property associated with the audit event.
/// </summary>
public sealed record AuthEventProperty
{
/// <summary>
/// Property name (canonical snake-case identifier).
/// </summary>
public required string Name { get; init; }
/// <summary>
/// Classified value assigned to the property.
/// </summary>
public ClassifiedString Value { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Sink that receives completed audit event records.
/// </summary>
public interface IAuthEventSink
{
/// <summary>
/// Persists the supplied audit event.
/// </summary>
ValueTask WriteAsync(AuthEventRecord record, CancellationToken cancellationToken);
}
/// <summary>
/// Operation encountered an unexpected error.
/// </summary>
Error
}
/// <summary>
/// Represents a string value enriched with a data classification tag.
/// </summary>
public readonly record struct ClassifiedString(string? Value, AuthEventDataClassification Classification)
{
/// <summary>
/// An empty classified string.
/// </summary>
public static ClassifiedString Empty => new(null, AuthEventDataClassification.None);
/// <summary>
/// Indicates whether the classified string carries a non-empty value.
/// </summary>
public bool HasValue => !string.IsNullOrWhiteSpace(Value);
/// <summary>
/// Creates a classified string for public/non-sensitive data.
/// </summary>
public static ClassifiedString Public(string? value) => Create(value, AuthEventDataClassification.None);
/// <summary>
/// Creates a classified string tagged as personally identifiable information (PII).
/// </summary>
public static ClassifiedString Personal(string? value) => Create(value, AuthEventDataClassification.Personal);
/// <summary>
/// Creates a classified string tagged as sensitive (e.g. credentials, secrets).
/// </summary>
public static ClassifiedString Sensitive(string? value) => Create(value, AuthEventDataClassification.Sensitive);
private static ClassifiedString Create(string? value, AuthEventDataClassification classification)
{
return new ClassifiedString(Normalize(value), classification);
}
private static string? Normalize(string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : value;
}
}
/// <summary>
/// Supported classifications for audit data values.
/// </summary>
public enum AuthEventDataClassification
{
/// <summary>
/// Data is not considered sensitive.
/// </summary>
None = 0,
/// <summary>
/// Personally identifiable information (PII) that warrants redaction in certain sinks.
/// </summary>
Personal,
/// <summary>
/// Highly sensitive information (credentials, secrets, tokens).
/// </summary>
Sensitive
}
/// <summary>
/// Captures subject metadata for an audit event.
/// </summary>
public sealed record AuthEventSubject
{
/// <summary>
/// Stable subject identifier (PII).
/// </summary>
public ClassifiedString SubjectId { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Username or login name (PII).
/// </summary>
public ClassifiedString Username { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Optional display name (PII).
/// </summary>
public ClassifiedString DisplayName { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Optional plugin or tenant realm controlling the subject namespace.
/// </summary>
public ClassifiedString Realm { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Additional classified attributes (e.g. email, phone).
/// </summary>
public IReadOnlyList<AuthEventProperty> Attributes { get; init; } = Array.Empty<AuthEventProperty>();
}
/// <summary>
/// Captures OAuth/OIDC client metadata for an audit event.
/// </summary>
public sealed record AuthEventClient
{
/// <summary>
/// Client identifier (PII for confidential clients).
/// </summary>
public ClassifiedString ClientId { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Friendly client name (may be public).
/// </summary>
public ClassifiedString Name { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Identity provider/plugin originating the client.
/// </summary>
public ClassifiedString Provider { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Captures network metadata for an audit event.
/// </summary>
public sealed record AuthEventNetwork
{
/// <summary>
/// Remote address observed for the request (PII).
/// </summary>
public ClassifiedString RemoteAddress { get; init; } = ClassifiedString.Empty;
/// <summary>
/// Forwarded address supplied by proxies (PII).
/// </summary>
public ClassifiedString ForwardedFor { get; init; } = ClassifiedString.Empty;
/// <summary>
/// User agent string associated with the request.
/// </summary>
public ClassifiedString UserAgent { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Represents an additional classified property associated with the audit event.
/// </summary>
public sealed record AuthEventProperty
{
/// <summary>
/// Property name (canonical snake-case identifier).
/// </summary>
public required string Name { get; init; }
/// <summary>
/// Classified value assigned to the property.
/// </summary>
public ClassifiedString Value { get; init; } = ClassifiedString.Empty;
}
/// <summary>
/// Sink that receives completed audit event records.
/// </summary>
public interface IAuthEventSink
{
/// <summary>
/// Persists the supplied audit event.
/// </summary>
ValueTask WriteAsync(AuthEventRecord record, CancellationToken cancellationToken);
}