Implement MongoDB-based storage for Pack Run approval, artifact, log, and state management
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added MongoPackRunApprovalStore for managing approval states with MongoDB.
- Introduced MongoPackRunArtifactUploader for uploading and storing artifacts.
- Created MongoPackRunLogStore to handle logging of pack run events.
- Developed MongoPackRunStateStore for persisting and retrieving pack run states.
- Implemented unit tests for MongoDB stores to ensure correct functionality.
- Added MongoTaskRunnerTestContext for setting up MongoDB test environment.
- Enhanced PackRunStateFactory to correctly initialize state with gate reasons.
This commit is contained in:
master
2025-11-07 10:01:35 +02:00
parent e5ffcd6535
commit a1ce3f74fa
122 changed files with 8730 additions and 914 deletions

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scanner.Surface.Env;
@@ -28,6 +29,13 @@ internal sealed class ScannerSurfaceSecretConfigurator : IConfigureOptions<Scann
ArgumentNullException.ThrowIfNull(options);
var tenant = _surfaceEnvironment.Settings.Secrets.Tenant;
ApplyCasAccessSecret(options, tenant);
ApplyRegistrySecret(options, tenant);
ApplyAttestationSecret(options, tenant);
}
private void ApplyCasAccessSecret(ScannerWebServiceOptions options, string tenant)
{
var request = new SurfaceSecretRequest(
Tenant: tenant,
Component: ComponentName,
@@ -56,6 +64,120 @@ internal sealed class ScannerSurfaceSecretConfigurator : IConfigureOptions<Scann
ApplySecret(options.ArtifactStore ??= new ScannerWebServiceOptions.ArtifactStoreOptions(), secret);
}
private void ApplyRegistrySecret(ScannerWebServiceOptions options, string tenant)
{
var request = new SurfaceSecretRequest(
Tenant: tenant,
Component: ComponentName,
SecretType: "registry");
RegistryAccessSecret? secret = null;
try
{
using var handle = _secretProvider.GetAsync(request).AsTask().GetAwaiter().GetResult();
secret = SurfaceSecretParser.ParseRegistryAccessSecret(handle);
}
catch (SurfaceSecretNotFoundException)
{
_logger.LogDebug("Surface secret 'registry' not found for {Component}; leaving registry credentials unchanged.", ComponentName);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to resolve surface secret 'registry' for {Component}.", ComponentName);
}
if (secret is null)
{
return;
}
options.Registry ??= new ScannerWebServiceOptions.RegistryOptions();
options.Registry.DefaultRegistry = secret.DefaultRegistry;
options.Registry.Credentials = new List<ScannerWebServiceOptions.RegistryCredentialOptions>();
foreach (var entry in secret.Entries)
{
var credential = new ScannerWebServiceOptions.RegistryCredentialOptions
{
Registry = entry.Registry,
Username = entry.Username,
Password = entry.Password,
IdentityToken = entry.IdentityToken,
RegistryToken = entry.RegistryToken,
RefreshToken = entry.RefreshToken,
ExpiresAt = entry.ExpiresAt,
AllowInsecureTls = entry.AllowInsecureTls,
Email = entry.Email
};
if (entry.Scopes.Count > 0)
{
credential.Scopes = new List<string>(entry.Scopes);
}
if (entry.Headers.Count > 0)
{
foreach (var (key, value) in entry.Headers)
{
credential.Headers[key] = value;
}
}
options.Registry.Credentials.Add(credential);
}
_logger.LogInformation(
"Surface secret 'registry' applied for {Component} (default: {DefaultRegistry}, entries: {Count}).",
ComponentName,
options.Registry.DefaultRegistry ?? "(none)",
options.Registry.Credentials.Count);
}
private void ApplyAttestationSecret(ScannerWebServiceOptions options, string tenant)
{
var request = new SurfaceSecretRequest(
Tenant: tenant,
Component: ComponentName,
SecretType: "attestation");
AttestationSecret? secret = null;
try
{
using var handle = _secretProvider.GetAsync(request).AsTask().GetAwaiter().GetResult();
secret = SurfaceSecretParser.ParseAttestationSecret(handle);
}
catch (SurfaceSecretNotFoundException)
{
_logger.LogDebug("Surface secret 'attestation' not found for {Component}; retaining signing configuration.", ComponentName);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to resolve surface secret 'attestation' for {Component}.", ComponentName);
}
if (secret is null)
{
return;
}
options.Signing ??= new ScannerWebServiceOptions.SigningOptions();
if (!string.IsNullOrWhiteSpace(secret.KeyPem))
{
options.Signing.KeyPem = secret.KeyPem;
}
if (!string.IsNullOrWhiteSpace(secret.CertificatePem))
{
options.Signing.CertificatePem = secret.CertificatePem;
}
if (!string.IsNullOrWhiteSpace(secret.CertificateChainPem))
{
options.Signing.CertificateChainPem = secret.CertificateChainPem;
}
}
private void ApplySecret(ScannerWebServiceOptions.ArtifactStoreOptions artifactStore, CasAccessSecret secret)
{
if (!string.IsNullOrWhiteSpace(secret.Driver))

View File

@@ -26,10 +26,15 @@ public sealed class ScannerWebServiceOptions
/// </summary>
public QueueOptions Queue { get; set; } = new();
/// <summary>
/// Object store configuration for SBOM artefacts.
/// </summary>
public ArtifactStoreOptions ArtifactStore { get; set; } = new();
/// <summary>
/// Object store configuration for SBOM artefacts.
/// </summary>
public ArtifactStoreOptions ArtifactStore { get; set; } = new();
/// <summary>
/// Registry credential configuration for report/export operations.
/// </summary>
public RegistryOptions Registry { get; set; } = new();
/// <summary>
/// Feature flags toggling optional behaviours.
@@ -144,11 +149,11 @@ public sealed class ScannerWebServiceOptions
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
public sealed class FeatureFlagOptions
{
public bool AllowAnonymousScanSubmission { get; set; }
public bool EnableSignedReports { get; set; } = true;
public sealed class FeatureFlagOptions
{
public bool AllowAnonymousScanSubmission { get; set; }
public bool EnableSignedReports { get; set; } = true;
public bool EnablePolicyPreview { get; set; } = true;
@@ -233,11 +238,11 @@ public sealed class ScannerWebServiceOptions
}
}
public sealed class SigningOptions
{
public bool Enabled { get; set; } = false;
public string KeyId { get; set; } = string.Empty;
public sealed class SigningOptions
{
public bool Enabled { get; set; } = false;
public string KeyId { get; set; } = string.Empty;
public string Algorithm { get; set; } = "ed25519";
@@ -251,12 +256,44 @@ public sealed class ScannerWebServiceOptions
public string? CertificatePemFile { get; set; }
public string? CertificateChainPem { get; set; }
public string? CertificateChainPemFile { get; set; }
public int EnvelopeTtlSeconds { get; set; } = 600;
}
public string? CertificateChainPem { get; set; }
public string? CertificateChainPemFile { get; set; }
public int EnvelopeTtlSeconds { get; set; } = 600;
}
public sealed class RegistryOptions
{
public string? DefaultRegistry { get; set; }
public IList<RegistryCredentialOptions> Credentials { get; set; } = new List<RegistryCredentialOptions>();
}
public sealed class RegistryCredentialOptions
{
public string Registry { get; set; } = string.Empty;
public string? Username { get; set; }
public string? Password { get; set; }
public string? IdentityToken { get; set; }
public string? RegistryToken { get; set; }
public string? RefreshToken { get; set; }
public DateTimeOffset? ExpiresAt { get; set; }
public IList<string> Scopes { get; set; } = new List<string>();
public bool? AllowInsecureTls { get; set; }
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public string? Email { get; set; }
}
public sealed class ApiOptions
{