consolidation of some of the modules, localization fixes, product advisories work, qa work

This commit is contained in:
master
2026-03-05 03:54:22 +02:00
parent 7bafcc3eef
commit 8e1cb9448d
3878 changed files with 72600 additions and 46861 deletions

View File

@@ -0,0 +1,138 @@
using StellaOps.Provenance.Attestation;
using System.Globalization;
using System.Text.Json;
return await ToolEntrypoint.RunAsync(args, Console.Out, Console.Error, TimeProvider.System);
internal static class ToolEntrypoint
{
private const int ExitInvalid = 1;
private const int ExitUnverified = 2;
public static async Task<int> RunAsync(string[] args, TextWriter stdout, TextWriter stderr, TimeProvider timeProvider)
{
var options = Parse(args);
if (!options.Valid)
{
return Usage(stderr);
}
byte[] payload;
try
{
payload = options.PayloadPath == "-"
? await ReadAllAsync(Console.OpenStandardInput())
: await File.ReadAllBytesAsync(options.PayloadPath!);
}
catch (Exception ex)
{
await stderr.WriteLineAsync($"read error: {ex.Message}");
return ExitInvalid;
}
byte[] signature;
byte[] key;
try
{
signature = Hex.FromHex(options.SignatureHex!);
key = Hex.FromHex(options.KeyHex!);
}
catch (Exception ex)
{
await stderr.WriteLineAsync($"hex parse error: {ex.Message}");
return ExitInvalid;
}
var signRequest = new SignRequest(payload, options.ContentType!, RequiredClaims: new[] { "predicateType" });
var signResult = new SignResult(signature, options.KeyId!, options.SignedAt ?? DateTimeOffset.MinValue, null);
var verifier = new HmacVerifier(new InMemoryKeyProvider(options.KeyId!, key, options.NotAfter), timeProvider, options.MaxSkew);
var verifyResult = await verifier.VerifyAsync(signRequest, signResult);
var json = JsonSerializer.Serialize(new
{
valid = verifyResult.IsValid,
reason = verifyResult.Reason,
verifiedAt = verifyResult.VerifiedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture),
keyId = options.KeyId,
contentType = options.ContentType
}, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = false });
await stdout.WriteLineAsync(json);
return verifyResult.IsValid ? 0 : ExitUnverified;
}
private static async Task<byte[]> ReadAllAsync(Stream stream)
{
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
return ms.ToArray();
}
private static int Usage(TextWriter stderr)
{
stderr.WriteLine("Usage: stella-forensic-verify --payload <file|-> --signature-hex <hex> --key-hex <hex> [--key-id <id>] [--content-type <ct>] [--signed-at <ISO>] [--not-after <ISO>] [--max-skew-minutes <int>]");
stderr.WriteLine("Exit codes: 0 valid, 2 invalid signature/time, 1 bad args");
return ExitInvalid;
}
private static ParsedOptions Parse(string[] args)
{
string? GetArg(string name)
{
for (int i = 0; i < args.Length - 1; i++)
{
if (args[i].Equals(name, StringComparison.OrdinalIgnoreCase))
return args[i + 1];
}
return null;
}
var payload = GetArg("--payload");
var sig = GetArg("--signature-hex");
var key = GetArg("--key-hex");
if (payload is null || sig is null || key is null)
{
return ParsedOptions.Invalid;
}
DateTimeOffset? ParseDate(string? value)
{
if (string.IsNullOrWhiteSpace(value)) return null;
return DateTimeOffset.Parse(value!, null, System.Globalization.DateTimeStyles.RoundtripKind);
}
TimeSpan ParseSkew(string? value)
{
if (string.IsNullOrWhiteSpace(value)) return TimeSpan.FromMinutes(5);
return TimeSpan.FromMinutes(double.Parse(value!, System.Globalization.CultureInfo.InvariantCulture));
}
return new ParsedOptions(
Valid: true,
PayloadPath: payload,
SignatureHex: sig,
KeyHex: key,
KeyId: GetArg("--key-id") ?? "hmac",
ContentType: GetArg("--content-type") ?? "application/octet-stream",
SignedAt: ParseDate(GetArg("--signed-at")),
NotAfter: ParseDate(GetArg("--not-after")),
MaxSkew: ParseSkew(GetArg("--max-skew-minutes"))
);
}
private sealed record ParsedOptions(
bool Valid,
string? PayloadPath = null,
string? SignatureHex = null,
string? KeyHex = null,
string? KeyId = null,
string? ContentType = null,
DateTimeOffset? SignedAt = null,
DateTimeOffset? NotAfter = null,
TimeSpan MaxSkew = default)
{
public static readonly ParsedOptions Invalid = new(false);
}
}

View File

@@ -0,0 +1,34 @@
# stella-forensic-verify (preview)
Minimal .NET 10 global tool for offline verification of provenance payloads signed with an HMAC key. No network access; deterministic JSON output.
## Usage
```
stella-forensic-verify \
--payload payload.bin # or '-' to read stdin
--signature-hex DEADBEEF... # hex-encoded HMAC
--key-hex 001122... # hex-encoded HMAC key
[--key-id hmac] # optional key id
[--content-type application/octet-stream]
[--signed-at 2025-11-21T12:00:00Z]
[--not-after 2025-12-31T23:59:59Z]
[--max-skew-minutes 5]
```
Output (single line, deterministic field order):
```
{"valid":true,"reason":"verified","verifiedAt":"2025-11-22T12:00:00.0000000Z","keyId":"hmac","contentType":"application/octet-stream"}
```
## Exit codes
- 0: signature valid
- 2: signature/time invalid
- 1: bad arguments or hex parse failure
## Offline kit packaging (manual)
1. `dotnet pack src/Provenance/StellaOps.Provenance.Attestation.Tool/StellaOps.Provenance.Attestation.Tool.csproj -c Release -o out/tools`
2. Copy the produced nupkg into the offline kit under `tools/`.
3. Install in air-gap host: `dotnet tool install --global --add-source tools stella-forensic-verify --version <pkg-version>`.
4. Document expected SHA256 of the nupkg alongside the kit manifest.

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Exe</OutputType>
<PackAsTool>true</PackAsTool>
<ToolCommandName>stella-forensic-verify</ToolCommandName>
<PackageOutputPath>../../out/tools</PackageOutputPath>
<!-- Clear restore sources to use only explicit feeds (from deleted Directory.Build.props) -->
<RestoreSources>;;</RestoreSources>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="StellaOps.Provenance.Attestation.Tests" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../StellaOps.Provenance.Attestation/StellaOps.Provenance.Attestation.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,8 @@
# StellaOps.Provenance.Attestation.Tool Task Board
This board mirrors active sprint tasks for this module.
Source of truth: `docs/implplan/SPRINT_20260130_002_Tools_csproj_remediation_solid_review.md`.
| Task ID | Status | Notes |
| --- | --- | --- |
| REMED-05 | TODO | Remediation checklist: docs/implplan/audits/csproj-standards/remediation/checklists/src/Provenance/StellaOps.Provenance.Attestation.Tool/StellaOps.Provenance.Attestation.Tool.md. |
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |

View File

@@ -0,0 +1 @@
test