up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-28 00:45:16 +02:00
parent 3b96b2e3ea
commit 1c6730a1d2
95 changed files with 14504 additions and 463 deletions

View File

@@ -55,6 +55,10 @@ internal sealed record RuntimePolicyImageResult
[JsonPropertyName("rekor")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public RuntimePolicyRekorResult? Rekor { get; init; }
[JsonPropertyName("manifestDigest")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ManifestDigest { get; init; }
}
internal sealed record RuntimePolicyRekorResult

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Globalization;
using System.Linq;
using System.Threading;
@@ -10,13 +11,20 @@ using StellaOps.Zastava.Core.Contracts;
using StellaOps.Zastava.Observer.Backend;
using StellaOps.Zastava.Observer.Configuration;
using StellaOps.Zastava.Observer.ContainerRuntime.Cri;
using StellaOps.Zastava.Observer.Surface;
namespace StellaOps.Zastava.Observer.Posture;
internal sealed class RuntimePostureEvaluator : IRuntimePostureEvaluator
{
private static readonly Meter Meter = new("StellaOps.Zastava.Observer", "1.0.0");
private static readonly Counter<long> ManifestFailuresCounter = Meter.CreateCounter<long>(
"zastava_surface_manifest_failures_total",
description: "Count of Surface manifest fetch failures");
private readonly IRuntimePolicyClient policyClient;
private readonly IRuntimePostureCache cache;
private readonly IRuntimeSurfaceFsClient surfaceFsClient;
private readonly IOptionsMonitor<ZastavaObserverOptions> optionsMonitor;
private readonly TimeProvider timeProvider;
private readonly ILogger<RuntimePostureEvaluator> logger;
@@ -24,12 +32,14 @@ internal sealed class RuntimePostureEvaluator : IRuntimePostureEvaluator
public RuntimePostureEvaluator(
IRuntimePolicyClient policyClient,
IRuntimePostureCache cache,
IRuntimeSurfaceFsClient surfaceFsClient,
IOptionsMonitor<ZastavaObserverOptions> optionsMonitor,
TimeProvider timeProvider,
ILogger<RuntimePostureEvaluator> logger)
{
this.policyClient = policyClient ?? throw new ArgumentNullException(nameof(policyClient));
this.cache = cache ?? throw new ArgumentNullException(nameof(cache));
this.surfaceFsClient = surfaceFsClient ?? throw new ArgumentNullException(nameof(surfaceFsClient));
this.optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor));
this.timeProvider = timeProvider ?? TimeProvider.System;
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -100,6 +110,8 @@ internal sealed class RuntimePostureEvaluator : IRuntimePostureEvaluator
Value = expiresAt.ToString("O", CultureInfo.InvariantCulture)
});
await EnrichWithManifestAsync(imageResult.ManifestDigest, evidence, cancellationToken).ConfigureAwait(false);
return new RuntimePostureEvaluationResult(posture, evidence);
}
catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
@@ -185,4 +197,86 @@ internal sealed class RuntimePostureEvaluator : IRuntimePostureEvaluator
return posture;
}
private async Task EnrichWithManifestAsync(string? manifestDigest, List<RuntimeEvidence> evidence, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(manifestDigest))
{
return;
}
try
{
var manifest = await surfaceFsClient.TryGetManifestAsync(manifestDigest, cancellationToken).ConfigureAwait(false);
if (manifest is null)
{
ManifestFailuresCounter.Add(1, new KeyValuePair<string, object?>("reason", "not_found"));
evidence.Add(new RuntimeEvidence
{
Signal = "runtime.surface.manifest",
Value = "not_found"
});
logger.LogDebug("Surface manifest {ManifestDigest} not found in local cache.", manifestDigest);
return;
}
evidence.Add(new RuntimeEvidence
{
Signal = "runtime.surface.manifest",
Value = "resolved"
});
evidence.Add(new RuntimeEvidence
{
Signal = "runtime.surface.manifestDigest",
Value = manifestDigest
});
if (!string.IsNullOrWhiteSpace(manifest.ImageDigest))
{
evidence.Add(new RuntimeEvidence
{
Signal = "runtime.surface.imageDigest",
Value = manifest.ImageDigest
});
}
foreach (var artifact in manifest.Artifacts)
{
var artifactKind = artifact.Kind;
if (string.IsNullOrWhiteSpace(artifactKind))
{
continue;
}
evidence.Add(new RuntimeEvidence
{
Signal = $"runtime.surface.artifact.{artifactKind}",
Value = artifact.Digest
});
if (artifact.Metadata is not null && artifact.Metadata.Count > 0)
{
foreach (var kvp in artifact.Metadata.Take(5))
{
evidence.Add(new RuntimeEvidence
{
Signal = $"runtime.surface.artifact.{artifactKind}.{kvp.Key}",
Value = kvp.Value
});
}
}
}
}
catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
{
ManifestFailuresCounter.Add(1, new KeyValuePair<string, object?>("reason", "fetch_error"));
evidence.Add(new RuntimeEvidence
{
Signal = "runtime.surface.manifest",
Value = "fetch_error"
});
logger.LogWarning(ex, "Failed to fetch Surface manifest {ManifestDigest}.", manifestDigest);
}
}
}