namespace StellaOps.AuditPack.Services; public sealed partial class AuditBundleReader { private static async Task LoadReplayInputsAsync( string bundleDir, CancellationToken ct) { var sbom = await ReadRequiredFileAsync(bundleDir, "sbom.json", "SBOM", ct).ConfigureAwait(false); var feeds = await ReadRequiredFileAsync(bundleDir, "feeds/feeds-snapshot.ndjson", "feeds", ct).ConfigureAwait(false); var policy = await ReadRequiredFileAsync(bundleDir, "policy/policy-bundle.tar.gz", "policy", ct).ConfigureAwait(false); var verdict = await ReadRequiredFileAsync(bundleDir, "verdict.json", "verdict", ct).ConfigureAwait(false); var vex = await ReadOptionalFileAsync(bundleDir, "vex/vex-statements.json", ct).ConfigureAwait(false); var proof = await ReadOptionalFileAsync(bundleDir, "proof/proof-bundle.json", ct).ConfigureAwait(false); var trustRoots = await ReadOptionalFileAsync(bundleDir, "trust/trust-roots.json", ct).ConfigureAwait(false); var scoring = await ReadOptionalFileAsync(bundleDir, "scoring-rules.json", ct).ConfigureAwait(false); var timeAnchor = await ReadOptionalFileAsync(bundleDir, "time-anchor.json", ct).ConfigureAwait(false); return new ReplayInputs { Sbom = sbom, FeedsSnapshot = feeds, PolicyBundle = policy, VexStatements = vex, Verdict = verdict, ProofBundle = proof, TrustRoots = trustRoots, ScoringRules = scoring, TimeAnchor = timeAnchor }; } private static async Task ReadRequiredFileAsync( string bundleDir, string relativePath, string label, CancellationToken ct) { var filePath = GetBundlePath(bundleDir, relativePath); if (!File.Exists(filePath)) { throw new FileNotFoundException($"{label} file not found", filePath); } return await File.ReadAllBytesAsync(filePath, ct).ConfigureAwait(false); } private static async Task ReadOptionalFileAsync( string bundleDir, string relativePath, CancellationToken ct) { var filePath = GetBundlePath(bundleDir, relativePath); if (!File.Exists(filePath)) { return null; } return await File.ReadAllBytesAsync(filePath, ct).ConfigureAwait(false); } }