feat: Add DigestUpsertRequest and LockEntity models
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
Export Center CI / export-ci (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
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
Export Center CI / export-ci (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
- Introduced DigestUpsertRequest for handling digest upsert requests with properties like ChannelId, Recipient, DigestKey, Events, and CollectUntil. - Created LockEntity to represent a lightweight distributed lock entry with properties such as Id, TenantId, Resource, Owner, ExpiresAt, and CreatedAt. feat: Implement ILockRepository interface and LockRepository class - Defined ILockRepository interface with methods for acquiring and releasing locks. - Implemented LockRepository class with methods to try acquiring a lock and releasing it, using SQL for upsert operations. feat: Add SurfaceManifestPointer record for manifest pointers - Introduced SurfaceManifestPointer to represent a minimal pointer to a Surface.FS manifest associated with an image digest. feat: Create PolicySimulationInputLock and related validation logic - Added PolicySimulationInputLock record to describe policy simulation inputs and expected digests. - Implemented validation logic for policy simulation inputs, including checks for digest drift and shadow mode requirements. test: Add unit tests for ReplayVerificationService and ReplayVerifier - Created ReplayVerificationServiceTests to validate the behavior of the ReplayVerificationService under various scenarios. - Developed ReplayVerifierTests to ensure the correctness of the ReplayVerifier logic. test: Implement PolicySimulationInputLockValidatorTests - Added tests for PolicySimulationInputLockValidator to verify the validation logic against expected inputs and conditions. chore: Add cosign key example and signing scripts - Included a placeholder cosign key example for development purposes. - Added a script for signing Signals artifacts using cosign with support for both v2 and v3. chore: Create script for uploading evidence to the evidence locker - Developed a script to upload evidence to the evidence locker, ensuring required environment variables are set.
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Scheduler.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Scheduler.Models;
|
||||
using StellaOps.Scheduler.Worker.Planning;
|
||||
|
||||
namespace StellaOps.Scheduler.Queue;
|
||||
|
||||
@@ -49,10 +50,11 @@ public sealed class PlannerQueueMessage
|
||||
public string? ScheduleId => Run.ScheduleId;
|
||||
}
|
||||
|
||||
public sealed class RunnerSegmentQueueMessage
|
||||
{
|
||||
private readonly ReadOnlyCollection<string> _imageDigests;
|
||||
private readonly IReadOnlyDictionary<string, string> _attributes;
|
||||
public sealed class RunnerSegmentQueueMessage
|
||||
{
|
||||
private readonly ReadOnlyCollection<string> _imageDigests;
|
||||
private readonly IReadOnlyDictionary<string, string> _attributes;
|
||||
private readonly IReadOnlyDictionary<string, SurfaceManifestPointer> _surfaceManifests;
|
||||
|
||||
[JsonConstructor]
|
||||
public RunnerSegmentQueueMessage(
|
||||
@@ -60,12 +62,13 @@ public sealed class RunnerSegmentQueueMessage
|
||||
string runId,
|
||||
string tenantId,
|
||||
IReadOnlyList<string> imageDigests,
|
||||
string? scheduleId = null,
|
||||
int? ratePerSecond = null,
|
||||
bool usageOnly = true,
|
||||
IReadOnlyDictionary<string, string>? attributes = null,
|
||||
string? correlationId = null)
|
||||
{
|
||||
string? scheduleId = null,
|
||||
int? ratePerSecond = null,
|
||||
bool usageOnly = true,
|
||||
IReadOnlyDictionary<string, string>? attributes = null,
|
||||
string? correlationId = null,
|
||||
IReadOnlyDictionary<string, SurfaceManifestPointer>? surfaceManifests = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(segmentId))
|
||||
{
|
||||
throw new ArgumentException("Segment identifier must be provided.", nameof(segmentId));
|
||||
@@ -86,14 +89,17 @@ public sealed class RunnerSegmentQueueMessage
|
||||
TenantId = tenantId;
|
||||
ScheduleId = string.IsNullOrWhiteSpace(scheduleId) ? null : scheduleId;
|
||||
RatePerSecond = ratePerSecond;
|
||||
UsageOnly = usageOnly;
|
||||
CorrelationId = string.IsNullOrWhiteSpace(correlationId) ? null : correlationId;
|
||||
|
||||
_imageDigests = new ReadOnlyCollection<string>(NormalizeDigests(imageDigests));
|
||||
_attributes = attributes is null
|
||||
? EmptyReadOnlyDictionary<string, string>.Instance
|
||||
: new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(attributes, StringComparer.Ordinal));
|
||||
}
|
||||
UsageOnly = usageOnly;
|
||||
CorrelationId = string.IsNullOrWhiteSpace(correlationId) ? null : correlationId;
|
||||
|
||||
_imageDigests = new ReadOnlyCollection<string>(NormalizeDigests(imageDigests));
|
||||
_attributes = attributes is null
|
||||
? EmptyReadOnlyDictionary<string, string>.Instance
|
||||
: new ReadOnlyDictionary<string, string>(new Dictionary<string, string>(attributes, StringComparer.Ordinal));
|
||||
_surfaceManifests = surfaceManifests is null
|
||||
? EmptyReadOnlyDictionary<string, SurfaceManifestPointer>.Instance
|
||||
: new ReadOnlyDictionary<string, SurfaceManifestPointer>(new Dictionary<string, SurfaceManifestPointer>(surfaceManifests, StringComparer.Ordinal));
|
||||
}
|
||||
|
||||
public string SegmentId { get; }
|
||||
|
||||
@@ -111,7 +117,10 @@ public sealed class RunnerSegmentQueueMessage
|
||||
|
||||
public IReadOnlyList<string> ImageDigests => _imageDigests;
|
||||
|
||||
public IReadOnlyDictionary<string, string> Attributes => _attributes;
|
||||
public IReadOnlyDictionary<string, string> Attributes => _attributes;
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public IReadOnlyDictionary<string, SurfaceManifestPointer> SurfaceManifests => _surfaceManifests;
|
||||
|
||||
public string IdempotencyKey => SegmentId;
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Notify.Queue;
|
||||
using StellaOps.Scheduler.Worker.Events;
|
||||
using StellaOps.Scheduler.Worker.Execution;
|
||||
using StellaOps.Scheduler.Worker.Options;
|
||||
using StellaOps.Scheduler.Worker.Observability;
|
||||
using StellaOps.Scheduler.Worker.Planning;
|
||||
using StellaOps.Scheduler.Worker.Policy;
|
||||
using StellaOps.Scheduler.Worker.Graph;
|
||||
using StellaOps.Scheduler.Worker.Graph.Cartographer;
|
||||
using StellaOps.Scheduler.Worker.Graph.Scheduler;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Notify.Queue;
|
||||
using StellaOps.Scheduler.Worker.Events;
|
||||
using StellaOps.Scheduler.Worker.Execution;
|
||||
using StellaOps.Scheduler.Worker.Options;
|
||||
using StellaOps.Scheduler.Worker.Observability;
|
||||
using StellaOps.Scheduler.Worker.Planning;
|
||||
using StellaOps.Scheduler.Worker.Policy;
|
||||
using StellaOps.Scheduler.Worker.Graph;
|
||||
using StellaOps.Scheduler.Worker.Graph.Cartographer;
|
||||
using StellaOps.Scheduler.Worker.Graph.Scheduler;
|
||||
using StellaOps.Scanner.Surface.Env;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
|
||||
namespace StellaOps.Scheduler.Worker.DependencyInjection;
|
||||
|
||||
@@ -30,10 +32,10 @@ public static class SchedulerWorkerServiceCollectionExtensions
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<SchedulerWorkerMetrics>();
|
||||
services.AddSingleton<IImpactTargetingService, ImpactTargetingService>();
|
||||
services.AddSingleton<IImpactShardPlanner, ImpactShardPlanner>();
|
||||
services.AddSingleton<IPlannerQueueDispatchService, PlannerQueueDispatchService>();
|
||||
services.AddSingleton<PlannerExecutionService>();
|
||||
services.AddSingleton<IRunnerExecutionService, RunnerExecutionService>();
|
||||
services.AddSingleton<IImpactShardPlanner, ImpactShardPlanner>();
|
||||
services.AddSingleton<IPlannerQueueDispatchService, PlannerQueueDispatchService>();
|
||||
services.AddSingleton<PlannerExecutionService>();
|
||||
services.AddSingleton<IRunnerExecutionService, RunnerExecutionService>();
|
||||
services.AddSingleton<IPolicyRunTargetingService, PolicyRunTargetingService>();
|
||||
services.AddSingleton<PolicyRunExecutionService>();
|
||||
services.AddSingleton<GraphBuildExecutionService>();
|
||||
@@ -80,10 +82,10 @@ public static class SchedulerWorkerServiceCollectionExtensions
|
||||
client.BaseAddress = baseAddress;
|
||||
}
|
||||
});
|
||||
services.AddHttpClient<IGraphJobCompletionClient, HttpGraphJobCompletionClient>((sp, client) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<SchedulerWorkerOptions>>().Value.Graph;
|
||||
client.Timeout = options.CartographerTimeout;
|
||||
services.AddHttpClient<IGraphJobCompletionClient, HttpGraphJobCompletionClient>((sp, client) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<SchedulerWorkerOptions>>().Value.Graph;
|
||||
client.Timeout = options.CartographerTimeout;
|
||||
|
||||
if (options.SchedulerApi.BaseAddress is { } baseAddress)
|
||||
{
|
||||
@@ -91,13 +93,17 @@ public static class SchedulerWorkerServiceCollectionExtensions
|
||||
}
|
||||
});
|
||||
|
||||
services.AddHostedService<PlannerBackgroundService>();
|
||||
services.AddHostedService<PlannerQueueDispatcherBackgroundService>();
|
||||
services.AddHostedService<RunnerBackgroundService>();
|
||||
services.AddHostedService<PolicyRunDispatchBackgroundService>();
|
||||
services.AddHostedService<GraphBuildBackgroundService>();
|
||||
services.AddHostedService<GraphOverlayBackgroundService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
services.AddHostedService<PlannerBackgroundService>();
|
||||
services.AddHostedService<PlannerQueueDispatcherBackgroundService>();
|
||||
services.AddHostedService<RunnerBackgroundService>();
|
||||
services.AddHostedService<PolicyRunDispatchBackgroundService>();
|
||||
services.AddHostedService<GraphBuildBackgroundService>();
|
||||
services.AddHostedService<GraphOverlayBackgroundService>();
|
||||
|
||||
services.AddSurfaceEnvironment(options => { options.ComponentName = "Scheduler.Worker"; });
|
||||
services.AddSurfaceFileCache();
|
||||
services.AddSurfaceManifestStore();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public sealed class SchedulerWorkerMetrics : IDisposable
|
||||
private readonly Counter<long> _runnerDeltaHighTotal;
|
||||
private readonly Counter<long> _runnerDeltaFindingsTotal;
|
||||
private readonly Counter<long> _runnerKevHitsTotal;
|
||||
private readonly Counter<long> _surfaceManifestPrefetchTotal;
|
||||
private readonly Counter<long> _surfaceManifestPrefetchTotal;
|
||||
private readonly Histogram<double> _runDurationSeconds;
|
||||
private readonly UpDownCounter<long> _runsActive;
|
||||
private readonly Counter<long> _graphJobsTotal;
|
||||
@@ -65,6 +67,14 @@ public sealed class SchedulerWorkerMetrics : IDisposable
|
||||
"scheduler_runner_delta_kev_total",
|
||||
unit: "count",
|
||||
description: "KEV hits observed by runner grouped by mode.");
|
||||
_surfaceManifestPrefetchTotal = _meter.CreateCounter<long>(
|
||||
"scheduler_surface_manifest_prefetch_total",
|
||||
unit: "attempt",
|
||||
description: "Surface manifest prefetch attempts grouped by result.");
|
||||
_surfaceManifestPrefetchTotal = _meter.CreateCounter<long>(
|
||||
"scheduler_surface_manifest_prefetch_total",
|
||||
unit: "attempt",
|
||||
description: "Surface manifest prefetch attempts grouped by result.");
|
||||
_runDurationSeconds = _meter.CreateHistogram<double>(
|
||||
"scheduler_run_duration_seconds",
|
||||
unit: "s",
|
||||
@@ -172,6 +182,12 @@ public sealed class SchedulerWorkerMetrics : IDisposable
|
||||
_runnerImagesTotal.Add(processedImages, imageTags);
|
||||
}
|
||||
|
||||
public void RecordSurfaceManifestPrefetch(string result)
|
||||
{
|
||||
var tags = new[] { new KeyValuePair<string, object?>("result", result) };
|
||||
_surfaceManifestPrefetchTotal.Add(1, tags);
|
||||
}
|
||||
|
||||
public void RecordDeltaSummaries(string mode, IReadOnlyList<DeltaSummary> deltas)
|
||||
{
|
||||
if (deltas.Count == 0)
|
||||
|
||||
@@ -4,7 +4,9 @@ using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Scheduler.Models;
|
||||
using StellaOps.Scheduler.Queue;
|
||||
using StellaOps.Scanner.Surface.FS;
|
||||
using StellaOps.Scheduler.Worker.Options;
|
||||
using StellaOps.Scheduler.Worker.Observability;
|
||||
|
||||
namespace StellaOps.Scheduler.Worker.Planning;
|
||||
|
||||
@@ -18,17 +20,23 @@ internal sealed class PlannerQueueDispatchService : IPlannerQueueDispatchService
|
||||
private readonly IImpactShardPlanner _shardPlanner;
|
||||
private readonly ISchedulerRunnerQueue _runnerQueue;
|
||||
private readonly SchedulerWorkerOptions _options;
|
||||
private readonly ISurfaceManifestReader _surfaceManifestReader;
|
||||
private readonly SchedulerWorkerMetrics _metrics;
|
||||
private readonly ILogger<PlannerQueueDispatchService> _logger;
|
||||
|
||||
public PlannerQueueDispatchService(
|
||||
IImpactShardPlanner shardPlanner,
|
||||
ISchedulerRunnerQueue runnerQueue,
|
||||
SchedulerWorkerOptions options,
|
||||
ISurfaceManifestReader surfaceManifestReader,
|
||||
SchedulerWorkerMetrics metrics,
|
||||
ILogger<PlannerQueueDispatchService> logger)
|
||||
{
|
||||
_shardPlanner = shardPlanner ?? throw new ArgumentNullException(nameof(shardPlanner));
|
||||
_runnerQueue = runnerQueue ?? throw new ArgumentNullException(nameof(runnerQueue));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
_surfaceManifestReader = surfaceManifestReader ?? throw new ArgumentNullException(nameof(surfaceManifestReader));
|
||||
_metrics = metrics ?? throw new ArgumentNullException(nameof(metrics));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -78,6 +86,8 @@ internal sealed class PlannerQueueDispatchService : IPlannerQueueDispatchService
|
||||
continue;
|
||||
}
|
||||
|
||||
var manifestPointers = await PrefetchManifestsAsync(digests, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var segmentAttributes = MergeAttributes(attributes, shard, schedule);
|
||||
var runnerMessage = new RunnerSegmentQueueMessage(
|
||||
segmentId,
|
||||
@@ -88,7 +98,8 @@ internal sealed class PlannerQueueDispatchService : IPlannerQueueDispatchService
|
||||
limits.RatePerSecond,
|
||||
impactSet.UsageOnly,
|
||||
segmentAttributes,
|
||||
message.CorrelationId);
|
||||
message.CorrelationId,
|
||||
manifestPointers);
|
||||
|
||||
enqueueTasks.Add(_runnerQueue.EnqueueAsync(runnerMessage, cancellationToken).AsTask());
|
||||
}
|
||||
@@ -190,6 +201,48 @@ internal sealed class PlannerQueueDispatchService : IPlannerQueueDispatchService
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyDictionary<string, SurfaceManifestPointer>> PrefetchManifestsAsync(
|
||||
IReadOnlyList<string> digests,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var results = new Dictionary<string, SurfaceManifestPointer>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var digest in digests)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
var manifest = await _surfaceManifestReader
|
||||
.TryGetByDigestAsync(digest, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (manifest is null)
|
||||
{
|
||||
_metrics.RecordSurfaceManifestPrefetch(result: "miss");
|
||||
continue;
|
||||
}
|
||||
|
||||
var pointer = new SurfaceManifestPointer(digest, manifest.Tenant);
|
||||
results[digest] = pointer;
|
||||
_metrics.RecordSurfaceManifestPrefetch(result: "hit");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, "Failed to prefetch surface manifest for digest {Digest}", digest);
|
||||
_metrics.RecordSurfaceManifestPrefetch(result: "error");
|
||||
}
|
||||
}
|
||||
|
||||
return results.Count == 0
|
||||
? (IReadOnlyDictionary<string, SurfaceManifestPointer>)EmptyReadOnlyDictionary<string, SurfaceManifestPointer>.Instance
|
||||
: results;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly record struct PlannerQueueDispatchResult(
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.Scheduler.Worker.Planning;
|
||||
|
||||
/// <summary>
|
||||
/// Minimal pointer to a Surface.FS manifest associated with an image digest.
|
||||
/// </summary>
|
||||
public sealed record SurfaceManifestPointer
|
||||
{
|
||||
public SurfaceManifestPointer(string manifestDigest, string? tenant)
|
||||
{
|
||||
ManifestDigest = manifestDigest ?? throw new ArgumentNullException(nameof(manifestDigest));
|
||||
Tenant = tenant;
|
||||
}
|
||||
|
||||
[JsonPropertyName("manifestDigest")]
|
||||
public string ManifestDigest { get; init; }
|
||||
|
||||
[JsonPropertyName("tenant")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Tenant { get; init; }
|
||||
}
|
||||
@@ -12,8 +12,10 @@
|
||||
<ProjectReference Include="../StellaOps.Scheduler.Queue/StellaOps.Scheduler.Queue.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Models/StellaOps.Notify.Models.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Queue/StellaOps.Notify.Queue.csproj" />
|
||||
<ProjectReference Include="../../../Scanner/__Libraries/StellaOps.Scanner.Surface.Env/StellaOps.Scanner.Surface.Env.csproj" />
|
||||
<ProjectReference Include="../../../Scanner/__Libraries/StellaOps.Scanner.Surface.FS/StellaOps.Scanner.Surface.FS.csproj" />
|
||||
<PackageReference Include="Cronos" Version="0.10.0" />
|
||||
<PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0-rc.2.25502.107" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user