audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories

This commit is contained in:
master
2026-01-07 18:49:59 +02:00
parent 04ec098046
commit 608a7f85c0
866 changed files with 56323 additions and 6231 deletions

View File

@@ -11,10 +11,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.runner.visualstudio" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>

View File

@@ -0,0 +1,242 @@
// <copyright file="AirGapBundleDsseSignerTests.cs" company="StellaOps">
// Copyright (c) StellaOps. Licensed under AGPL-3.0-or-later.
// </copyright>
using System.Security.Cryptography;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.AirGap.Sync.Models;
using StellaOps.AirGap.Sync.Services;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.AirGap.Sync.Tests;
/// <summary>
/// Unit tests for <see cref="AirGapBundleDsseSigner"/>.
/// </summary>
[Trait("Category", TestCategories.Unit)]
public sealed class AirGapBundleDsseSignerTests
{
private static readonly string TestSecretBase64 = Convert.ToBase64String(
RandomNumberGenerator.GetBytes(32));
[Fact]
public async Task SignAsync_WhenDisabled_ReturnsNull()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions { Mode = "none" });
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Act
var result = await signer.SignAsync(bundle);
// Assert
result.Should().BeNull();
signer.IsEnabled.Should().BeFalse();
}
[Fact]
public async Task SignAsync_WhenEnabled_ReturnsValidSignature()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64,
KeyId = "test-key"
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Act
var result = await signer.SignAsync(bundle);
// Assert
result.Should().NotBeNull();
result!.KeyId.Should().Be("test-key");
result.Signature.Should().NotBeEmpty();
result.SignatureBase64.Should().NotBeNullOrWhiteSpace();
signer.IsEnabled.Should().BeTrue();
}
[Fact]
public async Task SignAsync_DeterministicForSameInput()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Act
var result1 = await signer.SignAsync(bundle);
var result2 = await signer.SignAsync(bundle);
// Assert
result1!.SignatureBase64.Should().Be(result2!.SignatureBase64);
}
[Fact]
public async Task SignAsync_DifferentForDifferentManifest()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle1 = CreateTestBundle(manifestDigest: "sha256:aaa");
var bundle2 = CreateTestBundle(manifestDigest: "sha256:bbb");
// Act
var result1 = await signer.SignAsync(bundle1);
var result2 = await signer.SignAsync(bundle2);
// Assert
result1!.SignatureBase64.Should().NotBe(result2!.SignatureBase64);
}
[Fact]
public async Task VerifyAsync_WhenDisabled_ReturnsSigningDisabled()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions { Mode = "none" });
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Act
var result = await signer.VerifyAsync(bundle);
// Assert
result.Should().Be(AirGapBundleVerificationResult.SigningDisabled);
}
[Fact]
public async Task VerifyAsync_WhenNoSignature_ReturnsMissingSignature()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle(signature: null);
// Act
var result = await signer.VerifyAsync(bundle);
// Assert
result.Should().Be(AirGapBundleVerificationResult.MissingSignature);
}
[Fact]
public async Task VerifyAsync_WithValidSignature_ReturnsValid()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Sign the bundle first
var signResult = await signer.SignAsync(bundle);
var signedBundle = bundle with { Signature = signResult!.SignatureBase64, SignedBy = signResult.KeyId };
// Act
var verifyResult = await signer.VerifyAsync(signedBundle);
// Assert
verifyResult.Should().Be(AirGapBundleVerificationResult.Valid);
}
[Fact]
public async Task VerifyAsync_WithTamperedSignature_ReturnsInvalid()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Sign and then tamper
var signResult = await signer.SignAsync(bundle);
var tamperedBundle = bundle with
{
Signature = signResult!.SignatureBase64,
ManifestDigest = "sha256:tampered"
};
// Act
var verifyResult = await signer.VerifyAsync(tamperedBundle);
// Assert
verifyResult.Should().Be(AirGapBundleVerificationResult.InvalidSignature);
}
[Fact]
public async Task VerifyAsync_WithInvalidBase64Signature_ReturnsInvalid()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = TestSecretBase64
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle(signature: "not-valid-base64!!!");
// Act
var verifyResult = await signer.VerifyAsync(bundle);
// Assert
verifyResult.Should().Be(AirGapBundleVerificationResult.InvalidSignature);
}
[Fact]
public void SignAsync_WithMissingSecret_ThrowsInvalidOperation()
{
// Arrange
var options = Options.Create(new AirGapBundleDsseOptions
{
Mode = "hmac",
SecretBase64 = null
});
var signer = new AirGapBundleDsseSigner(options, NullLogger<AirGapBundleDsseSigner>.Instance);
var bundle = CreateTestBundle();
// Act & Assert
var act = async () => await signer.SignAsync(bundle);
act.Should().ThrowAsync<InvalidOperationException>()
.WithMessage("*SecretBase64*");
}
private static AirGapBundle CreateTestBundle(
string? manifestDigest = null,
string? signature = null)
{
return new AirGapBundle
{
BundleId = Guid.Parse("11111111-1111-1111-1111-111111111111"),
TenantId = "test-tenant",
CreatedAt = DateTimeOffset.Parse("2026-01-07T12:00:00Z"),
CreatedByNodeId = "test-node",
JobLogs = new List<NodeJobLog>(),
ManifestDigest = manifestDigest ?? "sha256:abc123def456",
Signature = signature
};
}
}

View File

@@ -11,10 +11,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>

View File

@@ -95,6 +95,7 @@ public class Rfc3161VerifierTests
Assert.False(result.IsValid);
// Should report either decode or error
Assert.True(result.Reason?.Contains("rfc3161-") ?? false);
Assert.NotNull(result.Reason);
Assert.Contains("rfc3161-", result.Reason);
}
}