104 lines
3.8 KiB
C#
104 lines
3.8 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using StellaOps.Scanner.WebService.Contracts;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Scanner.WebService.Tests;
|
|
|
|
public sealed class CallGraphEndpointsTests
|
|
{
|
|
[Fact]
|
|
public async Task SubmitCallGraphRequiresContentDigestHeader()
|
|
{
|
|
using var secrets = new TestSurfaceSecretsScope();
|
|
using var factory = new ScannerApplicationFactory().WithOverrides(configuration =>
|
|
{
|
|
configuration["scanner:authority:enabled"] = "false";
|
|
});
|
|
|
|
using var client = factory.CreateClient();
|
|
|
|
var scanId = await CreateScanAsync(client);
|
|
var request = CreateMinimalCallGraph(scanId);
|
|
|
|
var response = await client.PostAsJsonAsync($"/api/v1/scans/{scanId}/callgraphs", request);
|
|
|
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SubmitCallGraphReturnsAcceptedAndDetectsDuplicates()
|
|
{
|
|
using var secrets = new TestSurfaceSecretsScope();
|
|
using var factory = new ScannerApplicationFactory().WithOverrides(configuration =>
|
|
{
|
|
configuration["scanner:authority:enabled"] = "false";
|
|
});
|
|
|
|
using var client = factory.CreateClient();
|
|
|
|
var scanId = await CreateScanAsync(client);
|
|
var request = CreateMinimalCallGraph(scanId);
|
|
using var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/scans/{scanId}/callgraphs")
|
|
{
|
|
Content = JsonContent.Create(request)
|
|
};
|
|
httpRequest.Headers.TryAddWithoutValidation("Content-Digest", "sha256:deadbeef");
|
|
|
|
var first = await client.SendAsync(httpRequest);
|
|
Assert.Equal(HttpStatusCode.Accepted, first.StatusCode);
|
|
|
|
var payload = await first.Content.ReadFromJsonAsync<CallGraphAcceptedResponseDto>();
|
|
Assert.NotNull(payload);
|
|
Assert.False(string.IsNullOrWhiteSpace(payload!.CallgraphId));
|
|
Assert.Equal("sha256:deadbeef", payload.Digest);
|
|
Assert.Equal(2, payload.NodeCount);
|
|
Assert.Equal(1, payload.EdgeCount);
|
|
|
|
using var secondRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/scans/{scanId}/callgraphs")
|
|
{
|
|
Content = JsonContent.Create(request)
|
|
};
|
|
secondRequest.Headers.TryAddWithoutValidation("Content-Digest", "sha256:deadbeef");
|
|
|
|
var second = await client.SendAsync(secondRequest);
|
|
Assert.Equal(HttpStatusCode.Conflict, second.StatusCode);
|
|
}
|
|
|
|
private static async Task<string> CreateScanAsync(HttpClient client)
|
|
{
|
|
var response = await client.PostAsJsonAsync("/api/v1/scans", new ScanSubmitRequest
|
|
{
|
|
Image = new ScanImageDescriptor
|
|
{
|
|
Reference = "example.com/demo:1.0",
|
|
Digest = "sha256:0123456789abcdef"
|
|
}
|
|
});
|
|
|
|
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
|
|
|
var payload = await response.Content.ReadFromJsonAsync<ScanSubmitResponse>();
|
|
Assert.NotNull(payload);
|
|
Assert.False(string.IsNullOrWhiteSpace(payload!.ScanId));
|
|
return payload.ScanId;
|
|
}
|
|
|
|
private static CallGraphV1Dto CreateMinimalCallGraph(string scanId)
|
|
{
|
|
return new CallGraphV1Dto(
|
|
Schema: "stella.callgraph.v1",
|
|
ScanKey: scanId,
|
|
Language: "dotnet",
|
|
Nodes: new[]
|
|
{
|
|
new CallGraphNodeDto(NodeId: "n1", SymbolKey: "Demo.Entry", ArtifactKey: null, Visibility: "public", IsEntrypointCandidate: true),
|
|
new CallGraphNodeDto(NodeId: "n2", SymbolKey: "Demo.Vuln", ArtifactKey: null, Visibility: "public", IsEntrypointCandidate: false),
|
|
},
|
|
Edges: new[]
|
|
{
|
|
new CallGraphEdgeDto(From: "n1", To: "n2", Kind: "static", Reason: "direct", Weight: 1.0)
|
|
});
|
|
}
|
|
}
|