finish secrets finding work and audit remarks work save

This commit is contained in:
StellaOps Bot
2026-01-04 21:48:13 +02:00
parent 75611a505f
commit 8862e112c4
157 changed files with 11702 additions and 416 deletions

View File

@@ -12,8 +12,7 @@ public sealed record BunPackagesResponse
public string ImageDigest { get; init; } = string.Empty;
[JsonPropertyName("generatedAt")]
public DateTimeOffset GeneratedAt { get; init; }
= DateTimeOffset.UtcNow;
public required DateTimeOffset GeneratedAt { get; init; }
[JsonPropertyName("packages")]
public IReadOnlyList<BunPackageArtifact> Packages { get; init; }

View File

@@ -12,8 +12,7 @@ public sealed record RubyPackagesResponse
public string ImageDigest { get; init; } = string.Empty;
[JsonPropertyName("generatedAt")]
public DateTimeOffset GeneratedAt { get; init; }
= DateTimeOffset.UtcNow;
public required DateTimeOffset GeneratedAt { get; init; }
[JsonPropertyName("packages")]
public IReadOnlyList<RubyPackageArtifact> Packages { get; init; }

View File

@@ -0,0 +1,319 @@
// -----------------------------------------------------------------------------
// SecretDetectionConfigContracts.cs
// Sprint: SPRINT_20260104_006_BE (Secret Detection Configuration API)
// Task: SDC-005 - Create Settings CRUD API endpoints
// Description: API contracts for secret detection configuration.
// -----------------------------------------------------------------------------
using System.Text.Json.Serialization;
namespace StellaOps.Scanner.WebService.Contracts;
// ============================================================================
// Settings DTOs
// ============================================================================
/// <summary>
/// Request to get or update secret detection settings.
/// </summary>
public sealed record SecretDetectionSettingsDto
{
/// <summary>Whether secret detection is enabled.</summary>
public bool Enabled { get; init; }
/// <summary>Revelation policy configuration.</summary>
public required RevelationPolicyDto RevelationPolicy { get; init; }
/// <summary>Enabled rule categories.</summary>
public IReadOnlyList<string> EnabledRuleCategories { get; init; } = [];
/// <summary>Disabled rule IDs.</summary>
public IReadOnlyList<string> DisabledRuleIds { get; init; } = [];
/// <summary>Alert settings.</summary>
public required SecretAlertSettingsDto AlertSettings { get; init; }
/// <summary>Maximum file size to scan (bytes).</summary>
public long MaxFileSizeBytes { get; init; }
/// <summary>File extensions to exclude.</summary>
public IReadOnlyList<string> ExcludedFileExtensions { get; init; } = [];
/// <summary>Path patterns to exclude (glob).</summary>
public IReadOnlyList<string> ExcludedPaths { get; init; } = [];
/// <summary>Whether to scan binary files.</summary>
public bool ScanBinaryFiles { get; init; }
/// <summary>Whether to require signed rule bundles.</summary>
public bool RequireSignedRuleBundles { get; init; }
}
/// <summary>
/// Response containing settings with metadata.
/// </summary>
public sealed record SecretDetectionSettingsResponseDto
{
/// <summary>Tenant ID.</summary>
public Guid TenantId { get; init; }
/// <summary>Settings data.</summary>
public required SecretDetectionSettingsDto Settings { get; init; }
/// <summary>Version for optimistic concurrency.</summary>
public int Version { get; init; }
/// <summary>When settings were last updated.</summary>
public DateTimeOffset UpdatedAt { get; init; }
/// <summary>Who last updated settings.</summary>
public required string UpdatedBy { get; init; }
}
/// <summary>
/// Revelation policy configuration.
/// </summary>
public sealed record RevelationPolicyDto
{
/// <summary>Default masking policy.</summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public SecretRevelationPolicyType DefaultPolicy { get; init; }
/// <summary>Export masking policy.</summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public SecretRevelationPolicyType ExportPolicy { get; init; }
/// <summary>Roles allowed to see full secrets.</summary>
public IReadOnlyList<string> FullRevealRoles { get; init; } = [];
/// <summary>Characters to reveal at start/end for partial.</summary>
public int PartialRevealChars { get; init; }
/// <summary>Maximum mask characters.</summary>
public int MaxMaskChars { get; init; }
}
/// <summary>
/// Revelation policy types.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SecretRevelationPolicyType
{
/// <summary>Fully masked (e.g., [REDACTED]).</summary>
FullMask = 0,
/// <summary>Partially revealed (e.g., AKIA****WXYZ).</summary>
PartialReveal = 1,
/// <summary>Full value shown (audit logged).</summary>
FullReveal = 2
}
/// <summary>
/// Alert settings configuration.
/// </summary>
public sealed record SecretAlertSettingsDto
{
/// <summary>Whether alerting is enabled.</summary>
public bool Enabled { get; init; }
/// <summary>Minimum severity to trigger alerts.</summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public SecretSeverityType MinimumAlertSeverity { get; init; }
/// <summary>Alert destinations.</summary>
public IReadOnlyList<SecretAlertDestinationDto> Destinations { get; init; } = [];
/// <summary>Maximum alerts per scan.</summary>
public int MaxAlertsPerScan { get; init; }
/// <summary>Deduplication window in minutes.</summary>
public int DeduplicationWindowMinutes { get; init; }
/// <summary>Include file path in alerts.</summary>
public bool IncludeFilePath { get; init; }
/// <summary>Include masked value in alerts.</summary>
public bool IncludeMaskedValue { get; init; }
/// <summary>Include image reference in alerts.</summary>
public bool IncludeImageRef { get; init; }
/// <summary>Custom alert message prefix.</summary>
public string? AlertMessagePrefix { get; init; }
}
/// <summary>
/// Secret severity levels.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SecretSeverityType
{
Low = 0,
Medium = 1,
High = 2,
Critical = 3
}
/// <summary>
/// Alert channel types.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum AlertChannelType
{
Slack = 0,
Teams = 1,
Email = 2,
Webhook = 3,
PagerDuty = 4
}
/// <summary>
/// Alert destination configuration.
/// </summary>
public sealed record SecretAlertDestinationDto
{
/// <summary>Destination ID.</summary>
public Guid Id { get; init; }
/// <summary>Destination name.</summary>
public required string Name { get; init; }
/// <summary>Channel type.</summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public AlertChannelType ChannelType { get; init; }
/// <summary>Channel identifier (webhook URL, email, channel ID).</summary>
public required string ChannelId { get; init; }
/// <summary>Severity filter (if empty, uses MinimumAlertSeverity).</summary>
public IReadOnlyList<SecretSeverityType>? SeverityFilter { get; init; }
/// <summary>Rule category filter (if empty, alerts for all).</summary>
public IReadOnlyList<string>? RuleCategoryFilter { get; init; }
/// <summary>Whether this destination is active.</summary>
public bool IsActive { get; init; }
}
// ============================================================================
// Exception Pattern DTOs
// ============================================================================
/// <summary>
/// Request to create or update an exception pattern.
/// </summary>
public sealed record SecretExceptionPatternDto
{
/// <summary>Human-readable name.</summary>
public required string Name { get; init; }
/// <summary>Description of why this exception exists.</summary>
public required string Description { get; init; }
/// <summary>Regex pattern to match secret value.</summary>
public required string ValuePattern { get; init; }
/// <summary>Rule IDs this applies to (empty = all).</summary>
public IReadOnlyList<string> ApplicableRuleIds { get; init; } = [];
/// <summary>File path glob pattern.</summary>
public string? FilePathGlob { get; init; }
/// <summary>Business justification (required).</summary>
public required string Justification { get; init; }
/// <summary>Expiration date (null = permanent).</summary>
public DateTimeOffset? ExpiresAt { get; init; }
/// <summary>Whether this exception is active.</summary>
public bool IsActive { get; init; }
}
/// <summary>
/// Response containing exception pattern with metadata.
/// </summary>
public sealed record SecretExceptionPatternResponseDto
{
/// <summary>Exception ID.</summary>
public Guid Id { get; init; }
/// <summary>Tenant ID.</summary>
public Guid TenantId { get; init; }
/// <summary>Exception data.</summary>
public required SecretExceptionPatternDto Pattern { get; init; }
/// <summary>Number of times matched.</summary>
public long MatchCount { get; init; }
/// <summary>Last match time.</summary>
public DateTimeOffset? LastMatchedAt { get; init; }
/// <summary>Creation time.</summary>
public DateTimeOffset CreatedAt { get; init; }
/// <summary>Creator.</summary>
public required string CreatedBy { get; init; }
/// <summary>Last update time.</summary>
public DateTimeOffset? UpdatedAt { get; init; }
/// <summary>Last updater.</summary>
public string? UpdatedBy { get; init; }
}
/// <summary>
/// List response for exception patterns.
/// </summary>
public sealed record SecretExceptionPatternListResponseDto
{
/// <summary>Exception patterns.</summary>
public required IReadOnlyList<SecretExceptionPatternResponseDto> Patterns { get; init; }
/// <summary>Total count.</summary>
public int TotalCount { get; init; }
}
// ============================================================================
// Update Request DTOs
// ============================================================================
/// <summary>
/// Request to update settings with optimistic concurrency.
/// </summary>
public sealed record UpdateSecretDetectionSettingsRequestDto
{
/// <summary>Settings to apply.</summary>
public required SecretDetectionSettingsDto Settings { get; init; }
/// <summary>Expected version (for optimistic concurrency).</summary>
public int ExpectedVersion { get; init; }
}
/// <summary>
/// Available rule categories response.
/// </summary>
public sealed record RuleCategoriesResponseDto
{
/// <summary>All available categories.</summary>
public required IReadOnlyList<RuleCategoryDto> Categories { get; init; }
}
/// <summary>
/// Rule category information.
/// </summary>
public sealed record RuleCategoryDto
{
/// <summary>Category ID.</summary>
public required string Id { get; init; }
/// <summary>Display name.</summary>
public required string Name { get; init; }
/// <summary>Description.</summary>
public required string Description { get; init; }
/// <summary>Number of rules in this category.</summary>
public int RuleCount { get; init; }
}

View File

@@ -12,8 +12,7 @@ public sealed record SurfacePointersDto
[JsonPropertyName("generatedAt")]
[JsonPropertyOrder(1)]
public DateTimeOffset GeneratedAt { get; init; }
= DateTimeOffset.UtcNow;
public required DateTimeOffset GeneratedAt { get; init; }
[JsonPropertyName("manifestDigest")]
[JsonPropertyOrder(2)]