Add new features and tests for AirGap and Time modules
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Introduced `SbomService` tasks documentation.
- Updated `StellaOps.sln` to include new projects: `StellaOps.AirGap.Time` and `StellaOps.AirGap.Importer`.
- Added unit tests for `BundleImportPlanner`, `DsseVerifier`, `ImportValidator`, and other components in the `StellaOps.AirGap.Importer.Tests` namespace.
- Implemented `InMemoryBundleRepositories` for testing bundle catalog and item repositories.
- Created `MerkleRootCalculator`, `RootRotationPolicy`, and `TufMetadataValidator` tests.
- Developed `StalenessCalculator` and `TimeAnchorLoader` tests in the `StellaOps.AirGap.Time.Tests` namespace.
- Added `fetch-sbomservice-deps.sh` script for offline dependency fetching.
This commit is contained in:
master
2025-11-20 23:29:54 +02:00
parent 65b1599229
commit 79b8e53441
182 changed files with 6660 additions and 1242 deletions

View File

@@ -275,29 +275,7 @@ app.MapGet("/ledger/export/findings", async Task<Results<FileStreamHttpResult, J
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "page_token_filters_mismatch");
}
if (!string.IsNullOrEmpty(page.NextPageToken))
{
httpContext.Response.Headers["X-Stella-Next-Page-Token"] = page.NextPageToken;
}
httpContext.Response.Headers["X-Stella-Result-Count"] = page.Items.Count.ToString();
var acceptsNdjson = httpContext.Request.Headers.Accept.Any(h => h.Contains("application/x-ndjson", StringComparison.OrdinalIgnoreCase));
if (acceptsNdjson)
{
httpContext.Response.ContentType = "application/x-ndjson";
var stream = new MemoryStream();
await using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { SkipValidation = false, Indented = false });
foreach (var item in page.Items)
{
JsonSerializer.Serialize(writer, item);
writer.Flush();
await stream.WriteAsync(new byte[] { (byte)'\n' }, cancellationToken).ConfigureAwait(false);
}
stream.Position = 0;
return TypedResults.Stream(stream, contentType: "application/x-ndjson");
}
return TypedResults.Json(page);
return await WritePagedResponse(httpContext, page, cancellationToken).ConfigureAwait(false);
})
.WithName("LedgerExportFindings")
.RequireAuthorization(LedgerExportPolicy)
@@ -342,3 +320,33 @@ static LedgerEventResponse CreateResponse(LedgerEventRecord record, string statu
MerkleLeafHash = record.MerkleLeafHash,
RecordedAt = record.RecordedAt
};
static async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<T>>, ProblemHttpResult>> WritePagedResponse<T>(
HttpContext httpContext,
ExportPage<T> page,
CancellationToken cancellationToken)
{
if (!string.IsNullOrEmpty(page.NextPageToken))
{
httpContext.Response.Headers["X-Stella-Next-Page-Token"] = page.NextPageToken;
}
httpContext.Response.Headers["X-Stella-Result-Count"] = page.Items.Count.ToString();
var acceptsNdjson = httpContext.Request.Headers.Accept.Any(h => h.Contains("application/x-ndjson", StringComparison.OrdinalIgnoreCase));
if (acceptsNdjson)
{
httpContext.Response.ContentType = "application/x-ndjson";
var stream = new MemoryStream();
await using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { SkipValidation = false, Indented = false });
foreach (var item in page.Items)
{
JsonSerializer.Serialize(writer, item);
writer.Flush();
await stream.WriteAsync(new byte[] { (byte)'\n' }, cancellationToken).ConfigureAwait(false);
}
stream.Position = 0;
return TypedResults.Stream(stream, contentType: "application/x-ndjson");
}
return TypedResults.Json(page);
}