Files
git.stella-ops.org/src/Policy/__Tests/StellaOps.Policy.Tests/Snapshots/SnapshotBuilderTests.cs
StellaOps Bot 5146204f1b feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
2025-12-22 23:21:21 +02:00

160 lines
5.3 KiB
C#

using FluentAssertions;
using StellaOps.Cryptography;
using StellaOps.Policy.Snapshots;
using Xunit;
namespace StellaOps.Policy.Tests.Snapshots;
public sealed class SnapshotBuilderTests
{
private readonly ICryptoHash _hasher = DefaultCryptoHash.CreateForTests();
[Fact]
public void Build_ValidInputs_CreatesManifest()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz");
var manifest = builder.Build();
manifest.SnapshotId.Should().StartWith("ksm:sha256:");
manifest.SnapshotId.Length.Should().Be("ksm:sha256:".Length + 64); // ksm:sha256: + 64 hex chars
manifest.Sources.Should().HaveCount(1);
manifest.Engine.Name.Should().Be("test");
manifest.Engine.Version.Should().Be("1.0");
manifest.Engine.Commit.Should().Be("abc123");
manifest.Policy.PolicyId.Should().Be("policy-1");
manifest.Scoring.RulesId.Should().Be("scoring-1");
}
[Fact]
public void Build_MissingEngine_Throws()
{
var builder = new SnapshotBuilder(_hasher)
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz");
var act = () => builder.Build();
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Engine*");
}
[Fact]
public void Build_MissingPolicy_Throws()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz");
var act = () => builder.Build();
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Policy*");
}
[Fact]
public void Build_MissingScoring_Throws()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz");
var act = () => builder.Build();
act.Should().Throw<InvalidOperationException>()
.WithMessage("*Scoring*");
}
[Fact]
public void Build_NoSources_Throws()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy");
var act = () => builder.Build();
act.Should().Throw<InvalidOperationException>()
.WithMessage("*source*");
}
[Fact]
public void Build_MultipleSources_OrderedByName()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("z-source", "2025-12-21", "sha256:aaa")
.WithAdvisoryFeed("a-source", "2025-12-21", "sha256:bbb")
.WithAdvisoryFeed("m-source", "2025-12-21", "sha256:ccc");
var manifest = builder.Build();
manifest.Sources.Should().HaveCount(3);
manifest.Sources[0].Name.Should().Be("a-source");
manifest.Sources[1].Name.Should().Be("m-source");
manifest.Sources[2].Name.Should().Be("z-source");
}
[Fact]
public void Build_WithPlugins_IncludesPlugins()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz")
.WithPlugin("reachability", "2.0", "analyzer")
.WithPlugin("sbom", "1.5", "analyzer");
var manifest = builder.Build();
manifest.Plugins.Should().HaveCount(2);
manifest.Plugins[0].Name.Should().Be("reachability");
manifest.Plugins[1].Name.Should().Be("sbom");
}
[Fact]
public void Build_WithTrust_IncludesTrust()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz")
.WithTrust("trust-bundle", "sha256:trust123");
var manifest = builder.Build();
manifest.Trust.Should().NotBeNull();
manifest.Trust!.BundleId.Should().Be("trust-bundle");
manifest.Trust.Digest.Should().Be("sha256:trust123");
}
[Fact]
public void Build_CaptureCurrentEnvironment_SetsEnvironment()
{
var builder = new SnapshotBuilder(_hasher)
.WithEngine("test", "1.0", "abc123")
.WithPolicy("policy-1", "sha256:xxx")
.WithScoring("scoring-1", "sha256:yyy")
.WithAdvisoryFeed("nvd", "2025-12-21", "sha256:zzz")
.CaptureCurrentEnvironment();
var manifest = builder.Build();
manifest.Environment.Should().NotBeNull();
manifest.Environment!.Platform.Should().NotBeNullOrEmpty();
manifest.Environment.Locale.Should().NotBeNullOrEmpty();
}
}