work
This commit is contained in:
@@ -27,6 +27,8 @@ using Mongo2Go;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.IO;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.Core.Attestation;
|
||||
using static StellaOps.Concelier.WebService.Program;
|
||||
using StellaOps.Concelier.Core.Events;
|
||||
using StellaOps.Concelier.Core.Jobs;
|
||||
using StellaOps.Concelier.Models;
|
||||
@@ -39,6 +41,7 @@ using StellaOps.Concelier.Core.Raw;
|
||||
using StellaOps.Concelier.WebService.Jobs;
|
||||
using StellaOps.Concelier.WebService.Options;
|
||||
using StellaOps.Concelier.WebService.Contracts;
|
||||
using StellaOps.Concelier.WebService;
|
||||
using Xunit.Sdk;
|
||||
using StellaOps.Auth.Abstractions;
|
||||
using StellaOps.Auth.Client;
|
||||
@@ -73,7 +76,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
public Task InitializeAsync()
|
||||
{
|
||||
PrepareMongoEnvironment();
|
||||
if (TryStartExternalMongo(out var externalConnectionString))
|
||||
if (TryStartExternalMongo(out var externalConnectionString) && !string.IsNullOrWhiteSpace(externalConnectionString))
|
||||
{
|
||||
_factory = new ConcelierApplicationFactory(externalConnectionString);
|
||||
}
|
||||
@@ -381,6 +384,8 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Assert.Equal("ADV-002", firstItem.GetProperty("advisoryId").GetString());
|
||||
Assert.Contains("pkg:npm/demo@2.0.0", firstItem.GetProperty("purl").EnumerateArray().Select(x => x.GetString()));
|
||||
Assert.True(firstItem.GetProperty("conflicts").EnumerateArray().Count() >= 0);
|
||||
Assert.Equal("created", firstItem.GetProperty("timeline").EnumerateArray().First().GetProperty("event").GetString());
|
||||
Assert.Equal(DateTime.Parse("2025-01-06T00:00:00Z"), firstItem.GetProperty("publishedAt").GetDateTime());
|
||||
|
||||
var detailResponse = await client.GetAsync("/v1/lnm/linksets/ADV-001?source=osv&includeObservations=true");
|
||||
detailResponse.EnsureSuccessStatusCode();
|
||||
@@ -390,6 +395,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Assert.Equal("osv", detailPayload.GetProperty("source").GetString());
|
||||
Assert.Contains("pkg:npm/demo@1.0.0", detailPayload.GetProperty("purl").EnumerateArray().Select(x => x.GetString()));
|
||||
Assert.Contains("obs-1", detailPayload.GetProperty("observations").EnumerateArray().Select(x => x.GetString()));
|
||||
Assert.Equal(DateTime.Parse("2025-01-05T00:00:00Z"), detailPayload.GetProperty("publishedAt").GetDateTime());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -713,6 +719,66 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Assert.Equal(tarPath, evidence.Attestation.EvidenceBundlePath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Attestation")]
|
||||
public async Task InternalAttestationVerify_ReturnsClaims()
|
||||
{
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
|
||||
var sampleDir = Path.Combine(repoRoot, "docs", "samples", "evidence-bundle");
|
||||
var tarPath = Path.Combine(sampleDir, "evidence-bundle-m0.tar.gz");
|
||||
var manifestPath = Path.Combine(sampleDir, "manifest.json");
|
||||
var transparencyPath = Path.Combine(sampleDir, "transparency.json");
|
||||
|
||||
using var scope = _factory.Services.CreateScope();
|
||||
var concOptions = scope.ServiceProvider.GetRequiredService<IOptions<ConcelierOptions>>().Value;
|
||||
_output.WriteLine($"EvidenceRoot={concOptions.Evidence.RootAbsolute}");
|
||||
Assert.StartsWith(concOptions.Evidence.RootAbsolute, tarPath, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
using var client = _factory.CreateClient();
|
||||
var request = new VerifyAttestationRequest(tarPath, manifestPath, transparencyPath, "git:test-sha");
|
||||
|
||||
var response = await client.PostAsJsonAsync("/internal/attestations/verify?tenant=demo", request);
|
||||
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
Assert.True(response.IsSuccessStatusCode, $"Attestation verify failed: {(int)response.StatusCode} {response.StatusCode} · {responseBody}");
|
||||
|
||||
var claims = JsonSerializer.Deserialize<AttestationClaims>(
|
||||
responseBody,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
Assert.NotNull(claims);
|
||||
Assert.Equal("evidence-bundle-m0", claims!.SubjectName);
|
||||
Assert.Equal("git:test-sha", claims.PipelineVersion);
|
||||
Assert.Equal(tarPath, claims.EvidenceBundlePath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EvidenceBatch_ReturnsEmptyCollectionsWhenUnknown()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.Add(TenantHeaderName, "demo");
|
||||
|
||||
var request = new EvidenceBatchRequest(
|
||||
new[]
|
||||
{
|
||||
new EvidenceBatchItemRequest("component-a", new[] { "pkg:purl/example@1.0.0" }, new[] { "ALIAS-1" })
|
||||
},
|
||||
ObservationLimit: 5,
|
||||
LinksetLimit: 5);
|
||||
|
||||
var response = await client.PostAsJsonAsync("/v1/evidence/batch", request);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
var payload = await response.Content.ReadFromJsonAsync<EvidenceBatchResponse>();
|
||||
|
||||
Assert.NotNull(payload);
|
||||
var item = Assert.Single(payload!.Items);
|
||||
Assert.Equal("component-a", item.ComponentId);
|
||||
Assert.Empty(item.Observations);
|
||||
Assert.Empty(item.Linksets);
|
||||
Assert.False(item.HasMore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AdvisoryEvidenceEndpoint_FiltersByVendor()
|
||||
{
|
||||
@@ -1300,7 +1366,8 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var payload = await response.Content.ReadFromJsonAsync<ReplayResponse>();
|
||||
Assert.NotNull(payload);
|
||||
var conflict = Assert.Single(payload!.Conflicts);
|
||||
var conflicts = payload!.Conflicts ?? throw new XunitException("Conflicts was null");
|
||||
var conflict = Assert.Single(conflicts);
|
||||
Assert.Equal(conflictId, conflict.ConflictId);
|
||||
Assert.Equal("severity", conflict.Explainer.Type);
|
||||
Assert.Equal("mismatch", conflict.Explainer.Reason);
|
||||
@@ -1977,6 +2044,17 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
_previousTelemetryLogging = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING");
|
||||
_previousTelemetryTracing = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING");
|
||||
_previousTelemetryMetrics = Environment.GetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLEMETRICS");
|
||||
|
||||
var opensslPath = ResolveOpenSsl11Path();
|
||||
if (!string.IsNullOrEmpty(opensslPath))
|
||||
{
|
||||
var currentLd = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH");
|
||||
var merged = string.IsNullOrWhiteSpace(currentLd)
|
||||
? opensslPath
|
||||
: string.Join(':', opensslPath, currentLd);
|
||||
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", merged);
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DSN", connectionString);
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__DRIVER", "mongo");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_STORAGE__COMMANDTIMEOUTSECONDS", "30");
|
||||
@@ -1984,6 +2062,10 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING", "false");
|
||||
Environment.SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLEMETRICS", "false");
|
||||
const string EvidenceRootKey = "CONCELIER_EVIDENCE__ROOT";
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
|
||||
_additionalPreviousEnvironment[EvidenceRootKey] = Environment.GetEnvironmentVariable(EvidenceRootKey);
|
||||
Environment.SetEnvironmentVariable(EvidenceRootKey, repoRoot);
|
||||
const string TestSecretKey = "CONCELIER_AUTHORITY__TESTSIGNINGSECRET";
|
||||
if (environmentOverrides is null || !environmentOverrides.ContainsKey(TestSecretKey))
|
||||
{
|
||||
@@ -2002,6 +2084,23 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
}
|
||||
}
|
||||
|
||||
private static string? ResolveOpenSsl11Path()
|
||||
{
|
||||
var current = AppContext.BaseDirectory;
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
var candidate = Path.GetFullPath(Path.Combine(current, "tests", "native", "openssl-1.1", "linux-x64"));
|
||||
if (Directory.Exists(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
|
||||
current = Path.GetFullPath(Path.Combine(current, ".."));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||
{
|
||||
builder.ConfigureAppConfiguration((context, configurationBuilder) =>
|
||||
@@ -2035,7 +2134,17 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
options.Telemetry.EnableMetrics = false;
|
||||
options.Authority ??= new ConcelierOptions.AuthorityOptions();
|
||||
_authorityConfigure?.Invoke(options.Authority);
|
||||
|
||||
// Point evidence root at the repo so sample bundles under docs/samples/evidence-bundle resolve without 400.
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
|
||||
options.Evidence.Root = repoRoot;
|
||||
options.Evidence.RootAbsolute = repoRoot;
|
||||
});
|
||||
|
||||
// Ensure content root + wwwroot exist so host startup does not throw when WebService bin output isn't present.
|
||||
var contentRoot = AppContext.BaseDirectory;
|
||||
var wwwroot = Path.Combine(contentRoot, "wwwroot");
|
||||
Directory.CreateDirectory(wwwroot);
|
||||
});
|
||||
|
||||
builder.ConfigureTestServices(services =>
|
||||
@@ -3093,4 +3202,5 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
return Task.FromResult<IReadOnlyDictionary<string, JobRunSnapshot>>(map);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user