Add unit tests and implementations for MongoDB index models and OpenAPI metadata
- Implemented `MongoIndexModelTests` to verify index models for various stores. - Created `OpenApiMetadataFactory` with methods to generate OpenAPI metadata. - Added tests for `OpenApiMetadataFactory` to ensure expected defaults and URL overrides. - Introduced `ObserverSurfaceSecrets` and `WebhookSurfaceSecrets` for managing secrets. - Developed `RuntimeSurfaceFsClient` and `WebhookSurfaceFsClient` for manifest retrieval. - Added dependency injection tests for `SurfaceEnvironmentRegistration` in both Observer and Webhook contexts. - Implemented tests for secret resolution in `ObserverSurfaceSecretsTests` and `WebhookSurfaceSecretsTests`. - Created `EnsureLinkNotMergeCollectionsMigrationTests` to validate MongoDB migration logic. - Added project files for MongoDB tests and NuGet package mirroring.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Scanner.Surface.Secrets;
|
||||
using StellaOps.Zastava.Core.Configuration;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
|
||||
namespace StellaOps.Zastava.Observer.Secrets;
|
||||
|
||||
internal interface IObserverSurfaceSecrets
|
||||
{
|
||||
ValueTask<CasAccessSecret> GetCasAccessAsync(string? name, CancellationToken cancellationToken = default);
|
||||
ValueTask<AttestationSecret> GetAttestationAsync(string? name, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
internal sealed class ObserverSurfaceSecrets : IObserverSurfaceSecrets
|
||||
{
|
||||
private const string Component = "Zastava.Observer";
|
||||
|
||||
private readonly ISurfaceSecretProvider _provider;
|
||||
private readonly IOptions<ZastavaRuntimeOptions> _runtime;
|
||||
private readonly IOptions<ZastavaObserverOptions> _observer;
|
||||
|
||||
public ObserverSurfaceSecrets(
|
||||
ISurfaceSecretProvider provider,
|
||||
IOptions<ZastavaRuntimeOptions> runtime,
|
||||
IOptions<ZastavaObserverOptions> observer)
|
||||
{
|
||||
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_observer = observer ?? throw new ArgumentNullException(nameof(observer));
|
||||
}
|
||||
|
||||
public async ValueTask<CasAccessSecret> GetCasAccessAsync(string? name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = _observer.Value.Secrets;
|
||||
var request = new SurfaceSecretRequest(
|
||||
Tenant: _runtime.Value.Tenant,
|
||||
Component: Component,
|
||||
SecretType: "cas-access",
|
||||
Name: string.IsNullOrWhiteSpace(name) ? options.CasAccessName : name);
|
||||
|
||||
var handle = await _provider.GetAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return SurfaceSecretParser.ParseCasAccessSecret(handle);
|
||||
}
|
||||
|
||||
public async ValueTask<AttestationSecret> GetAttestationAsync(string? name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = _observer.Value.Secrets;
|
||||
var request = new SurfaceSecretRequest(
|
||||
Tenant: _runtime.Value.Tenant,
|
||||
Component: Component,
|
||||
SecretType: "attestation",
|
||||
Name: string.IsNullOrWhiteSpace(name) ? options.AttestationName : name);
|
||||
|
||||
var handle = await _provider.GetAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return SurfaceSecretParser.ParseAttestationSecret(handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
|
||||
namespace StellaOps.Zastava.Observer.Surface;
|
||||
|
||||
internal interface IRuntimeSurfaceFsClient
|
||||
{
|
||||
Task<SurfaceManifestDocument?> TryGetManifestAsync(string manifestDigest, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
internal sealed class RuntimeSurfaceFsClient : IRuntimeSurfaceFsClient
|
||||
{
|
||||
private readonly ISurfaceManifestReader _manifestReader;
|
||||
private readonly SurfaceEnvironmentSettings _environment;
|
||||
|
||||
public RuntimeSurfaceFsClient(ISurfaceManifestReader manifestReader, SurfaceEnvironmentSettings environment)
|
||||
{
|
||||
_manifestReader = manifestReader ?? throw new ArgumentNullException(nameof(manifestReader));
|
||||
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
|
||||
}
|
||||
|
||||
public Task<SurfaceManifestDocument?> TryGetManifestAsync(string manifestDigest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(manifestDigest))
|
||||
{
|
||||
return Task.FromResult<SurfaceManifestDocument?>(null);
|
||||
}
|
||||
|
||||
// manifest digests follow sha256:<hex>; manifest reader handles validation and tenant discovery
|
||||
return _manifestReader.TryGetByDigestAsync(manifestDigest.Trim(), cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Scanner.Surface.Secrets;
|
||||
using StellaOps.Zastava.Core.Configuration;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Secrets;
|
||||
|
||||
internal interface IWebhookSurfaceSecrets
|
||||
{
|
||||
ValueTask<AttestationSecret> GetAttestationAsync(string? name, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
internal sealed class WebhookSurfaceSecrets : IWebhookSurfaceSecrets
|
||||
{
|
||||
private const string Component = "Zastava.Webhook";
|
||||
|
||||
private readonly ISurfaceSecretProvider _provider;
|
||||
private readonly IOptions<ZastavaRuntimeOptions> _runtime;
|
||||
private readonly IOptions<ZastavaWebhookOptions> _webhook;
|
||||
|
||||
public WebhookSurfaceSecrets(
|
||||
ISurfaceSecretProvider provider,
|
||||
IOptions<ZastavaRuntimeOptions> runtime,
|
||||
IOptions<ZastavaWebhookOptions> webhook)
|
||||
{
|
||||
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_webhook = webhook ?? throw new ArgumentNullException(nameof(webhook));
|
||||
}
|
||||
|
||||
public async ValueTask<AttestationSecret> GetAttestationAsync(string? name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = _webhook.Value.Secrets;
|
||||
var request = new SurfaceSecretRequest(
|
||||
Tenant: _runtime.Value.Tenant,
|
||||
Component: Component,
|
||||
SecretType: "attestation",
|
||||
Name: string.IsNullOrWhiteSpace(name) ? options.AttestationName : name);
|
||||
|
||||
var handle = await _provider.GetAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return SurfaceSecretParser.ParseAttestationSecret(handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
using StellaOps.Zastava.Core.Configuration;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Surface;
|
||||
|
||||
internal interface IWebhookSurfaceFsClient
|
||||
{
|
||||
Task<(bool Found, string? ManifestUri)> TryGetManifestAsync(string manifestDigest, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
internal sealed class WebhookSurfaceFsClient : IWebhookSurfaceFsClient
|
||||
{
|
||||
private readonly ISurfaceManifestReader _manifestReader;
|
||||
private readonly SurfaceManifestPathBuilder _pathBuilder;
|
||||
private readonly IOptions<ZastavaRuntimeOptions> _runtimeOptions;
|
||||
|
||||
public WebhookSurfaceFsClient(
|
||||
ISurfaceManifestReader manifestReader,
|
||||
IOptions<SurfaceCacheOptions> cacheOptions,
|
||||
IOptions<SurfaceManifestStoreOptions> storeOptions,
|
||||
IOptions<ZastavaRuntimeOptions> runtimeOptions)
|
||||
{
|
||||
_manifestReader = manifestReader ?? throw new ArgumentNullException(nameof(manifestReader));
|
||||
_runtimeOptions = runtimeOptions ?? throw new ArgumentNullException(nameof(runtimeOptions));
|
||||
|
||||
if (cacheOptions is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cacheOptions));
|
||||
}
|
||||
|
||||
if (storeOptions is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(storeOptions));
|
||||
}
|
||||
|
||||
_pathBuilder = new SurfaceManifestPathBuilder(cacheOptions.Value, storeOptions.Value);
|
||||
}
|
||||
|
||||
public async Task<(bool Found, string? ManifestUri)> TryGetManifestAsync(string manifestDigest, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(manifestDigest))
|
||||
{
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// First check whether the manifest exists in the local surface store.
|
||||
var manifest = await _manifestReader.TryGetByDigestAsync(manifestDigest.Trim(), cancellationToken).ConfigureAwait(false);
|
||||
if (manifest is null)
|
||||
{
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
var tenant = !string.IsNullOrWhiteSpace(manifest.Tenant)
|
||||
? manifest.Tenant
|
||||
: _runtimeOptions.Value.Tenant;
|
||||
|
||||
var digestHex = SurfaceManifestPathBuilder.EnsureSha256Digest(manifestDigest); // strips sha256:
|
||||
var uri = _pathBuilder.BuildManifestUri(tenant, digestHex);
|
||||
|
||||
return (true, uri);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Observer.Tests.DependencyInjection;
|
||||
|
||||
public sealed class SurfaceEnvironmentRegistrationTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddZastavaObserver_RegistersSurfaceEnvironmentWithZastavaPrefixes()
|
||||
{
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ZASTAVA_SURFACE_FS_ENDPOINT"] = "https://surface.example",
|
||||
["ZASTAVA_SURFACE_FS_BUCKET"] = "zastava-cache",
|
||||
["ZASTAVA_SURFACE_FEATURES"] = "prefetch,drift",
|
||||
["ZASTAVA_SURFACE_SECRETS_PROVIDER"] = "kubernetes",
|
||||
["ZASTAVA_SURFACE_SECRETS_NAMESPACE"] = "security",
|
||||
["ZASTAVA_SURFACE_TENANT"] = "tenant-a"
|
||||
};
|
||||
|
||||
var originals = CaptureEnvironment(env.Keys);
|
||||
try
|
||||
{
|
||||
foreach (var pair in env)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaObserverOptions.SectionName}:runtimes:0:engine"] = "Containerd"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaObserver(configuration);
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var surface = provider.GetRequiredService<ISurfaceEnvironment>();
|
||||
var settings = provider.GetRequiredService<SurfaceEnvironmentSettings>();
|
||||
|
||||
Assert.Equal(new Uri("https://surface.example"), settings.SurfaceFsEndpoint);
|
||||
Assert.Equal("zastava-cache", settings.SurfaceFsBucket);
|
||||
Assert.Contains("prefetch", settings.FeatureFlags, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Contains("drift", settings.FeatureFlags, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Equal("kubernetes", settings.Secrets.Provider);
|
||||
Assert.Equal("security", settings.Secrets.Namespace);
|
||||
Assert.Equal("tenant-a", settings.Tenant);
|
||||
|
||||
// Ensure singleton mapping is shared
|
||||
Assert.Same(surface.Settings, settings);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RestoreEnvironment(originals);
|
||||
}
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, string?> CaptureEnvironment(IEnumerable<string> names)
|
||||
{
|
||||
var snapshot = new Dictionary<string, string?>();
|
||||
foreach (var name in names)
|
||||
{
|
||||
snapshot[name] = Environment.GetEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private static void RestoreEnvironment(IReadOnlyDictionary<string, string?> snapshot)
|
||||
{
|
||||
foreach (var pair in snapshot)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
using StellaOps.Zastava.Observer.Secrets;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Observer.Tests.Secrets;
|
||||
|
||||
public sealed class ObserverSurfaceSecretsTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetCasAccessAsync_ResolvesInlineSecret()
|
||||
{
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ZASTAVA_SURFACE_FS_ENDPOINT"] = "https://surface.example",
|
||||
["ZASTAVA_SURFACE_SECRETS_PROVIDER"] = "inline",
|
||||
["ZASTAVA_SURFACE_SECRETS_ALLOW_INLINE"] = "true",
|
||||
["SURFACE_SECRET_DEFAULT_ZASTAVA.OBSERVER_CAS-ACCESS_PRIMARY"] = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("{\"driver\":\"s3\",\"accessKeyId\":\"ak\",\"secretAccessKey\":\"sk\"}"))
|
||||
};
|
||||
|
||||
var services = BuildServices(env);
|
||||
|
||||
var secrets = services.GetRequiredService<IObserverSurfaceSecrets>();
|
||||
var result = await secrets.GetCasAccessAsync(name: null);
|
||||
|
||||
Assert.Equal("s3", result.Driver);
|
||||
Assert.Equal("ak", result.AccessKeyId);
|
||||
Assert.Equal("sk", result.SecretAccessKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAttestationAsync_ResolvesInlineSecret()
|
||||
{
|
||||
var payload = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("{\"keyPem\":\"KEY\",\"rekorToken\":\"token123\"}"));
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ZASTAVA_SURFACE_FS_ENDPOINT"] = "https://surface.example",
|
||||
["ZASTAVA_SURFACE_SECRETS_PROVIDER"] = "inline",
|
||||
["ZASTAVA_SURFACE_SECRETS_ALLOW_INLINE"] = "true",
|
||||
["SURFACE_SECRET_DEFAULT_ZASTAVA.OBSERVER_ATTESTATION_SIGNING"] = payload
|
||||
};
|
||||
|
||||
var services = BuildServices(env);
|
||||
|
||||
var secrets = services.GetRequiredService<IObserverSurfaceSecrets>();
|
||||
var result = await secrets.GetAttestationAsync(name: null);
|
||||
|
||||
Assert.Equal("KEY", result.KeyPem);
|
||||
Assert.Equal("token123", result.RekorApiToken);
|
||||
}
|
||||
|
||||
private static ServiceProvider BuildServices(Dictionary<string, string?> env)
|
||||
{
|
||||
var originals = new Dictionary<string, string?>();
|
||||
foreach (var pair in env)
|
||||
{
|
||||
originals[pair.Key] = Environment.GetEnvironmentVariable(pair.Key);
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaObserverOptions.SectionName}:runtimes:0:engine"] = "Containerd"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaObserver(configuration);
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
foreach (var pair in originals)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
using StellaOps.Zastava.Observer.Configuration;
|
||||
using StellaOps.Zastava.Observer.Surface;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Observer.Tests.Surface;
|
||||
|
||||
public sealed class RuntimeSurfaceFsClientTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task TryGetManifestAsync_ReturnsPublishedManifest()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaObserverOptions.SectionName}:runtimes:0:engine"] = "Containerd",
|
||||
[$"{ZastavaObserverOptions.SectionName}:backend:baseAddress"] = "https://scanner.internal"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaObserver(configuration);
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var manifestWriter = provider.GetRequiredService<ISurfaceManifestWriter>();
|
||||
var client = provider.GetRequiredService<IRuntimeSurfaceFsClient>();
|
||||
|
||||
var document = new SurfaceManifestDocument
|
||||
{
|
||||
Tenant = "default",
|
||||
ImageDigest = "sha256:deadbeef",
|
||||
GeneratedAt = DateTimeOffset.UtcNow,
|
||||
Artifacts = new[]
|
||||
{
|
||||
new SurfaceManifestArtifact
|
||||
{
|
||||
Kind = "entry-trace",
|
||||
Uri = "cas://surface-cache/manifest/entry-trace",
|
||||
Digest = "sha256:abc123",
|
||||
MediaType = "application/json",
|
||||
Format = "ndsjon"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var published = await manifestWriter.PublishAsync(document, default);
|
||||
var fetched = await client.TryGetManifestAsync(published.ManifestDigest, default);
|
||||
|
||||
Assert.NotNull(fetched);
|
||||
Assert.Equal(document.Tenant, fetched!.Tenant);
|
||||
Assert.Equal(document.ImageDigest, fetched.ImageDigest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Tests.DependencyInjection;
|
||||
|
||||
public sealed class SurfaceEnvironmentRegistrationTests
|
||||
{
|
||||
[Fact]
|
||||
public void AddZastavaWebhook_RegistersSurfaceEnvironmentWithZastavaPrefixes()
|
||||
{
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ZASTAVA_WEBHOOK_SURFACE_FS_ENDPOINT"] = "https://surface.example",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_FS_BUCKET"] = "zastava-cache",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_FEATURES"] = "admission,drift",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_SECRETS_PROVIDER"] = "kubernetes",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_SECRETS_NAMESPACE"] = "security",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_TENANT"] = "tenant-w"
|
||||
};
|
||||
|
||||
var originals = CaptureEnvironment(env.Keys);
|
||||
try
|
||||
{
|
||||
foreach (var pair in env)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaWebhookOptions.SectionName}:tls:mode"] = "Secret"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaWebhook(configuration);
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var surface = provider.GetRequiredService<ISurfaceEnvironment>();
|
||||
var settings = provider.GetRequiredService<SurfaceEnvironmentSettings>();
|
||||
|
||||
Assert.Equal(new Uri("https://surface.example"), settings.SurfaceFsEndpoint);
|
||||
Assert.Equal("zastava-cache", settings.SurfaceFsBucket);
|
||||
Assert.Contains("admission", settings.FeatureFlags, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Contains("drift", settings.FeatureFlags, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.Equal("kubernetes", settings.Secrets.Provider);
|
||||
Assert.Equal("security", settings.Secrets.Namespace);
|
||||
Assert.Equal("tenant-w", settings.Tenant);
|
||||
|
||||
Assert.Same(surface.Settings, settings);
|
||||
}
|
||||
finally
|
||||
{
|
||||
RestoreEnvironment(originals);
|
||||
}
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, string?> CaptureEnvironment(IEnumerable<string> names)
|
||||
{
|
||||
var snapshot = new Dictionary<string, string?>();
|
||||
foreach (var name in names)
|
||||
{
|
||||
snapshot[name] = Environment.GetEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private static void RestoreEnvironment(IReadOnlyDictionary<string, string?> snapshot)
|
||||
{
|
||||
foreach (var pair in snapshot)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
using StellaOps.Zastava.Webhook.Secrets;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Tests.DependencyInjection;
|
||||
|
||||
public sealed class SurfaceSecretsRegistrationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task AddZastavaWebhook_ResolvesInlineAttestationSecret()
|
||||
{
|
||||
var payload = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("{\"keyPem\":\"KEY\",\"rekorToken\":\"rekor\"}"));
|
||||
var env = new Dictionary<string, string?>
|
||||
{
|
||||
["ZASTAVA_WEBHOOK_SURFACE_FS_ENDPOINT"] = "https://surface.example",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_SECRETS_PROVIDER"] = "inline",
|
||||
["ZASTAVA_WEBHOOK_SURFACE_SECRETS_ALLOW_INLINE"] = "true",
|
||||
["SURFACE_SECRET_DEFAULT_ZASTAVA.WEBHOOK_ATTESTATION_VERIFICATION"] = payload
|
||||
};
|
||||
|
||||
var services = BuildServices(env);
|
||||
|
||||
var secrets = services.GetRequiredService<IWebhookSurfaceSecrets>();
|
||||
var result = await secrets.GetAttestationAsync(name: null);
|
||||
|
||||
Assert.Equal("KEY", result.KeyPem);
|
||||
Assert.Equal("rekor", result.RekorApiToken);
|
||||
}
|
||||
|
||||
private static ServiceProvider BuildServices(Dictionary<string, string?> env)
|
||||
{
|
||||
var originals = new Dictionary<string, string?>();
|
||||
foreach (var pair in env)
|
||||
{
|
||||
originals[pair.Key] = Environment.GetEnvironmentVariable(pair.Key);
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaWebhookOptions.SectionName}:tls:mode"] = "Secret"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaWebhook(configuration);
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
foreach (var pair in originals)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
using StellaOps.Zastava.Webhook.Surface;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Tests.Surface;
|
||||
|
||||
public sealed class WebhookSurfaceFsClientTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task TryGetManifestAsync_ReturnsPointerWhenPresent()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
[$"{ZastavaWebhookOptions.SectionName}:tls:mode"] = "Secret"
|
||||
})
|
||||
.Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddZastavaWebhook(configuration);
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var writer = provider.GetRequiredService<ISurfaceManifestWriter>();
|
||||
var client = provider.GetRequiredService<IWebhookSurfaceFsClient>();
|
||||
|
||||
var doc = new SurfaceManifestDocument
|
||||
{
|
||||
Tenant = "default",
|
||||
ImageDigest = "sha256:deadbeef",
|
||||
GeneratedAt = DateTimeOffset.UtcNow,
|
||||
Artifacts = new[]
|
||||
{
|
||||
new SurfaceManifestArtifact
|
||||
{
|
||||
Kind = "entry-trace",
|
||||
Uri = "cas://surface-cache/manifest/entry-trace",
|
||||
Digest = "sha256:abc123",
|
||||
MediaType = "application/json",
|
||||
Format = "ndjson"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var published = await writer.PublishAsync(doc, default);
|
||||
var (found, pointer) = await client.TryGetManifestAsync(published.ManifestDigest, default);
|
||||
|
||||
Assert.True(found);
|
||||
Assert.NotNull(pointer);
|
||||
Assert.Contains("surface-cache", pointer); // matches default bucket
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user