work work hard work

This commit is contained in:
StellaOps Bot
2025-12-18 00:47:24 +02:00
parent dee252940b
commit b4235c134c
189 changed files with 9627 additions and 3258 deletions

View File

@@ -286,6 +286,8 @@ internal static partial class CommandHandlers
}
}
var dssePath = (verifyDsse || verifyRekor) ? ResolveOfflineDssePath(bundleDir) : null;
var dsseVerified = false;
if (verifyDsse)
{
@@ -304,7 +306,6 @@ internal static partial class CommandHandlers
return;
}
var dssePath = ResolveOfflineDssePath(bundleDir);
if (dssePath is null)
{
verificationLog.Add("dsse:missing");
@@ -507,6 +508,44 @@ internal static partial class CommandHandlers
var rekorVerified = false;
if (verifyRekor)
{
if (dssePath is null)
{
verificationLog.Add("rekor:missing-dsse");
var quarantineId = await TryQuarantineOfflineBundleAsync(
loggerFactory,
quarantineRoot,
effectiveTenant,
bundlePath,
manifestJson,
reasonCode: "REKOR_VERIFY_FAIL",
reasonMessage: "Rekor verification requires a DSSE statement file (statement.dsse.json).",
verificationLog,
cancellationToken).ConfigureAwait(false);
await WriteOfflineImportResultAsync(
emitJson,
new OfflineImportResultPayload(
Status: "failed",
ExitCode: OfflineExitCodes.RekorVerificationFailed,
TenantId: effectiveTenant,
BundlePath: bundlePath,
ManifestPath: manifestPath,
Version: manifest.Version,
Digest: $"sha256:{bundleDigest}",
DsseVerified: dsseVerified,
RekorVerified: false,
ActivatedAt: null,
WasForceActivated: false,
ForceActivateReason: null,
QuarantineId: quarantineId,
ReasonCode: "REKOR_VERIFY_FAIL",
ReasonMessage: "Rekor verification requires a DSSE statement file (statement.dsse.json)."),
cancellationToken).ConfigureAwait(false);
Environment.ExitCode = OfflineExitCodes.RekorVerificationFailed;
return;
}
var rekorPath = ResolveOfflineRekorReceiptPath(bundleDir);
if (rekorPath is null)
{
@@ -546,20 +585,10 @@ internal static partial class CommandHandlers
return;
}
var receiptJson = await File.ReadAllTextAsync(rekorPath, cancellationToken).ConfigureAwait(false);
var receipt = JsonSerializer.Deserialize<OfflineKitRekorReceiptDocument>(receiptJson, new JsonSerializerOptions(JsonSerializerDefaults.Web)
var rekorKeyPath = ResolveOfflineRekorPublicKeyPath(bundleDir);
if (rekorKeyPath is null)
{
PropertyNameCaseInsensitive = true
});
if (receipt is null ||
string.IsNullOrWhiteSpace(receipt.Uuid) ||
receipt.LogIndex < 0 ||
string.IsNullOrWhiteSpace(receipt.RootHash) ||
receipt.Hashes is not { Count: > 0 } ||
string.IsNullOrWhiteSpace(receipt.Checkpoint))
{
verificationLog.Add("rekor:invalid");
verificationLog.Add("rekor:missing-public-key");
var quarantineId = await TryQuarantineOfflineBundleAsync(
loggerFactory,
quarantineRoot,
@@ -567,7 +596,7 @@ internal static partial class CommandHandlers
bundlePath,
manifestJson,
reasonCode: "REKOR_VERIFY_FAIL",
reasonMessage: "Rekor receipt is missing required fields.",
reasonMessage: "Rekor public key not found in offline bundle (rekor-pub.pem).",
verificationLog,
cancellationToken).ConfigureAwait(false);
@@ -588,16 +617,26 @@ internal static partial class CommandHandlers
ForceActivateReason: null,
QuarantineId: quarantineId,
ReasonCode: "REKOR_VERIFY_FAIL",
ReasonMessage: "Rekor receipt is missing required fields."),
ReasonMessage: "Rekor public key not found in offline bundle (rekor-pub.pem)."),
cancellationToken).ConfigureAwait(false);
Environment.ExitCode = OfflineExitCodes.RekorVerificationFailed;
return;
}
if (receipt.Checkpoint.IndexOf(receipt.RootHash, StringComparison.OrdinalIgnoreCase) < 0)
var dsseBytes = await File.ReadAllBytesAsync(dssePath, cancellationToken).ConfigureAwait(false);
var dsseSha256 = SHA256.HashData(dsseBytes);
var verify = await RekorOfflineReceiptVerifier.VerifyAsync(
rekorPath,
dsseSha256,
rekorKeyPath,
cancellationToken)
.ConfigureAwait(false);
if (!verify.Verified)
{
verificationLog.Add("rekor:checkpoint-mismatch");
verificationLog.Add("rekor:verify-failed");
var quarantineId = await TryQuarantineOfflineBundleAsync(
loggerFactory,
quarantineRoot,
@@ -605,7 +644,7 @@ internal static partial class CommandHandlers
bundlePath,
manifestJson,
reasonCode: "REKOR_VERIFY_FAIL",
reasonMessage: "Rekor checkpoint does not reference receipt rootHash.",
reasonMessage: verify.FailureReason ?? "Rekor verification failed.",
verificationLog,
cancellationToken).ConfigureAwait(false);
@@ -626,7 +665,7 @@ internal static partial class CommandHandlers
ForceActivateReason: null,
QuarantineId: quarantineId,
ReasonCode: "REKOR_VERIFY_FAIL",
ReasonMessage: "Rekor checkpoint does not reference receipt rootHash."),
ReasonMessage: verify.FailureReason ?? "Rekor verification failed."),
cancellationToken).ConfigureAwait(false);
Environment.ExitCode = OfflineExitCodes.RekorVerificationFailed;
@@ -635,8 +674,15 @@ internal static partial class CommandHandlers
rekorVerified = true;
verificationLog.Add("rekor:ok");
activity?.SetTag("stellaops.cli.offline.rekor_uuid", receipt.Uuid);
activity?.SetTag("stellaops.cli.offline.rekor_log_index", receipt.LogIndex);
if (!string.IsNullOrWhiteSpace(verify.RekorUuid))
{
activity?.SetTag("stellaops.cli.offline.rekor_uuid", verify.RekorUuid);
}
if (verify.LogIndex is not null)
{
activity?.SetTag("stellaops.cli.offline.rekor_log_index", verify.LogIndex.Value);
}
}
BundleVersion incomingVersion;
@@ -947,6 +993,25 @@ internal static partial class CommandHandlers
return candidates.FirstOrDefault(File.Exists);
}
private static string? ResolveOfflineRekorPublicKeyPath(string bundleDirectory)
{
var candidates = new[]
{
Path.Combine(bundleDirectory, "rekor-pub.pem"),
Path.Combine(bundleDirectory, "rekor.pub"),
Path.Combine(bundleDirectory, "tlog-root.pub"),
Path.Combine(bundleDirectory, "tlog-root.pem"),
Path.Combine(bundleDirectory, "tlog", "rekor-pub.pem"),
Path.Combine(bundleDirectory, "tlog", "rekor.pub"),
Path.Combine(bundleDirectory, "keys", "tlog-root", "rekor-pub.pem"),
Path.Combine(bundleDirectory, "keys", "tlog-root", "rekor.pub"),
Path.Combine(bundleDirectory, "evidence", "keys", "tlog-root", "rekor-pub.pem"),
Path.Combine(bundleDirectory, "evidence", "keys", "tlog-root", "rekor.pub"),
};
return candidates.FirstOrDefault(File.Exists);
}
private static async Task<byte[]> LoadTrustRootPublicKeyAsync(string path, CancellationToken cancellationToken)
{
var bytes = await File.ReadAllBytesAsync(path, cancellationToken).ConfigureAwait(false);