audit remarks work

This commit is contained in:
master
2025-12-30 16:10:34 +02:00
parent e6ee092c7a
commit c706b3d3e0
72 changed files with 9997 additions and 5323 deletions

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\FixtureUpdater\FixtureUpdater.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using StellaOps.Tools.FixtureUpdater;
using Xunit;
public sealed class FixtureUpdaterRunnerTests
{
[Fact]
public void Run_IsDeterministic_And_WritesGhsaFixtures()
{
var repoRoot = FindRepoRoot();
using var temp = new TempDirectory();
var osvDir = Path.Combine(temp.Path, "osv");
var ghsaDir = Path.Combine(temp.Path, "ghsa");
var nvdDir = Path.Combine(temp.Path, "nvd");
Directory.CreateDirectory(osvDir);
Directory.CreateDirectory(ghsaDir);
Directory.CreateDirectory(nvdDir);
File.Copy(
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Osv.Tests", "Fixtures", "osv-ghsa.raw-osv.json"),
Path.Combine(osvDir, "osv-ghsa.raw-osv.json"));
File.Copy(
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Ghsa.Tests", "Fixtures", "osv-ghsa.raw-ghsa.json"),
Path.Combine(ghsaDir, "osv-ghsa.raw-ghsa.json"));
var options = new FixtureUpdaterOptions(
RepoRoot: null,
OsvFixturesPath: osvDir,
GhsaFixturesPath: ghsaDir,
NvdFixturesPath: nvdDir,
FixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
var firstResult = new FixtureUpdaterRunner(options).Run();
Assert.Equal(0, firstResult.ErrorCount);
var firstOutputs = ReadOutputs(temp.Path);
var secondResult = new FixtureUpdaterRunner(options).Run();
Assert.Equal(0, secondResult.ErrorCount);
var secondOutputs = ReadOutputs(temp.Path);
Assert.Equal(firstOutputs.Count, secondOutputs.Count);
foreach (var (path, content) in firstOutputs)
{
Assert.True(secondOutputs.TryGetValue(path, out var secondContent));
Assert.Equal(content, secondContent);
}
Assert.True(File.Exists(Path.Combine(ghsaDir, "osv-ghsa.ghsa.json")));
Assert.False(File.Exists(Path.Combine(osvDir, "osv-ghsa.ghsa.json")));
}
[Fact]
public void Run_Reports_ParseErrors_With_Context()
{
var repoRoot = FindRepoRoot();
using var temp = new TempDirectory();
var osvDir = Path.Combine(temp.Path, "osv");
var ghsaDir = Path.Combine(temp.Path, "ghsa");
var nvdDir = Path.Combine(temp.Path, "nvd");
Directory.CreateDirectory(osvDir);
Directory.CreateDirectory(ghsaDir);
Directory.CreateDirectory(nvdDir);
File.Copy(
Path.Combine(repoRoot, "src", "Concelier", "__Tests", "StellaOps.Concelier.Connector.Osv.Tests", "Fixtures", "osv-ghsa.raw-osv.json"),
Path.Combine(osvDir, "osv-ghsa.raw-osv.json"));
File.WriteAllText(Path.Combine(ghsaDir, "osv-ghsa.raw-ghsa.json"), "{ broken json }");
var errors = new List<string>();
var options = new FixtureUpdaterOptions(
RepoRoot: null,
OsvFixturesPath: osvDir,
GhsaFixturesPath: ghsaDir,
NvdFixturesPath: nvdDir,
FixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
var result = new FixtureUpdaterRunner(options, _ => { }, message => errors.Add(message)).Run();
Assert.True(result.ErrorCount > 0);
Assert.Contains(errors, message => message.Contains("osv-ghsa.raw-ghsa.json", StringComparison.Ordinal));
}
private static Dictionary<string, string> ReadOutputs(string root)
{
var files = Directory.GetFiles(root, "*.json", SearchOption.AllDirectories)
.OrderBy(path => path, StringComparer.Ordinal)
.ToArray();
var outputs = new Dictionary<string, string>(StringComparer.Ordinal);
foreach (var file in files)
{
var relative = Path.GetRelativePath(root, file);
var content = File.ReadAllText(file).ReplaceLineEndings("\n");
outputs[relative] = content;
}
return outputs;
}
private static string FindRepoRoot()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current is not null)
{
var solution = Path.Combine(current.FullName, "src", "StellaOps.sln");
if (File.Exists(solution))
{
return current.FullName;
}
current = current.Parent;
}
throw new InvalidOperationException("Repository root not found.");
}
private sealed class TempDirectory : IDisposable
{
public TempDirectory()
{
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"fixture-updater-{Guid.NewGuid():N}");
Directory.CreateDirectory(Path);
}
public string Path { get; }
public void Dispose()
{
if (Directory.Exists(Path))
{
Directory.Delete(Path, recursive: true);
}
}
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\LanguageAnalyzerSmoke\LanguageAnalyzerSmoke.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using StellaOps.Tools.LanguageAnalyzerSmoke;
using Xunit;
public sealed class LanguageAnalyzerSmokeRunnerTests
{
[Fact]
public void Resolve_UsesProfileDefaults_WhenOverridesMissing()
{
var profile = AnalyzerProfileCatalog.GetProfile("python");
var options = SmokeOptions.Resolve(
repoRoot: "C:\\repo",
analyzerId: "python",
pluginDirectoryName: null,
fixtureRelativePath: null,
allowGoldenDrift: false,
fixedTime: new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
useSystemTime: false,
timeoutSeconds: 120);
Assert.Equal(profile.PluginDirectory, options.PluginDirectoryName);
Assert.Equal(profile.FixtureRelativePath, options.FixtureRelativePath);
Assert.Equal(profile.AnalyzerId, options.AnalyzerId);
}
[Fact]
public void ValidateManifest_RejectsMissingCapabilities()
{
var profile = AnalyzerProfileCatalog.GetProfile("python");
var manifest = new PluginManifest
{
SchemaVersion = "1.0",
Id = profile.ExpectedPluginId,
RequiresRestart = true,
EntryPoint = new PluginEntryPoint
{
Type = "dotnet",
TypeName = profile.ExpectedEntryPointType,
Assembly = "Plugin.dll"
},
Capabilities = Array.Empty<string>()
};
var exception = Assert.Throws<InvalidOperationException>(() =>
LanguageAnalyzerSmokeRunner.ValidateManifest(manifest, profile, profile.PluginDirectory));
Assert.Contains("capability", exception.Message, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void CompareGoldenSnapshot_Throws_WhenDriftNotAllowed()
{
Assert.Throws<InvalidOperationException>(() =>
LanguageAnalyzerSmokeRunner.CompareGoldenSnapshot(
scenarioName: "sample",
actualJson: "{\"a\":1}",
goldenNormalized: "{\"a\":2}",
allowGoldenDrift: false,
info: _ => { }));
}
[Fact]
public void CompareGoldenSnapshot_AllowsWhenDriftAllowed()
{
var warnings = new List<string>();
LanguageAnalyzerSmokeRunner.CompareGoldenSnapshot(
scenarioName: "sample",
actualJson: "{\"a\":1}",
goldenNormalized: "{\"a\":2}",
allowGoldenDrift: true,
info: message => warnings.Add(message));
Assert.Single(warnings);
Assert.Contains("golden", warnings[0], StringComparison.OrdinalIgnoreCase);
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\NotifySmokeCheck\NotifySmokeCheck.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using StackExchange.Redis;
using StellaOps.Tools.NotifySmokeCheck;
using Xunit;
public sealed class NotifySmokeCheckRunnerTests
{
[Fact]
public void FromEnvironment_ParsesExpectedKinds()
{
var env = new Dictionary<string, string>(StringComparer.Ordinal)
{
["NOTIFY_SMOKE_REDIS_DSN"] = "localhost:6379",
["NOTIFY_SMOKE_EXPECT_KINDS"] = "scan, scan, Alert",
["NOTIFY_SMOKE_LOOKBACK_MINUTES"] = "15",
["NOTIFY_SMOKE_NOTIFY_BASEURL"] = "https://notify.local",
["NOTIFY_SMOKE_NOTIFY_TOKEN"] = "token",
["NOTIFY_SMOKE_NOTIFY_TENANT"] = "tenant"
};
var options = NotifySmokeOptions.FromEnvironment(name => env.TryGetValue(name, out var value) ? value : null);
Assert.Equal(new[] { "scan", "alert" }, options.ExpectedKinds);
}
[Fact]
public void FromEnvironment_UsesFixedTimeWhenProvided()
{
var env = new Dictionary<string, string>(StringComparer.Ordinal)
{
["NOTIFY_SMOKE_REDIS_DSN"] = "localhost:6379",
["NOTIFY_SMOKE_EXPECT_KINDS"] = "scan",
["NOTIFY_SMOKE_LOOKBACK_MINUTES"] = "5",
["NOTIFY_SMOKE_NOTIFY_BASEURL"] = "https://notify.local",
["NOTIFY_SMOKE_NOTIFY_TOKEN"] = "token",
["NOTIFY_SMOKE_NOTIFY_TENANT"] = "tenant",
["NOTIFY_SMOKE_FIXED_TIME"] = "2025-01-02T03:04:05Z"
};
var options = NotifySmokeOptions.FromEnvironment(name => env.TryGetValue(name, out var value) ? value : null);
Assert.Equal(new DateTimeOffset(2025, 1, 2, 3, 4, 5, TimeSpan.Zero), options.TimeProvider.GetUtcNow());
}
[Fact]
public void ParseDeliveries_HandlesItemsArray()
{
var json = "{\"items\":[{\"kind\":\"scan\",\"status\":\"delivered\"},{\"kind\":\"vex\",\"status\":\"failed\"}]}";
var deliveries = NotifySmokeCheckRunner.ParseDeliveries(json);
Assert.Equal(2, deliveries.Count);
Assert.Equal("scan", deliveries[0].Kind, StringComparer.OrdinalIgnoreCase);
Assert.Equal("delivered", deliveries[0].Status, StringComparer.OrdinalIgnoreCase);
}
[Fact]
public void TryGetStreamTimestamp_ParsesEntryId()
{
var entry = new StreamEntry("1700000000000-0", Array.Empty<NameValueEntry>());
var success = NotifySmokeCheckRunner.TryGetStreamTimestamp(entry, out var timestamp);
Assert.True(success);
Assert.Equal(DateTimeOffset.FromUnixTimeMilliseconds(1700000000000), timestamp);
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\PolicyDslValidator\PolicyDslValidator.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,44 @@
using StellaOps.Policy;
using StellaOps.Policy.Tools;
public sealed class PolicyDslValidatorAppTests
{
[Fact]
public async Task RunAsync_ReturnsUsageExitCode_OnMissingInputs()
{
var runner = new CapturingRunner();
var exitCode = await PolicyDslValidatorApp.RunAsync(Array.Empty<string>(), runner);
Assert.Equal(64, exitCode);
Assert.False(runner.WasCalled);
}
[Fact]
public async Task Command_CapturesStrictAndJson()
{
var runner = new CapturingRunner();
var exitCode = await PolicyDslValidatorApp.RunAsync(new[] { "--strict", "--json", "policy.json" }, runner);
Assert.Equal(0, exitCode);
Assert.True(runner.WasCalled);
Assert.NotNull(runner.CapturedOptions);
Assert.True(runner.CapturedOptions!.Strict);
Assert.True(runner.CapturedOptions!.OutputJson);
Assert.Single(runner.CapturedOptions!.Inputs);
Assert.Equal("policy.json", runner.CapturedOptions!.Inputs[0]);
}
private sealed class CapturingRunner : IPolicyValidationRunner
{
public PolicyValidationCliOptions? CapturedOptions { get; private set; }
public bool WasCalled { get; private set; }
public Task<int> RunAsync(PolicyValidationCliOptions options, CancellationToken cancellationToken)
{
CapturedOptions = options;
WasCalled = true;
return Task.FromResult(0);
}
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\PolicySchemaExporter\PolicySchemaExporter.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,46 @@
using System.IO;
using StellaOps.Policy.Tools;
public sealed class PolicySchemaExporterTests
{
[Fact]
public void GenerateSchemas_IsStableAndHasExpectedNames()
{
var exports = PolicySchemaExporterSchema.BuildExports();
var first = PolicySchemaExporterSchema.GenerateSchemas(
PolicySchemaExporterSchema.CreateGenerator(),
exports);
var second = PolicySchemaExporterSchema.GenerateSchemas(
PolicySchemaExporterSchema.CreateGenerator(),
exports);
Assert.Equal(exports.Length, first.Count);
foreach (var export in exports)
{
Assert.True(first.ContainsKey(export.FileName));
Assert.True(second.ContainsKey(export.FileName));
Assert.Equal(first[export.FileName], second[export.FileName]);
}
}
[Fact]
public void ResolveOutputDirectory_UsesRepoRootForRelativeOutput()
{
var repoRoot = Path.Combine(Path.GetTempPath(), "schema-exporter");
var resolved = PolicySchemaExporterPaths.ResolveOutputDirectory("out", repoRoot);
var expected = Path.GetFullPath(Path.Combine(repoRoot, "out"));
Assert.Equal(expected, resolved);
}
[Fact]
public void ResolveDefaultOutputDirectory_UsesRepoRootDocsSchemas()
{
var repoRoot = Path.Combine(Path.GetTempPath(), "schema-exporter-root");
var resolved = PolicySchemaExporterPaths.ResolveDefaultOutputDirectory(repoRoot);
var expected = Path.GetFullPath(Path.Combine(repoRoot, "docs", "schemas"));
Assert.Equal(expected, resolved);
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\PolicySimulationSmoke\PolicySimulationSmoke.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,67 @@
using System.Collections.Immutable;
using StellaOps.Policy;
using StellaOps.Policy.Tools;
public sealed class PolicySimulationSmokeEvaluatorTests
{
[Fact]
public void EvaluateScenario_FailsWhenPreviewFails()
{
var scenario = new PolicySimulationScenario { Name = "demo" };
var response = new PolicyPreviewResponse(
Success: false,
PolicyDigest: "digest",
RevisionId: null,
Issues: ImmutableArray<PolicyIssue>.Empty,
Diffs: ImmutableArray<PolicyVerdictDiff>.Empty,
ChangedCount: 0);
var result = PolicySimulationSmokeEvaluator.EvaluateScenario(scenario, response);
Assert.False(result.Success);
Assert.Contains("Preview failed.", result.Failures);
}
[Fact]
public void EvaluateScenario_FailsWhenExpectedDiffMissing()
{
var scenario = new PolicySimulationScenario
{
Name = "demo",
ExpectedDiffs = new List<ScenarioExpectedDiff>
{
new ScenarioExpectedDiff { FindingId = "F-1", Status = "Blocked" }
}
};
var baseline = new PolicyVerdict("F-2", PolicyVerdictStatus.Pass);
var projected = new PolicyVerdict("F-2", PolicyVerdictStatus.Pass);
var diff = new PolicyVerdictDiff(baseline, projected);
var response = new PolicyPreviewResponse(
Success: true,
PolicyDigest: "digest",
RevisionId: null,
Issues: ImmutableArray<PolicyIssue>.Empty,
Diffs: ImmutableArray.Create(diff),
ChangedCount: 1);
var result = PolicySimulationSmokeEvaluator.EvaluateScenario(scenario, response);
Assert.False(result.Success);
Assert.Contains("Expected finding 'F-1' missing from diff.", result.Failures);
}
[Fact]
public async Task RunAsync_ReturnsNoInputWhenScenarioRootMissing()
{
var runner = new PolicySimulationSmokeRunner();
var missingRoot = Path.Combine(Path.GetTempPath(), "stellaops-missing-" + Guid.NewGuid().ToString("N"));
var exitCode = await runner.RunAsync(
new PolicySimulationSmokeOptions { ScenarioRoot = missingRoot },
CancellationToken.None);
Assert.Equal(66, exitCode);
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\RustFsMigrator\RustFsMigrator.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,42 @@
using System;
using Xunit;
public sealed class RustFsMigratorTests
{
[Fact]
public void Parse_ExtractsRetryAndTimeoutOptions()
{
var options = MigrationOptions.Parse(new[]
{
"--s3-bucket", "bucket",
"--rustfs-endpoint", "http://rustfs:8080",
"--rustfs-bucket", "target",
"--retry-attempts", "5",
"--retry-delay-ms", "500",
"--timeout-seconds", "60",
"--retain-days", "1.5"
});
Assert.NotNull(options);
Assert.Equal(5, options!.RetryAttempts);
Assert.Equal(500, options.RetryDelayMs);
Assert.Equal(60, options.TimeoutSeconds);
Assert.NotNull(options.RetentionSeconds);
Assert.True(options.RetentionSeconds > 0);
}
[Fact]
public void BuildRustFsUri_EncodesObjectKey()
{
var options = new MigrationOptions
{
RustFsEndpoint = "https://rustfs.local",
RustFsBucket = "scanner artifacts"
};
var uri = RustFsMigratorPaths.BuildRustFsUri(options, "path/with space/file.txt");
Assert.Equal("https", uri.Scheme);
Assert.Contains("scanner%20artifacts", uri.AbsoluteUri, StringComparison.Ordinal);
Assert.Contains("path/with%20space/file.txt", uri.AbsoluteUri, StringComparison.Ordinal);
}
}