up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-13 00:20:26 +02:00
parent e1f1bef4c1
commit 564df71bfb
2376 changed files with 334389 additions and 328032 deletions

View File

@@ -1,5 +1,5 @@
global using System.Collections.Immutable;
global using StellaOps.Scheduler.ImpactIndex;
global using StellaOps.Scheduler.Models;
global using StellaOps.Scheduler.Worker;
global using Xunit;
global using System.Collections.Immutable;
global using StellaOps.Scheduler.ImpactIndex;
global using StellaOps.Scheduler.Models;
global using StellaOps.Scheduler.Worker;
global using Xunit;

View File

@@ -4,7 +4,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Driver;
using StellaOps.Scheduler.Queue;
using StellaOps.Scheduler.Storage.Postgres.Repositories.Projections;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
@@ -212,23 +211,23 @@ public sealed class PlannerBackgroundServiceTests
public IReadOnlyList<Run> UpdatedRuns => _updates.ToArray();
public Task InsertAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task InsertAsync(Run run, CancellationToken cancellationToken = default)
=> throw new NotSupportedException();
public Task<bool> UpdateAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> UpdateAsync(Run run, CancellationToken cancellationToken = default)
{
_updates.Enqueue(run);
Interlocked.Increment(ref _updateCount);
return Task.FromResult(true);
}
public Task<Run?> GetAsync(string tenantId, string runId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<Run?> GetAsync(string tenantId, string runId, CancellationToken cancellationToken = default)
=> Task.FromResult<Run?>(null);
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Run>>(Array.Empty<Run>());
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, CancellationToken cancellationToken = default)
{
if (state != RunState.Planning)
{
@@ -266,25 +265,25 @@ public sealed class PlannerBackgroundServiceTests
private readonly Dictionary<(string TenantId, string ScheduleId), Schedule> _schedules;
public Task UpsertAsync(Schedule schedule, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task UpsertAsync(Schedule schedule, CancellationToken cancellationToken = default)
{
_schedules[(schedule.TenantId, schedule.Id)] = schedule;
return Task.CompletedTask;
}
public Task<Schedule?> GetAsync(string tenantId, string scheduleId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<Schedule?> GetAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default)
{
_schedules.TryGetValue((tenantId, scheduleId), out var schedule);
return Task.FromResult(schedule);
}
public Task<IReadOnlyList<Schedule>> ListAsync(string tenantId, ScheduleQueryOptions? options = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Schedule>> ListAsync(string tenantId, ScheduleQueryOptions? options = null, CancellationToken cancellationToken = default)
{
var results = _schedules.Values.Where(schedule => schedule.TenantId == tenantId).ToArray();
return Task.FromResult<IReadOnlyList<Schedule>>(results);
}
public Task<bool> SoftDeleteAsync(string tenantId, string scheduleId, string deletedBy, DateTimeOffset deletedAt, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> SoftDeleteAsync(string tenantId, string scheduleId, string deletedBy, DateTimeOffset deletedAt, CancellationToken cancellationToken = default)
{
var removed = _schedules.Remove((tenantId, scheduleId));
return Task.FromResult(removed);
@@ -295,16 +294,16 @@ public sealed class PlannerBackgroundServiceTests
{
public ImpactSet? LastSnapshot { get; private set; }
public Task UpsertAsync(ImpactSet snapshot, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task UpsertAsync(ImpactSet snapshot, CancellationToken cancellationToken = default)
{
LastSnapshot = snapshot;
return Task.CompletedTask;
}
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(null);
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(null);
}

View File

@@ -1,7 +1,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using MongoDB.Driver;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Queue;
@@ -187,22 +186,22 @@ public sealed class PlannerExecutionServiceTests
_store = schedules.ToDictionary(schedule => (schedule.TenantId, schedule.Id), schedule => schedule);
}
public Task UpsertAsync(Schedule schedule, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task UpsertAsync(Schedule schedule, CancellationToken cancellationToken = default)
{
_store[(schedule.TenantId, schedule.Id)] = schedule;
return Task.CompletedTask;
}
public Task<Schedule?> GetAsync(string tenantId, string scheduleId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<Schedule?> GetAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default)
{
_store.TryGetValue((tenantId, scheduleId), out var schedule);
return Task.FromResult(schedule);
}
public Task<IReadOnlyList<Schedule>> ListAsync(string tenantId, ScheduleQueryOptions? options = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Schedule>> ListAsync(string tenantId, ScheduleQueryOptions? options = null, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Schedule>>(_store.Values.Where(schedule => schedule.TenantId == tenantId).ToArray());
public Task<bool> SoftDeleteAsync(string tenantId, string scheduleId, string deletedBy, DateTimeOffset deletedAt, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> SoftDeleteAsync(string tenantId, string scheduleId, string deletedBy, DateTimeOffset deletedAt, CancellationToken cancellationToken = default)
=> Task.FromResult(_store.Remove((tenantId, scheduleId)));
}
@@ -218,28 +217,28 @@ public sealed class PlannerExecutionServiceTests
}
}
public Task InsertAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task InsertAsync(Run run, CancellationToken cancellationToken = default)
{
_runs[(run.TenantId, run.Id)] = run;
return Task.CompletedTask;
}
public Task<bool> UpdateAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> UpdateAsync(Run run, CancellationToken cancellationToken = default)
{
_runs[(run.TenantId, run.Id)] = run;
return Task.FromResult(true);
}
public Task<Run?> GetAsync(string tenantId, string runId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<Run?> GetAsync(string tenantId, string runId, CancellationToken cancellationToken = default)
{
_runs.TryGetValue((tenantId, runId), out var run);
return Task.FromResult(run);
}
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Run>>(_runs.Values.Where(run => run.TenantId == tenantId).ToArray());
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Run>>(_runs.Values.Where(run => run.State == state).Take(limit).ToArray());
}
@@ -247,16 +246,16 @@ public sealed class PlannerExecutionServiceTests
{
public ImpactSet? LastSnapshot { get; private set; }
public Task UpsertAsync(ImpactSet snapshot, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task UpsertAsync(ImpactSet snapshot, CancellationToken cancellationToken = default)
{
LastSnapshot = snapshot;
return Task.CompletedTask;
}
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(null);
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(null);
}

View File

@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
@@ -67,13 +66,13 @@ public sealed class PolicyRunDispatchBackgroundServiceTests
public int LeaseAttempts => Volatile.Read(ref _leaseAttempts);
public Task InsertAsync(PolicyRunJob job, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task InsertAsync(PolicyRunJob job, CancellationToken cancellationToken = default)
=> Task.CompletedTask;
public Task<PolicyRunJob?> GetAsync(string tenantId, string jobId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<PolicyRunJob?> GetAsync(string tenantId, string jobId, CancellationToken cancellationToken = default)
=> Task.FromResult<PolicyRunJob?>(null);
public Task<PolicyRunJob?> GetByRunIdAsync(string tenantId, string runId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<PolicyRunJob?> GetByRunIdAsync(string tenantId, string runId, CancellationToken cancellationToken = default)
=> Task.FromResult<PolicyRunJob?>(null);
public Task<PolicyRunJob?> LeaseAsync(
@@ -81,7 +80,6 @@ public sealed class PolicyRunDispatchBackgroundServiceTests
DateTimeOffset now,
TimeSpan leaseDuration,
int maxAttempts,
IClientSessionHandle? session = null,
CancellationToken cancellationToken = default)
{
Interlocked.Increment(ref _leaseAttempts);
@@ -95,14 +93,12 @@ public sealed class PolicyRunDispatchBackgroundServiceTests
IReadOnlyCollection<PolicyRunJobStatus>? statuses = null,
DateTimeOffset? queuedAfter = null,
int limit = 50,
IClientSessionHandle? session = null,
CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<PolicyRunJob>>(Array.Empty<PolicyRunJob>());
public Task<bool> ReplaceAsync(
PolicyRunJob job,
string? expectedLeaseOwner = null,
IClientSessionHandle? session = null,
CancellationToken cancellationToken = default)
=> Task.FromResult(true);

View File

@@ -5,7 +5,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
@@ -310,13 +309,13 @@ public sealed class PolicyRunExecutionServiceTests
public string? ExpectedLeaseOwner { get; private set; }
public PolicyRunJob? LastJob { get; private set; }
public Task<PolicyRunJob?> GetAsync(string tenantId, string jobId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<PolicyRunJob?> GetAsync(string tenantId, string jobId, CancellationToken cancellationToken = default)
=> Task.FromResult<PolicyRunJob?>(null);
public Task<PolicyRunJob?> GetByRunIdAsync(string tenantId, string runId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<PolicyRunJob?> GetByRunIdAsync(string tenantId, string runId, CancellationToken cancellationToken = default)
=> Task.FromResult<PolicyRunJob?>(null);
public Task InsertAsync(PolicyRunJob job, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task InsertAsync(PolicyRunJob job, CancellationToken cancellationToken = default)
{
LastJob = job;
return Task.CompletedTask;
@@ -325,10 +324,10 @@ public sealed class PolicyRunExecutionServiceTests
public Task<long> CountAsync(string tenantId, PolicyRunMode mode, IReadOnlyCollection<PolicyRunJobStatus> statuses, CancellationToken cancellationToken = default)
=> Task.FromResult(0L);
public Task<PolicyRunJob?> LeaseAsync(string leaseOwner, DateTimeOffset now, TimeSpan leaseDuration, int maxAttempts, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<PolicyRunJob?> LeaseAsync(string leaseOwner, DateTimeOffset now, TimeSpan leaseDuration, int maxAttempts, CancellationToken cancellationToken = default)
=> Task.FromResult<PolicyRunJob?>(null);
public Task<bool> ReplaceAsync(PolicyRunJob job, string? expectedLeaseOwner = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> ReplaceAsync(PolicyRunJob job, string? expectedLeaseOwner = null, CancellationToken cancellationToken = default)
{
ReplaceCalled = true;
ExpectedLeaseOwner = expectedLeaseOwner;
@@ -336,7 +335,7 @@ public sealed class PolicyRunExecutionServiceTests
return Task.FromResult(true);
}
public Task<IReadOnlyList<PolicyRunJob>> ListAsync(string tenantId, string? policyId = null, PolicyRunMode? mode = null, IReadOnlyCollection<PolicyRunJobStatus>? statuses = null, DateTimeOffset? queuedAfter = null, int limit = 50, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<PolicyRunJob>> ListAsync(string tenantId, string? policyId = null, PolicyRunMode? mode = null, IReadOnlyCollection<PolicyRunJobStatus>? statuses = null, DateTimeOffset? queuedAfter = null, int limit = 50, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<PolicyRunJob>>(Array.Empty<PolicyRunJob>());
}

View File

@@ -1,255 +1,255 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Worker;
using StellaOps.Scheduler.Worker.Options;
using StellaOps.Scheduler.Worker.Policy;
using Xunit;
namespace StellaOps.Scheduler.Worker.Tests;
public sealed class PolicyRunTargetingServiceTests
{
[Fact]
public async Task EnsureTargetsAsync_ReturnsUnchanged_ForNonIncrementalJob()
{
var service = CreateService();
var job = CreateJob(mode: PolicyRunMode.Full);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
Assert.Equal(job, result.Job);
}
[Fact]
public async Task EnsureTargetsAsync_ReturnsUnchanged_WhenSbomSetAlreadyPresent()
{
var service = CreateService();
var inputs = new PolicyRunInputs(sbomSet: new[] { "sbom:S-1" });
var job = CreateJob(inputs: inputs);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
}
[Fact]
public async Task EnsureTargetsAsync_ReturnsNoWork_WhenNoCandidatesResolved()
{
var impact = new StubImpactTargetingService();
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.purls", "pkg:npm/leftpad");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.NoWork, result.Status);
Assert.Equal("no_matches", result.Reason);
}
[Fact]
public async Task EnsureTargetsAsync_TargetsDirectSboms()
{
var service = CreateService();
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.sboms", "sbom:S-2, sbom:S-1, sbom:S-2");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:S-1", "sbom:S-2" }, result.Job.Inputs.SbomSet);
}
[Fact]
public async Task EnsureTargetsAsync_TargetsUsingImpactIndex()
{
var impact = new StubImpactTargetingService
{
OnResolveByPurls = (keys, usageOnly, selector, _) =>
{
var image = new ImpactImage(
"sha256:111",
"registry",
"repo",
labels: ImmutableSortedDictionary.Create<string, string>(StringComparer.Ordinal).Add("sbomId", "sbom:S-42"));
var impactSet = new ImpactSet(
selector,
new[] { image },
usageOnly,
DateTimeOffset.UtcNow,
total: 1,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
return ValueTask.FromResult(impactSet);
}
};
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.purls", "pkg:npm/example");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:S-42" }, result.Job.Inputs.SbomSet);
}
[Fact]
public async Task EnsureTargetsAsync_FallsBack_WhenLimitExceeded()
{
var service = CreateService(configure: options => options.MaxSboms = 1);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.sboms", "sbom:S-1,sbom:S-2");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
}
[Fact]
public async Task EnsureTargetsAsync_FallbacksToDigest_WhenLabelMissing()
{
var impact = new StubImpactTargetingService
{
OnResolveByVulnerabilities = (ids, usageOnly, selector, _) =>
{
var image = new ImpactImage("sha256:aaa", "registry", "repo");
var impactSet = new ImpactSet(
selector,
new[] { image },
usageOnly,
DateTimeOffset.UtcNow,
total: 1,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
return ValueTask.FromResult(impactSet);
}
};
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.vulns", "CVE-2025-1234");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:sha256:aaa" }, result.Job.Inputs.SbomSet);
}
private static PolicyRunTargetingService CreateService(
IImpactTargetingService? impact = null,
Action<SchedulerWorkerOptions.PolicyOptions.TargetingOptions>? configure = null)
{
impact ??= new StubImpactTargetingService();
var options = CreateOptions(configure);
return new PolicyRunTargetingService(
impact,
Microsoft.Extensions.Options.Options.Create(options),
timeProvider: null,
NullLogger<PolicyRunTargetingService>.Instance);
}
private static SchedulerWorkerOptions CreateOptions(Action<SchedulerWorkerOptions.PolicyOptions.TargetingOptions>? configure)
{
var options = new SchedulerWorkerOptions
{
Policy =
{
Api =
{
BaseAddress = new Uri("https://policy.example.com"),
RunsPath = "/runs",
SimulatePath = "/simulate"
}
}
};
configure?.Invoke(options.Policy.Targeting);
return options;
}
private static PolicyRunJob CreateJob(
PolicyRunMode mode = PolicyRunMode.Incremental,
ImmutableSortedDictionary<string, string>? metadata = null,
PolicyRunInputs? inputs = null)
{
return new PolicyRunJob(
SchemaVersion: SchedulerSchemaVersions.PolicyRunJob,
Id: "job-1",
TenantId: "tenant-alpha",
PolicyId: "P-7",
PolicyVersion: 4,
Mode: mode,
Priority: PolicyRunPriority.Normal,
PriorityRank: 0,
RunId: null,
RequestedBy: null,
CorrelationId: null,
Metadata: metadata ?? ImmutableSortedDictionary<string, string>.Empty,
Inputs: inputs ?? PolicyRunInputs.Empty,
QueuedAt: DateTimeOffset.UtcNow,
Status: PolicyRunJobStatus.Dispatching,
AttemptCount: 0,
LastAttemptAt: null,
LastError: null,
CreatedAt: DateTimeOffset.UtcNow,
UpdatedAt: DateTimeOffset.UtcNow,
AvailableAt: DateTimeOffset.UtcNow,
SubmittedAt: null,
CompletedAt: null,
LeaseOwner: "lease",
LeaseExpiresAt: DateTimeOffset.UtcNow.AddMinutes(1),
CancellationRequested: false,
CancellationRequestedAt: null,
CancellationReason: null,
CancelledAt: null);
}
private sealed class StubImpactTargetingService : IImpactTargetingService
{
public Func<IEnumerable<string>, bool, Selector, CancellationToken, ValueTask<ImpactSet>>? OnResolveByPurls { get; set; }
public Func<IEnumerable<string>, bool, Selector, CancellationToken, ValueTask<ImpactSet>>? OnResolveByVulnerabilities { get; set; }
public ValueTask<ImpactSet> ResolveByPurlsAsync(IEnumerable<string> productKeys, bool usageOnly, Selector selector, CancellationToken cancellationToken = default)
{
if (OnResolveByPurls is null)
{
return ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
}
return OnResolveByPurls(productKeys, usageOnly, selector, cancellationToken);
}
public ValueTask<ImpactSet> ResolveByVulnerabilitiesAsync(IEnumerable<string> vulnerabilityIds, bool usageOnly, Selector selector, CancellationToken cancellationToken = default)
{
if (OnResolveByVulnerabilities is null)
{
return ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
}
return OnResolveByVulnerabilities(vulnerabilityIds, usageOnly, selector, cancellationToken);
}
public ValueTask<ImpactSet> ResolveAllAsync(Selector selector, bool usageOnly, CancellationToken cancellationToken = default)
=> ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
private static ImpactSet CreateEmptyImpactSet(Selector selector, bool usageOnly)
{
return new ImpactSet(
selector,
ImmutableArray<ImpactImage>.Empty,
usageOnly,
DateTimeOffset.UtcNow,
total: 0,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Worker;
using StellaOps.Scheduler.Worker.Options;
using StellaOps.Scheduler.Worker.Policy;
using Xunit;
namespace StellaOps.Scheduler.Worker.Tests;
public sealed class PolicyRunTargetingServiceTests
{
[Fact]
public async Task EnsureTargetsAsync_ReturnsUnchanged_ForNonIncrementalJob()
{
var service = CreateService();
var job = CreateJob(mode: PolicyRunMode.Full);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
Assert.Equal(job, result.Job);
}
[Fact]
public async Task EnsureTargetsAsync_ReturnsUnchanged_WhenSbomSetAlreadyPresent()
{
var service = CreateService();
var inputs = new PolicyRunInputs(sbomSet: new[] { "sbom:S-1" });
var job = CreateJob(inputs: inputs);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
}
[Fact]
public async Task EnsureTargetsAsync_ReturnsNoWork_WhenNoCandidatesResolved()
{
var impact = new StubImpactTargetingService();
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.purls", "pkg:npm/leftpad");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.NoWork, result.Status);
Assert.Equal("no_matches", result.Reason);
}
[Fact]
public async Task EnsureTargetsAsync_TargetsDirectSboms()
{
var service = CreateService();
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.sboms", "sbom:S-2, sbom:S-1, sbom:S-2");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:S-1", "sbom:S-2" }, result.Job.Inputs.SbomSet);
}
[Fact]
public async Task EnsureTargetsAsync_TargetsUsingImpactIndex()
{
var impact = new StubImpactTargetingService
{
OnResolveByPurls = (keys, usageOnly, selector, _) =>
{
var image = new ImpactImage(
"sha256:111",
"registry",
"repo",
labels: ImmutableSortedDictionary.Create<string, string>(StringComparer.Ordinal).Add("sbomId", "sbom:S-42"));
var impactSet = new ImpactSet(
selector,
new[] { image },
usageOnly,
DateTimeOffset.UtcNow,
total: 1,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
return ValueTask.FromResult(impactSet);
}
};
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.purls", "pkg:npm/example");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:S-42" }, result.Job.Inputs.SbomSet);
}
[Fact]
public async Task EnsureTargetsAsync_FallsBack_WhenLimitExceeded()
{
var service = CreateService(configure: options => options.MaxSboms = 1);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.sboms", "sbom:S-1,sbom:S-2");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Unchanged, result.Status);
}
[Fact]
public async Task EnsureTargetsAsync_FallbacksToDigest_WhenLabelMissing()
{
var impact = new StubImpactTargetingService
{
OnResolveByVulnerabilities = (ids, usageOnly, selector, _) =>
{
var image = new ImpactImage("sha256:aaa", "registry", "repo");
var impactSet = new ImpactSet(
selector,
new[] { image },
usageOnly,
DateTimeOffset.UtcNow,
total: 1,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
return ValueTask.FromResult(impactSet);
}
};
var service = CreateService(impact);
var metadata = ImmutableSortedDictionary<string, string>.Empty.Add("delta.vulns", "CVE-2025-1234");
var job = CreateJob(metadata: metadata, inputs: PolicyRunInputs.Empty);
var result = await service.EnsureTargetsAsync(job, CancellationToken.None);
Assert.Equal(PolicyRunTargetingStatus.Targeted, result.Status);
Assert.Equal(new[] { "sbom:sha256:aaa" }, result.Job.Inputs.SbomSet);
}
private static PolicyRunTargetingService CreateService(
IImpactTargetingService? impact = null,
Action<SchedulerWorkerOptions.PolicyOptions.TargetingOptions>? configure = null)
{
impact ??= new StubImpactTargetingService();
var options = CreateOptions(configure);
return new PolicyRunTargetingService(
impact,
Microsoft.Extensions.Options.Options.Create(options),
timeProvider: null,
NullLogger<PolicyRunTargetingService>.Instance);
}
private static SchedulerWorkerOptions CreateOptions(Action<SchedulerWorkerOptions.PolicyOptions.TargetingOptions>? configure)
{
var options = new SchedulerWorkerOptions
{
Policy =
{
Api =
{
BaseAddress = new Uri("https://policy.example.com"),
RunsPath = "/runs",
SimulatePath = "/simulate"
}
}
};
configure?.Invoke(options.Policy.Targeting);
return options;
}
private static PolicyRunJob CreateJob(
PolicyRunMode mode = PolicyRunMode.Incremental,
ImmutableSortedDictionary<string, string>? metadata = null,
PolicyRunInputs? inputs = null)
{
return new PolicyRunJob(
SchemaVersion: SchedulerSchemaVersions.PolicyRunJob,
Id: "job-1",
TenantId: "tenant-alpha",
PolicyId: "P-7",
PolicyVersion: 4,
Mode: mode,
Priority: PolicyRunPriority.Normal,
PriorityRank: 0,
RunId: null,
RequestedBy: null,
CorrelationId: null,
Metadata: metadata ?? ImmutableSortedDictionary<string, string>.Empty,
Inputs: inputs ?? PolicyRunInputs.Empty,
QueuedAt: DateTimeOffset.UtcNow,
Status: PolicyRunJobStatus.Dispatching,
AttemptCount: 0,
LastAttemptAt: null,
LastError: null,
CreatedAt: DateTimeOffset.UtcNow,
UpdatedAt: DateTimeOffset.UtcNow,
AvailableAt: DateTimeOffset.UtcNow,
SubmittedAt: null,
CompletedAt: null,
LeaseOwner: "lease",
LeaseExpiresAt: DateTimeOffset.UtcNow.AddMinutes(1),
CancellationRequested: false,
CancellationRequestedAt: null,
CancellationReason: null,
CancelledAt: null);
}
private sealed class StubImpactTargetingService : IImpactTargetingService
{
public Func<IEnumerable<string>, bool, Selector, CancellationToken, ValueTask<ImpactSet>>? OnResolveByPurls { get; set; }
public Func<IEnumerable<string>, bool, Selector, CancellationToken, ValueTask<ImpactSet>>? OnResolveByVulnerabilities { get; set; }
public ValueTask<ImpactSet> ResolveByPurlsAsync(IEnumerable<string> productKeys, bool usageOnly, Selector selector, CancellationToken cancellationToken = default)
{
if (OnResolveByPurls is null)
{
return ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
}
return OnResolveByPurls(productKeys, usageOnly, selector, cancellationToken);
}
public ValueTask<ImpactSet> ResolveByVulnerabilitiesAsync(IEnumerable<string> vulnerabilityIds, bool usageOnly, Selector selector, CancellationToken cancellationToken = default)
{
if (OnResolveByVulnerabilities is null)
{
return ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
}
return OnResolveByVulnerabilities(vulnerabilityIds, usageOnly, selector, cancellationToken);
}
public ValueTask<ImpactSet> ResolveAllAsync(Selector selector, bool usageOnly, CancellationToken cancellationToken = default)
=> ValueTask.FromResult(CreateEmptyImpactSet(selector, usageOnly));
private static ImpactSet CreateEmptyImpactSet(Selector selector, bool usageOnly)
{
return new ImpactSet(
selector,
ImmutableArray<ImpactImage>.Empty,
usageOnly,
DateTimeOffset.UtcNow,
total: 0,
snapshotId: null,
schemaVersion: SchedulerSchemaVersions.ImpactSet);
}
}
}

View File

@@ -6,7 +6,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Driver;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Queue;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
@@ -205,28 +204,28 @@ public sealed class RunnerExecutionServiceTests
}
}
public Task InsertAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task InsertAsync(Run run, CancellationToken cancellationToken = default)
{
_runs[(run.TenantId, run.Id)] = run;
return Task.CompletedTask;
}
public Task<bool> UpdateAsync(Run run, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<bool> UpdateAsync(Run run, CancellationToken cancellationToken = default)
{
_runs[(run.TenantId, run.Id)] = run;
return Task.FromResult(true);
}
public Task<Run?> GetAsync(string tenantId, string runId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<Run?> GetAsync(string tenantId, string runId, CancellationToken cancellationToken = default)
{
_runs.TryGetValue((tenantId, runId), out var run);
return Task.FromResult(run);
}
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListAsync(string tenantId, RunQueryOptions? options = null, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Run>>(_runs.Values.Where(run => run.TenantId == tenantId).ToArray());
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<IReadOnlyList<Run>> ListByStateAsync(RunState state, int limit = 50, CancellationToken cancellationToken = default)
=> Task.FromResult<IReadOnlyList<Run>>(_runs.Values.Where(run => run.State == state).Take(limit).ToArray());
public Run? GetSnapshot(string tenantId, string runId)
@@ -253,13 +252,13 @@ public sealed class RunnerExecutionServiceTests
total: imageArray.Length);
}
public Task UpsertAsync(ImpactSet snapshot, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task UpsertAsync(ImpactSet snapshot, CancellationToken cancellationToken = default)
=> Task.CompletedTask;
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetBySnapshotIdAsync(string snapshotId, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(string.Equals(snapshotId, _snapshotId, StringComparison.Ordinal) ? _snapshot : null);
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, IClientSessionHandle? session = null, CancellationToken cancellationToken = default)
public Task<ImpactSet?> GetLatestBySelectorAsync(Selector selector, CancellationToken cancellationToken = default)
=> Task.FromResult<ImpactSet?>(_snapshot);
}