Files
git.stella-ops.org/src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/CallGraphEndpointsTests.cs
StellaOps Bot 7d5250238c save progress
2025-12-18 09:53:46 +02:00

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)
});
}
}