audit, advisories and doctors/setup work
This commit is contained in:
@@ -43,8 +43,7 @@ public sealed partial class NvdGoldenSetExtractor : IGoldenSetSourceExtractor
|
||||
|
||||
_logger.LogDebug("Extracting from NVD for {VulnerabilityId}", vulnerabilityId);
|
||||
|
||||
// TODO: Implement actual NVD API call
|
||||
// For now, return a stub result indicating the API needs implementation
|
||||
// NVD API integration is not yet implemented; return a stub result.
|
||||
await Task.CompletedTask;
|
||||
|
||||
var source = new ExtractionSource
|
||||
|
||||
@@ -293,8 +293,9 @@ public sealed class GoldenSetReviewService : IGoldenSetReviewService
|
||||
return comments;
|
||||
}
|
||||
|
||||
const string newline = "\n";
|
||||
var changeList = string.Join(
|
||||
Environment.NewLine,
|
||||
newline,
|
||||
changes.Select(c => string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"- [{0}]: {1}",
|
||||
@@ -305,7 +306,7 @@ public sealed class GoldenSetReviewService : IGoldenSetReviewService
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0}{1}{1}Requested changes:{1}{2}",
|
||||
comments,
|
||||
Environment.NewLine,
|
||||
newline,
|
||||
changeList);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace StellaOps.BinaryIndex.GoldenSet;
|
||||
/// <summary>
|
||||
/// PostgreSQL implementation of <see cref="IGoldenSetStore"/>.
|
||||
/// </summary>
|
||||
internal sealed class PostgresGoldenSetStore : IGoldenSetStore
|
||||
public sealed class PostgresGoldenSetStore : IGoldenSetStore
|
||||
{
|
||||
private readonly NpgsqlDataSource _dataSource;
|
||||
private readonly IGoldenSetValidator _validator;
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class PostgresGoldenSetStoreTests : IAsyncLifetime
|
||||
private PostgresGoldenSetStore _store = null!;
|
||||
private FakeTimeProvider _timeProvider = null!;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
_postgres = new PostgreSqlBuilder()
|
||||
.WithImage("postgres:16-alpine")
|
||||
@@ -54,7 +54,7 @@ public sealed class PostgresGoldenSetStoreTests : IAsyncLifetime
|
||||
logger);
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _dataSource.DisposeAsync();
|
||||
await _postgres.DisposeAsync();
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// Licensed under AGPL-3.0-or-later. Copyright (C) 2026 StellaOps Contributors.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
|
||||
using FluentAssertions;
|
||||
|
||||
using StellaOps.BinaryIndex.GoldenSet.Authoring;
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.BinaryIndex.GoldenSet.Tests.Unit.Authoring;
|
||||
@@ -167,6 +170,36 @@ public sealed class ReviewWorkflowTests
|
||||
ReviewActions.Archived.Should().Be("archived");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestChangesAsync_UsesLfNewlines()
|
||||
{
|
||||
// Arrange
|
||||
var store = new CapturingGoldenSetStore();
|
||||
var validator = new StubGoldenSetValidator();
|
||||
var service = new GoldenSetReviewService(
|
||||
store,
|
||||
validator,
|
||||
TimeProvider.System,
|
||||
NullLogger<GoldenSetReviewService>.Instance);
|
||||
|
||||
var changes = ImmutableArray.Create(
|
||||
new ChangeRequest { Field = "targets[0].sinks", Comment = "Add memcpy" },
|
||||
new ChangeRequest { Field = "targets[0].edges", Comment = "Add bb1->bb2" });
|
||||
|
||||
// Act
|
||||
var result = await service.RequestChangesAsync(
|
||||
"CVE-2024-0001",
|
||||
"reviewer@example.com",
|
||||
"Please update the entry.",
|
||||
changes,
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
result.Success.Should().BeTrue();
|
||||
store.LastComment.Should().Be(
|
||||
"Please update the entry.\n\nRequested changes:\n- [targets[0].sinks]: Add memcpy\n- [targets[0].edges]: Add bb1->bb2");
|
||||
}
|
||||
|
||||
private static GoldenSetReviewService CreateReviewService()
|
||||
{
|
||||
// Create a minimal review service for testing state transitions
|
||||
@@ -175,6 +208,103 @@ public sealed class ReviewWorkflowTests
|
||||
store: null!,
|
||||
validator: null!,
|
||||
timeProvider: TimeProvider.System,
|
||||
logger: Microsoft.Extensions.Logging.Abstractions.NullLogger<GoldenSetReviewService>.Instance);
|
||||
logger: NullLogger<GoldenSetReviewService>.Instance);
|
||||
}
|
||||
|
||||
private sealed class CapturingGoldenSetStore : IGoldenSetStore
|
||||
{
|
||||
public string? LastComment { get; private set; }
|
||||
|
||||
public Task<GoldenSetStoreResult> StoreAsync(
|
||||
GoldenSetDefinition definition,
|
||||
GoldenSetStatus status = GoldenSetStatus.Draft,
|
||||
CancellationToken ct = default) =>
|
||||
Task.FromResult(GoldenSetStoreResult.Succeeded("sha256:stub"));
|
||||
|
||||
public Task<GoldenSetDefinition?> GetByIdAsync(string goldenSetId, CancellationToken ct = default) =>
|
||||
Task.FromResult<GoldenSetDefinition?>(null);
|
||||
|
||||
public Task<GoldenSetDefinition?> GetByDigestAsync(string contentDigest, CancellationToken ct = default) =>
|
||||
Task.FromResult<GoldenSetDefinition?>(null);
|
||||
|
||||
public Task<ImmutableArray<GoldenSetSummary>> ListAsync(GoldenSetListQuery query, CancellationToken ct = default) =>
|
||||
Task.FromResult(ImmutableArray<GoldenSetSummary>.Empty);
|
||||
|
||||
public Task UpdateStatusAsync(
|
||||
string goldenSetId,
|
||||
GoldenSetStatus status,
|
||||
string? reviewedBy = null,
|
||||
CancellationToken ct = default) =>
|
||||
Task.CompletedTask;
|
||||
|
||||
public Task<GoldenSetStoreResult> UpdateStatusAsync(
|
||||
string goldenSetId,
|
||||
GoldenSetStatus status,
|
||||
string actorId,
|
||||
string comment,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
LastComment = comment;
|
||||
return Task.FromResult(GoldenSetStoreResult.Succeeded("sha256:stub"));
|
||||
}
|
||||
|
||||
public Task<StoredGoldenSet?> GetAsync(string goldenSetId, CancellationToken ct = default)
|
||||
{
|
||||
var definition = new GoldenSetDefinition
|
||||
{
|
||||
Id = goldenSetId,
|
||||
Component = "component",
|
||||
Targets =
|
||||
[
|
||||
new VulnerableTarget
|
||||
{
|
||||
FunctionName = "func"
|
||||
}
|
||||
],
|
||||
Metadata = new GoldenSetMetadata
|
||||
{
|
||||
AuthorId = "author@example.com",
|
||||
CreatedAt = DateTimeOffset.Parse("2024-01-01T00:00:00Z", CultureInfo.InvariantCulture),
|
||||
SourceRef = "source"
|
||||
}
|
||||
};
|
||||
|
||||
return Task.FromResult<StoredGoldenSet?>(new StoredGoldenSet
|
||||
{
|
||||
Definition = definition,
|
||||
Status = GoldenSetStatus.InReview,
|
||||
CreatedAt = DateTimeOffset.Parse("2024-01-01T00:00:00Z", CultureInfo.InvariantCulture),
|
||||
UpdatedAt = DateTimeOffset.Parse("2024-01-02T00:00:00Z", CultureInfo.InvariantCulture)
|
||||
});
|
||||
}
|
||||
|
||||
public Task<ImmutableArray<GoldenSetAuditEntry>> GetAuditLogAsync(
|
||||
string goldenSetId,
|
||||
CancellationToken ct = default) =>
|
||||
Task.FromResult(ImmutableArray<GoldenSetAuditEntry>.Empty);
|
||||
|
||||
public Task<ImmutableArray<GoldenSetDefinition>> GetByComponentAsync(
|
||||
string component,
|
||||
GoldenSetStatus? statusFilter = GoldenSetStatus.Approved,
|
||||
CancellationToken ct = default) =>
|
||||
Task.FromResult(ImmutableArray<GoldenSetDefinition>.Empty);
|
||||
|
||||
public Task<bool> DeleteAsync(string goldenSetId, CancellationToken ct = default) =>
|
||||
Task.FromResult(false);
|
||||
}
|
||||
|
||||
private sealed class StubGoldenSetValidator : IGoldenSetValidator
|
||||
{
|
||||
public Task<GoldenSetValidationResult> ValidateAsync(
|
||||
GoldenSetDefinition definition,
|
||||
ValidationOptions? options = null,
|
||||
CancellationToken ct = default) =>
|
||||
Task.FromResult(GoldenSetValidationResult.Success(definition, "sha256:stub"));
|
||||
|
||||
public Task<GoldenSetValidationResult> ValidateYamlAsync(
|
||||
string yamlContent,
|
||||
ValidationOptions? options = null,
|
||||
CancellationToken ct = default) =>
|
||||
Task.FromResult(GoldenSetValidationResult.Failure([]));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user