- 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.
160 lines
5.3 KiB
C#
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();
|
|
}
|
|
}
|