Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -7,6 +7,11 @@ using StellaOps.EvidenceLocker.Storage;
|
||||
|
||||
namespace StellaOps.EvidenceLocker.Api;
|
||||
|
||||
/// <summary>
|
||||
/// Logging category for verdict endpoints.
|
||||
/// </summary>
|
||||
internal sealed class VerdictEndpointsLogger;
|
||||
|
||||
/// <summary>
|
||||
/// Minimal API endpoints for verdict attestations.
|
||||
/// </summary>
|
||||
@@ -63,7 +68,7 @@ public static class VerdictEndpoints
|
||||
private static async Task<IResult> StoreVerdictAsync(
|
||||
[FromBody] StoreVerdictRequest request,
|
||||
[FromServices] IVerdictRepository repository,
|
||||
[FromServices] ILogger<Program> logger,
|
||||
[FromServices] ILogger<VerdictEndpointsLogger> logger,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -132,7 +137,7 @@ public static class VerdictEndpoints
|
||||
private static async Task<IResult> GetVerdictAsync(
|
||||
string verdictId,
|
||||
[FromServices] IVerdictRepository repository,
|
||||
[FromServices] ILogger<Program> logger,
|
||||
[FromServices] ILogger<VerdictEndpointsLogger> logger,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -184,13 +189,13 @@ public static class VerdictEndpoints
|
||||
|
||||
private static async Task<IResult> ListVerdictsForRunAsync(
|
||||
string runId,
|
||||
[FromQuery] string? status,
|
||||
[FromQuery] string? severity,
|
||||
[FromQuery] int limit = 50,
|
||||
[FromQuery] int offset = 0,
|
||||
[FromServices] IVerdictRepository repository,
|
||||
[FromServices] ILogger<Program> logger,
|
||||
CancellationToken cancellationToken)
|
||||
[FromServices] ILogger<VerdictEndpointsLogger> logger,
|
||||
CancellationToken cancellationToken,
|
||||
[FromQuery] string? status = null,
|
||||
[FromQuery] string? severity = null,
|
||||
[FromQuery] int limit = 50,
|
||||
[FromQuery] int offset = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -249,7 +254,7 @@ public static class VerdictEndpoints
|
||||
private static async Task<IResult> VerifyVerdictAsync(
|
||||
string verdictId,
|
||||
[FromServices] IVerdictRepository repository,
|
||||
[FromServices] ILogger<Program> logger,
|
||||
[FromServices] ILogger<VerdictEndpointsLogger> logger,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
@@ -306,7 +311,7 @@ public static class VerdictEndpoints
|
||||
private static async Task<IResult> DownloadEnvelopeAsync(
|
||||
string verdictId,
|
||||
[FromServices] IVerdictRepository repository,
|
||||
[FromServices] ILogger<Program> logger,
|
||||
[FromServices] ILogger<VerdictEndpointsLogger> logger,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"StellaOps.EvidenceLocker": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:62511;http://localhost:62512"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public sealed class EvidencePortableBundleService
|
||||
return new EvidenceBundlePackageResult(metadata.StorageKey, details.Bundle.RootHash, Created: true);
|
||||
}
|
||||
|
||||
private static Stream BuildPackageStream(
|
||||
private Stream BuildPackageStream(
|
||||
EvidenceBundleDetails details,
|
||||
ManifestDocument manifest,
|
||||
DateTimeOffset generatedAt)
|
||||
@@ -146,7 +146,7 @@ public sealed class EvidencePortableBundleService
|
||||
WriteTextEntry(
|
||||
tarWriter,
|
||||
_options.InstructionsFileName,
|
||||
BuildInstructions(details, manifest, generatedAt));
|
||||
BuildInstructions(details, manifest, generatedAt, _options));
|
||||
|
||||
WriteTextEntry(
|
||||
tarWriter,
|
||||
@@ -224,7 +224,8 @@ public sealed class EvidencePortableBundleService
|
||||
private static string BuildInstructions(
|
||||
EvidenceBundleDetails details,
|
||||
ManifestDocument manifest,
|
||||
DateTimeOffset generatedAt)
|
||||
DateTimeOffset generatedAt,
|
||||
PortableOptions options)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine("Portable Evidence Bundle Instructions");
|
||||
@@ -245,9 +246,9 @@ public sealed class EvidencePortableBundleService
|
||||
builder.Append("Portable Generated At: ").AppendLine(generatedAt.ToString("O"));
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("Verification steps:");
|
||||
builder.Append("1. Copy '").Append(_options.ArtifactName).AppendLine("' into the sealed environment.");
|
||||
builder.Append("2. Execute './").Append(_options.OfflineScriptFileName).Append(' ');
|
||||
builder.Append(_options.ArtifactName).AppendLine("' to extract contents and verify checksums.");
|
||||
builder.Append("1. Copy '").Append(options.ArtifactName).AppendLine("' into the sealed environment.");
|
||||
builder.Append("2. Execute './").Append(options.OfflineScriptFileName).Append(' ');
|
||||
builder.Append(options.ArtifactName).AppendLine("' to extract contents and verify checksums.");
|
||||
builder.AppendLine("3. Review 'bundle.json' for sanitized metadata and incident context.");
|
||||
builder.AppendLine("4. Run 'stella evidence verify --bundle <path>' or use an offline verifier with 'manifest.json' + 'signature.json'.");
|
||||
builder.AppendLine("5. Store the bundle and verification output with the receiving enclave's evidence locker.");
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.303.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="AWSSDK.S3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" />
|
||||
<PackageReference Include="Npgsql" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -11,7 +11,6 @@ using StellaOps.EvidenceLocker.Core.Domain;
|
||||
using StellaOps.EvidenceLocker.Infrastructure.Db;
|
||||
using Xunit;
|
||||
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.EvidenceLocker.Tests;
|
||||
|
||||
@@ -44,7 +43,7 @@ public sealed class DatabaseMigrationTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
|
||||
await _migrationRunner!.ApplyAsync(cancellationToken);
|
||||
|
||||
@@ -101,7 +100,6 @@ public sealed class DatabaseMigrationTests : IAsyncLifetime
|
||||
Assert.Equal(0, otherVisible);
|
||||
|
||||
await using var violationConnection = await _dataSource.OpenConnectionAsync(tenant, cancellationToken);
|
||||
using StellaOps.TestKit;
|
||||
await using var violationCommand = new NpgsqlCommand(@"
|
||||
INSERT INTO evidence_locker.evidence_bundles
|
||||
(bundle_id, tenant_id, kind, status, root_hash, storage_key)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.EvidenceLocker.Core.Builders;
|
||||
using StellaOps.EvidenceLocker.Core.Domain;
|
||||
using StellaOps.EvidenceLocker.Core.Repositories;
|
||||
@@ -19,7 +20,7 @@ public sealed class EvidenceBundleBuilderTests
|
||||
|
||||
public EvidenceBundleBuilderTests()
|
||||
{
|
||||
_builder = new EvidenceBundleBuilder(_repository, new MerkleTreeCalculator());
|
||||
_builder = new EvidenceBundleBuilder(_repository, new MerkleTreeCalculator(new DefaultCryptoHasher(HashAlgorithms.Sha256)));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
|
||||
@@ -64,7 +64,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -107,7 +107,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenant1 = TenantId.FromGuid(Guid.NewGuid());
|
||||
var tenant2 = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
@@ -153,7 +153,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -193,7 +193,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var nonExistentBundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
@@ -235,7 +235,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -311,7 +311,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
@@ -360,7 +360,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -407,7 +407,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -473,7 +473,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -515,7 +515,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -561,7 +561,7 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
Assert.Skip(_skipReason);
|
||||
}
|
||||
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var tenantId = TenantId.FromGuid(Guid.NewGuid());
|
||||
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
@@ -589,7 +589,8 @@ public sealed class EvidenceBundleImmutabilityTests : IAsyncLifetime
|
||||
CaseId: $"CASE-{i:D4}",
|
||||
Reason: $"Legal hold reason {i}",
|
||||
CreatedAt: now.AddMinutes(i),
|
||||
ExpiresAt: now.AddDays(30 + i));
|
||||
ExpiresAt: now.AddDays(30 + i),
|
||||
ReleasedAt: null);
|
||||
|
||||
var createdHold = await _repository.CreateHoldAsync(hold, cancellationToken);
|
||||
holds.Add(createdHold);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Buffers.Binary;
|
||||
using System.Formats.Tar;
|
||||
using System.IO.Compression;
|
||||
using System.Security.Cryptography;
|
||||
@@ -348,11 +348,12 @@ public sealed class EvidenceBundlePackagingServiceTests
|
||||
continue;
|
||||
}
|
||||
|
||||
var posixEntry = entry as PosixTarEntry;
|
||||
entries[entry.Name] = new TarEntryMetadata(
|
||||
entry.Uid,
|
||||
entry.Gid,
|
||||
entry.UserName ?? string.Empty,
|
||||
entry.GroupName ?? string.Empty,
|
||||
posixEntry?.UserName ?? string.Empty,
|
||||
posixEntry?.GroupName ?? string.Empty,
|
||||
entry.ModificationTime);
|
||||
}
|
||||
|
||||
@@ -443,7 +444,6 @@ public sealed class EvidenceBundlePackagingServiceTests
|
||||
{
|
||||
Stored = true;
|
||||
using var memory = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
content.CopyTo(memory);
|
||||
StoredBytes = memory.ToArray();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// EvidenceLockerIntegrationTests.cs
|
||||
// Sprint: SPRINT_5100_0010_0001_evidencelocker_tests
|
||||
// Task: EVIDENCE-5100-007
|
||||
// Description: Integration test: store artifact → retrieve artifact → verify hash matches
|
||||
// Description: Integration test: store artifact → retrieve artifact → verify hash matches
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Net;
|
||||
@@ -20,7 +20,7 @@ namespace StellaOps.EvidenceLocker.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Integration Tests for EvidenceLocker
|
||||
/// Task EVIDENCE-5100-007: store artifact → retrieve artifact → verify hash matches
|
||||
/// Task EVIDENCE-5100-007: store artifact → retrieve artifact → verify hash matches
|
||||
/// </summary>
|
||||
public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
{
|
||||
@@ -34,7 +34,7 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
_client = _factory.CreateClient();
|
||||
}
|
||||
|
||||
#region EVIDENCE-5100-007: Store → Retrieve → Verify Hash
|
||||
#region EVIDENCE-5100-007: Store → Retrieve → Verify Hash
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
@@ -72,10 +72,10 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = storeResult.GetProperty("bundleId").GetString();
|
||||
var storedRootHash = storeResult.GetProperty("rootHash").GetString();
|
||||
|
||||
@@ -85,10 +85,10 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
// Act - Retrieve
|
||||
var retrieveResponse = await _client.GetAsync(
|
||||
$"/evidence/{bundleId}",
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
retrieveResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var retrieveResult = await retrieveResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var retrieveResult = await retrieveResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var retrievedRootHash = retrieveResult.GetProperty("rootHash").GetString();
|
||||
var retrievedBundleId = retrieveResult.GetProperty("bundleId").GetString();
|
||||
|
||||
@@ -111,22 +111,22 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = storeResult.GetProperty("bundleId").GetString();
|
||||
|
||||
// Act - Download
|
||||
var downloadResponse = await _client.GetAsync(
|
||||
$"/evidence/{bundleId}/download",
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
downloadResponse.EnsureSuccessStatusCode();
|
||||
|
||||
// Assert
|
||||
downloadResponse.Content.Headers.ContentType?.MediaType.Should().Be("application/gzip");
|
||||
|
||||
var archiveBytes = await downloadResponse.Content.ReadAsByteArrayAsync(TestContext.Current.CancellationToken);
|
||||
var archiveBytes = await downloadResponse.Content.ReadAsByteArrayAsync(CancellationToken.None);
|
||||
archiveBytes.Should().NotBeEmpty();
|
||||
|
||||
// Verify archive contains manifest with correct bundleId
|
||||
@@ -174,10 +174,10 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
hashes.Add(result.GetProperty("rootHash").GetString()!);
|
||||
}
|
||||
|
||||
@@ -199,10 +199,10 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
|
||||
// Assert - Signature should be present and valid
|
||||
storeResult.TryGetProperty("signature", out var signature).Should().BeTrue();
|
||||
@@ -249,19 +249,19 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = storeResult.GetProperty("bundleId").GetString();
|
||||
|
||||
// Act - Retrieve
|
||||
var retrieveResponse = await _client.GetAsync(
|
||||
$"/evidence/{bundleId}",
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
retrieveResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var retrieveResult = await retrieveResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var retrieveResult = await retrieveResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
|
||||
// Assert - Metadata preserved
|
||||
retrieveResult.TryGetProperty("metadata", out var retrievedMetadata).Should().BeTrue();
|
||||
@@ -289,10 +289,10 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = storeResult.GetProperty("bundleId").GetString();
|
||||
|
||||
// Assert - Timeline event emitted
|
||||
@@ -318,22 +318,22 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
var storeResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
payload,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
storeResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var storeResult = await storeResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = storeResult.GetProperty("bundleId").GetString();
|
||||
|
||||
// Act - Portable download
|
||||
var portableResponse = await _client.GetAsync(
|
||||
$"/evidence/{bundleId}/portable",
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
portableResponse.EnsureSuccessStatusCode();
|
||||
|
||||
// Assert
|
||||
portableResponse.Content.Headers.ContentType?.MediaType.Should().Be("application/gzip");
|
||||
|
||||
var archiveBytes = await portableResponse.Content.ReadAsByteArrayAsync(TestContext.Current.CancellationToken);
|
||||
var archiveBytes = await portableResponse.Content.ReadAsByteArrayAsync(CancellationToken.None);
|
||||
var entries = ReadGzipTarEntries(archiveBytes);
|
||||
|
||||
// Portable bundle should have manifest but be sanitized
|
||||
@@ -395,7 +395,6 @@ public sealed class EvidenceLockerIntegrationTests : IDisposable
|
||||
if (entry.DataStream is not null)
|
||||
{
|
||||
using var contentStream = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
entry.DataStream.CopyTo(contentStream);
|
||||
entries[entry.Name] = Encoding.UTF8.GetString(contentStream.ToArray());
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ using StellaOps.EvidenceLocker.Core.Incident;
|
||||
using StellaOps.EvidenceLocker.Core.Timeline;
|
||||
using StellaOps.EvidenceLocker.Core.Storage;
|
||||
|
||||
using EvidenceLockerProgram = StellaOps.EvidenceLocker.WebService.Program;
|
||||
|
||||
namespace StellaOps.EvidenceLocker.Tests;
|
||||
|
||||
internal sealed class EvidenceLockerWebApplicationFactory : WebApplicationFactory<Program>
|
||||
internal sealed class EvidenceLockerWebApplicationFactory : WebApplicationFactory<EvidenceLockerProgram>
|
||||
{
|
||||
private readonly string _contentRoot;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// EvidenceLockerWebServiceContractTests.cs
|
||||
// Sprint: SPRINT_5100_0010_0001_evidencelocker_tests
|
||||
// Tasks: EVIDENCE-5100-004, EVIDENCE-5100-005, EVIDENCE-5100-006
|
||||
@@ -53,12 +53,12 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
|
||||
var payload = CreateValidSnapshotPayload();
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var response = await _client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var content = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
using var doc = JsonDocument.Parse(content);
|
||||
var root = doc.RootElement;
|
||||
|
||||
@@ -85,21 +85,20 @@ public sealed class EvidenceLockerWebServiceContractTests : IDisposable
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var content = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
using var doc = JsonDocument.Parse(content);
|
||||
using StellaOps.TestKit;
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Verify contract schema for retrieved bundle
|
||||
@@ -121,14 +120,14 @@ using StellaOps.TestKit;
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}/download", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}/download", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -145,7 +144,7 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert - Unauthorized should return consistent error schema
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
|
||||
@@ -161,7 +160,7 @@ using StellaOps.TestKit;
|
||||
var nonExistentId = Guid.NewGuid();
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{nonExistentId}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{nonExistentId}", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
@@ -181,7 +180,7 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
|
||||
@@ -199,7 +198,7 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().BeOneOf(HttpStatusCode.Forbidden, HttpStatusCode.Unauthorized);
|
||||
@@ -217,7 +216,7 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -234,17 +233,17 @@ using StellaOps.TestKit;
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Change to no read scope
|
||||
ConfigureAuthHeaders(_client, tenantId, scopes: StellaOpsScopes.EvidenceCreate);
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().BeOneOf(HttpStatusCode.Forbidden, HttpStatusCode.Unauthorized);
|
||||
@@ -261,10 +260,10 @@ using StellaOps.TestKit;
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Try to access as tenant B
|
||||
@@ -272,7 +271,7 @@ using StellaOps.TestKit;
|
||||
ConfigureAuthHeaders(_client, tenantB, scopes: $"{StellaOpsScopes.EvidenceRead}");
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", CancellationToken.None);
|
||||
|
||||
// Assert - Should not be accessible across tenants
|
||||
response.StatusCode.Should().BeOneOf(HttpStatusCode.NotFound, HttpStatusCode.Forbidden);
|
||||
@@ -289,17 +288,17 @@ using StellaOps.TestKit;
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Remove read scope
|
||||
ConfigureAuthHeaders(_client, tenantId, scopes: StellaOpsScopes.EvidenceCreate);
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}/download", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}/download", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().BeOneOf(HttpStatusCode.Forbidden, HttpStatusCode.Unauthorized);
|
||||
@@ -340,10 +339,10 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await response.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await response.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Assert
|
||||
@@ -369,7 +368,7 @@ using StellaOps.TestKit;
|
||||
var response = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
// Assert
|
||||
@@ -391,17 +390,17 @@ using StellaOps.TestKit;
|
||||
var createResponse = await _client.PostAsJsonAsync(
|
||||
"/evidence/snapshot",
|
||||
CreateValidSnapshotPayload(),
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
createResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(TestContext.Current.CancellationToken);
|
||||
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>(CancellationToken.None);
|
||||
var bundleId = created.GetProperty("bundleId").GetString();
|
||||
|
||||
// Clear timeline events before retrieve
|
||||
_factory.TimelinePublisher.ClearEvents();
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{bundleId}", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
@@ -417,12 +416,12 @@ using StellaOps.TestKit;
|
||||
ConfigureAuthHeaders(_client, tenantId, scopes: StellaOpsScopes.EvidenceRead);
|
||||
|
||||
// Act - Request non-existent bundle
|
||||
var response = await _client.GetAsync($"/evidence/{Guid.NewGuid()}", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync($"/evidence/{Guid.NewGuid()}", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var content = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
content.Should().NotContain("Exception");
|
||||
content.Should().NotContain("StackTrace");
|
||||
content.Should().NotContain("InnerException");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Buffers.Binary;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Formats.Tar;
|
||||
using System.IO;
|
||||
@@ -50,10 +50,10 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
snapshotResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(TestContext.Current.CancellationToken);
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(CancellationToken.None);
|
||||
Assert.NotNull(snapshot);
|
||||
Assert.NotEqual(Guid.Empty, snapshot!.BundleId);
|
||||
Assert.False(string.IsNullOrEmpty(snapshot.RootHash));
|
||||
@@ -65,7 +65,7 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
Assert.Contains(snapshot.BundleId.ToString("D"), timelineEvent);
|
||||
Assert.Contains(snapshot.RootHash, timelineEvent);
|
||||
|
||||
var bundle = await client.GetFromJsonAsync<EvidenceBundleResponseDto>($"/evidence/{snapshot.BundleId}", TestContext.Current.CancellationToken);
|
||||
var bundle = await client.GetFromJsonAsync<EvidenceBundleResponseDto>($"/evidence/{snapshot.BundleId}", CancellationToken.None);
|
||||
Assert.NotNull(bundle);
|
||||
Assert.Equal(snapshot.RootHash, bundle!.RootHash);
|
||||
Assert.NotNull(bundle.Signature);
|
||||
@@ -105,13 +105,13 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
snapshotResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(TestContext.Current.CancellationToken);
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(CancellationToken.None);
|
||||
Assert.NotNull(snapshot);
|
||||
|
||||
var bundle = await client.GetFromJsonAsync<EvidenceBundleResponseDto>($"/evidence/{snapshot!.BundleId}", TestContext.Current.CancellationToken);
|
||||
var bundle = await client.GetFromJsonAsync<EvidenceBundleResponseDto>($"/evidence/{snapshot!.BundleId}", CancellationToken.None);
|
||||
Assert.NotNull(bundle);
|
||||
Assert.NotNull(bundle!.ExpiresAt);
|
||||
Assert.True(bundle.ExpiresAt > bundle.CreatedAt);
|
||||
@@ -141,17 +141,17 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
snapshotResponse.EnsureSuccessStatusCode();
|
||||
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(TestContext.Current.CancellationToken);
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(CancellationToken.None);
|
||||
Assert.NotNull(snapshot);
|
||||
|
||||
var downloadResponse = await client.GetAsync($"/evidence/{snapshot!.BundleId}/download", TestContext.Current.CancellationToken);
|
||||
var downloadResponse = await client.GetAsync($"/evidence/{snapshot!.BundleId}/download", CancellationToken.None);
|
||||
downloadResponse.EnsureSuccessStatusCode();
|
||||
Assert.Equal("application/gzip", downloadResponse.Content.Headers.ContentType?.MediaType);
|
||||
|
||||
var archiveBytes = await downloadResponse.Content.ReadAsByteArrayAsync(TestContext.Current.CancellationToken);
|
||||
var archiveBytes = await downloadResponse.Content.ReadAsByteArrayAsync(CancellationToken.None);
|
||||
var mtime = BinaryPrimitives.ReadInt32LittleEndian(archiveBytes.AsSpan(4, 4));
|
||||
var expectedSeconds = (int)(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero) - DateTimeOffset.UnixEpoch).TotalSeconds;
|
||||
Assert.Equal(expectedSeconds, mtime);
|
||||
@@ -196,16 +196,16 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var snapshotResponse = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
snapshotResponse.EnsureSuccessStatusCode();
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(TestContext.Current.CancellationToken);
|
||||
var snapshot = await snapshotResponse.Content.ReadFromJsonAsync<EvidenceSnapshotResponseDto>(CancellationToken.None);
|
||||
Assert.NotNull(snapshot);
|
||||
|
||||
var portableResponse = await client.GetAsync($"/evidence/{snapshot!.BundleId}/portable", TestContext.Current.CancellationToken);
|
||||
var portableResponse = await client.GetAsync($"/evidence/{snapshot!.BundleId}/portable", CancellationToken.None);
|
||||
portableResponse.EnsureSuccessStatusCode();
|
||||
Assert.Equal("application/gzip", portableResponse.Content.Headers.ContentType?.MediaType);
|
||||
|
||||
var archiveBytes = await portableResponse.Content.ReadAsByteArrayAsync(TestContext.Current.CancellationToken);
|
||||
var archiveBytes = await portableResponse.Content.ReadAsByteArrayAsync(CancellationToken.None);
|
||||
var entries = ReadArchiveEntries(archiveBytes);
|
||||
Assert.Contains("bundle.json", entries.Keys);
|
||||
Assert.Contains("instructions-portable.txt", entries.Keys);
|
||||
@@ -243,11 +243,11 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var response = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var responseContent = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
Assert.True(response.StatusCode == HttpStatusCode.BadRequest, $"Expected 400 but received {(int)response.StatusCode}: {responseContent}");
|
||||
var problem = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>(TestContext.Current.CancellationToken);
|
||||
var problem = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>(CancellationToken.None);
|
||||
Assert.NotNull(problem);
|
||||
Assert.True(problem!.Errors.TryGetValue("message", out var messages));
|
||||
Assert.Contains(messages, m => m.Contains("exceeds", StringComparison.OrdinalIgnoreCase));
|
||||
@@ -272,9 +272,9 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
var response = await client.PostAsJsonAsync("/evidence/snapshot", payload, TestContext.Current.CancellationToken);
|
||||
var response = await client.PostAsJsonAsync("/evidence/snapshot", payload, CancellationToken.None);
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var responseContent = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
Assert.True(response.StatusCode == HttpStatusCode.Forbidden, $"Expected 403 but received {(int)response.StatusCode}: {responseContent}");
|
||||
}
|
||||
|
||||
@@ -296,11 +296,11 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
{
|
||||
reason = "legal-hold"
|
||||
},
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
|
||||
var responseContent = await response.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
Assert.True(response.StatusCode == HttpStatusCode.BadRequest, $"Expected 400 but received {(int)response.StatusCode}: {responseContent}");
|
||||
var problem = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>(TestContext.Current.CancellationToken);
|
||||
var problem = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>(CancellationToken.None);
|
||||
Assert.NotNull(problem);
|
||||
Assert.True(problem!.Errors.TryGetValue("message", out var messages));
|
||||
Assert.Contains(messages, m => m.IndexOf("already exists", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
@@ -323,10 +323,10 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
reason = "retention",
|
||||
notes = "retain for investigation"
|
||||
},
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
var hold = await response.Content.ReadFromJsonAsync<EvidenceHoldResponseDto>(TestContext.Current.CancellationToken);
|
||||
var hold = await response.Content.ReadFromJsonAsync<EvidenceHoldResponseDto>(CancellationToken.None);
|
||||
Assert.NotNull(hold);
|
||||
Assert.Contains($"hold:{hold!.CaseId}", factory.TimelinePublisher.PublishedEvents);
|
||||
}
|
||||
@@ -347,7 +347,6 @@ public sealed class EvidenceLockerWebServiceTests
|
||||
}
|
||||
|
||||
using var entryStream = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
entry.DataStream!.CopyTo(entryStream);
|
||||
var content = Encoding.UTF8.GetString(entryStream.ToArray());
|
||||
entries[entry.Name] = content;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Formats.Tar;
|
||||
using System.Formats.Tar;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -248,11 +248,12 @@ public sealed class EvidencePortableBundleServiceTests
|
||||
continue;
|
||||
}
|
||||
|
||||
var posixEntry = entry as PosixTarEntry;
|
||||
entries[entry.Name] = new TarEntryMetadata(
|
||||
entry.Uid,
|
||||
entry.Gid,
|
||||
entry.UserName ?? string.Empty,
|
||||
entry.GroupName ?? string.Empty,
|
||||
posixEntry?.UserName ?? string.Empty,
|
||||
posixEntry?.GroupName ?? string.Empty,
|
||||
entry.ModificationTime);
|
||||
}
|
||||
|
||||
@@ -337,7 +338,6 @@ public sealed class EvidencePortableBundleServiceTests
|
||||
{
|
||||
Stored = true;
|
||||
using var memory = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
content.CopyTo(memory);
|
||||
StoredBytes = memory.ToArray();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Security.Cryptography;
|
||||
@@ -200,7 +200,6 @@ public sealed class EvidenceSignatureServiceTests
|
||||
private static SigningKeyMaterialOptions CreateKeyMaterial()
|
||||
{
|
||||
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
||||
using StellaOps.TestKit;
|
||||
var privatePem = ecdsa.ExportECPrivateKeyPem();
|
||||
var publicPem = ecdsa.ExportSubjectPublicKeyInfoPem();
|
||||
return new SigningKeyMaterialOptions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Linq;
|
||||
@@ -477,7 +477,6 @@ public sealed class EvidenceSnapshotServiceTests
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var memory = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
content.CopyTo(memory);
|
||||
var bytes = memory.ToArray();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.EvidenceLocker.Core.Configuration;
|
||||
using StellaOps.EvidenceLocker.Core.Domain;
|
||||
@@ -22,7 +22,7 @@ public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
|
||||
[Fact]
|
||||
public async Task StoreAsync_EnforcesWriteOnceWhenConfigured()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var store = CreateStore(enforceWriteOnce: true);
|
||||
var options = CreateWriteOptions();
|
||||
|
||||
@@ -37,7 +37,7 @@ public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
|
||||
[Fact]
|
||||
public async Task StoreAsync_AllowsOverwriteWhenWriteOnceDisabled()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var cancellationToken = CancellationToken.None;
|
||||
var store = CreateStore(enforceWriteOnce: false);
|
||||
var options = CreateWriteOptions() with { EnforceWriteOnce = false };
|
||||
|
||||
@@ -45,7 +45,6 @@ public sealed class FileSystemEvidenceObjectStoreTests : IDisposable
|
||||
var firstMetadata = await store.StoreAsync(first, options, cancellationToken);
|
||||
|
||||
using var second = CreateStream("payload-1");
|
||||
using StellaOps.TestKit;
|
||||
var secondMetadata = await store.StoreAsync(second, options, cancellationToken);
|
||||
|
||||
Assert.Equal(firstMetadata.Sha256, secondMetadata.Sha256);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -77,7 +77,6 @@ public sealed class GoldenFixturesTests
|
||||
private static JsonElement ReadJson(string path)
|
||||
{
|
||||
using var doc = JsonDocument.Parse(File.ReadAllText(path), new JsonDocumentOptions { AllowTrailingCommas = true });
|
||||
using StellaOps.TestKit;
|
||||
return doc.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Amazon;
|
||||
@@ -116,7 +116,6 @@ public sealed class S3EvidenceObjectStoreTests
|
||||
var ifNoneMatch = request.Headers?["If-None-Match"];
|
||||
|
||||
using var memory = new MemoryStream();
|
||||
using StellaOps.TestKit;
|
||||
request.InputStream.CopyTo(memory);
|
||||
|
||||
PutRequests.Add(new CapturedPutObjectRequest(
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<UseXunitV3>true</UseXunitV3>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNet.Testcontainers" Version="1.6.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="xunit.v3" Version="3.0.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3" />
|
||||
<PackageReference Include="DotNet.Testcontainers" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
|
||||
<PackageReference Include="Npgsql" />
|
||||
<PackageReference Include="xunit.v3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -35,5 +33,6 @@
|
||||
<ProjectReference Include="..\StellaOps.EvidenceLocker.Infrastructure\StellaOps.EvidenceLocker.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\StellaOps.EvidenceLocker.WebService\StellaOps.EvidenceLocker.WebService.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
@@ -125,7 +125,6 @@ public sealed class TimelineIndexerEvidenceTimelinePublisherTests
|
||||
Assert.Equal(HttpMethod.Post, request.Method);
|
||||
|
||||
using var json = JsonDocument.Parse(request.Content!);
|
||||
using StellaOps.TestKit;
|
||||
var root = json.RootElement;
|
||||
Assert.Equal("evidence.hold.created", root.GetProperty("kind").GetString());
|
||||
Assert.Equal(hold.CaseId, root.GetProperty("attributes").GetProperty("caseId").GetString());
|
||||
|
||||
@@ -347,3 +347,9 @@ static IResult ValidationProblem(string message)
|
||||
{
|
||||
["message"] = new[] { message }
|
||||
});
|
||||
|
||||
// Make Program class accessible for integration testing
|
||||
namespace StellaOps.EvidenceLocker.WebService
|
||||
{
|
||||
public partial class Program { }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
|
||||
</ItemGroup>
|
||||
<!-- Include Api folder from parent project -->
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Api\**\*.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StellaOps.EvidenceLocker.csproj" />
|
||||
@@ -17,6 +21,6 @@
|
||||
<ProjectReference Include="..\StellaOps.EvidenceLocker.Infrastructure\StellaOps.EvidenceLocker.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj" />
|
||||
<ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Router.AspNet\StellaOps.Router.AspNet.csproj" />
|
||||
<ProjectReference Include="..\..\..\Router/__Libraries/StellaOps.Router.AspNet\StellaOps.Router.AspNet.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Exclude subprojects from compilation - they have their own .csproj files -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="Dapper" Version="2.1.35" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||
<Compile Remove="Api\**\*.cs" />
|
||||
<Compile Remove="StellaOps.EvidenceLocker.Core\**\*.cs" />
|
||||
<Compile Remove="StellaOps.EvidenceLocker.Infrastructure\**\*.cs" />
|
||||
<Compile Remove="StellaOps.EvidenceLocker.Tests\**\*.cs" />
|
||||
<Compile Remove="StellaOps.EvidenceLocker.WebService\**\*.cs" />
|
||||
<Compile Remove="StellaOps.EvidenceLocker.Worker\**\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql" />
|
||||
<PackageReference Include="Dapper" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
|
||||
<PackageReference Include="Serilog.AspNetCore" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.EvidenceLocker.Core", "StellaOps.EvidenceLocker.Core\StellaOps.EvidenceLocker.Core.csproj", "{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.EvidenceLocker.Infrastructure", "StellaOps.EvidenceLocker.Infrastructure\StellaOps.EvidenceLocker.Infrastructure.csproj", "{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.EvidenceLocker.WebService", "StellaOps.EvidenceLocker.WebService\StellaOps.EvidenceLocker.WebService.csproj", "{392D1580-C75B-4CB2-8F26-45C65268A191}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.EvidenceLocker.Worker", "StellaOps.EvidenceLocker.Worker\StellaOps.EvidenceLocker.Worker.csproj", "{B384F421-48D0-48EB-A63F-0AF28EBC75EB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.EvidenceLocker.Tests", "StellaOps.EvidenceLocker.Tests\StellaOps.EvidenceLocker.Tests.csproj", "{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{217D54F6-D07F-4B1E-8598-7DCAF0BD65C7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BF61F2F5-4ECA-4DA6-AC6B-102C39D225A1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|x64.Build.0 = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{392D1580-C75B-4CB2-8F26-45C65268A191}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B384F421-48D0-48EB-A63F-0AF28EBC75EB}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B9D6DCF2-1C6F-41E5-8D63-118BD0751839}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user