consolidation of some of the modules, localization fixes, product advisories work, qa work
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
|
||||
using Dapper;
|
||||
using StellaOps.Scheduler.Persistence.Postgres;
|
||||
using StellaOps.Scheduler.Worker.Exceptions;
|
||||
|
||||
namespace StellaOps.Scheduler.WebService.Exceptions;
|
||||
|
||||
public sealed class PostgresExceptionRepository : IExceptionRepository
|
||||
{
|
||||
private readonly SchedulerDataSource _dataSource;
|
||||
|
||||
public PostgresExceptionRepository(SchedulerDataSource dataSource)
|
||||
{
|
||||
_dataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource));
|
||||
}
|
||||
|
||||
public async ValueTask<ExceptionRecord?> GetAsync(string exceptionId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(exceptionId);
|
||||
await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken);
|
||||
|
||||
const string sql = """
|
||||
SELECT exception_id, tenant_id, policy_id, vulnerability_id, component_purl,
|
||||
state, created_at, activation_date, expiration_date, activated_at,
|
||||
expired_at, justification, created_by
|
||||
FROM scheduler.scheduler_exceptions
|
||||
WHERE exception_id = @ExceptionId
|
||||
LIMIT 1;
|
||||
""";
|
||||
|
||||
var row = await conn.QuerySingleOrDefaultAsync(sql, new { ExceptionId = exceptionId });
|
||||
return row is null ? null : Map(row);
|
||||
}
|
||||
|
||||
public async ValueTask<IReadOnlyList<ExceptionRecord>> GetPendingActivationsAsync(
|
||||
DateTimeOffset asOf,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken);
|
||||
|
||||
const string sql = """
|
||||
SELECT exception_id, tenant_id, policy_id, vulnerability_id, component_purl,
|
||||
state, created_at, activation_date, expiration_date, activated_at,
|
||||
expired_at, justification, created_by
|
||||
FROM scheduler.scheduler_exceptions
|
||||
WHERE state = 'pending' AND activation_date <= @AsOf
|
||||
ORDER BY activation_date ASC;
|
||||
""";
|
||||
|
||||
var rows = await conn.QueryAsync(sql, new { AsOf = asOf });
|
||||
return rows.Select(Map).ToList();
|
||||
}
|
||||
|
||||
public async ValueTask<IReadOnlyList<ExceptionRecord>> GetExpiredExceptionsAsync(
|
||||
DateTimeOffset asOf,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken);
|
||||
|
||||
const string sql = """
|
||||
SELECT exception_id, tenant_id, policy_id, vulnerability_id, component_purl,
|
||||
state, created_at, activation_date, expiration_date, activated_at,
|
||||
expired_at, justification, created_by
|
||||
FROM scheduler.scheduler_exceptions
|
||||
WHERE state = 'active' AND expiration_date <= @AsOf
|
||||
ORDER BY expiration_date ASC;
|
||||
""";
|
||||
|
||||
var rows = await conn.QueryAsync(sql, new { AsOf = asOf });
|
||||
return rows.Select(Map).ToList();
|
||||
}
|
||||
|
||||
public async ValueTask<IReadOnlyList<ExceptionRecord>> GetExpiringExceptionsAsync(
|
||||
DateTimeOffset windowStart,
|
||||
DateTimeOffset windowEnd,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken);
|
||||
|
||||
const string sql = """
|
||||
SELECT exception_id, tenant_id, policy_id, vulnerability_id, component_purl,
|
||||
state, created_at, activation_date, expiration_date, activated_at,
|
||||
expired_at, justification, created_by
|
||||
FROM scheduler.scheduler_exceptions
|
||||
WHERE state = 'active'
|
||||
AND expiration_date > @WindowStart
|
||||
AND expiration_date <= @WindowEnd
|
||||
ORDER BY expiration_date ASC;
|
||||
""";
|
||||
|
||||
var rows = await conn.QueryAsync(sql, new { WindowStart = windowStart, WindowEnd = windowEnd });
|
||||
return rows.Select(Map).ToList();
|
||||
}
|
||||
|
||||
public async ValueTask UpdateAsync(ExceptionRecord record, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
await using var conn = await _dataSource.OpenSystemConnectionAsync(cancellationToken);
|
||||
|
||||
const string sql = """
|
||||
UPDATE scheduler.scheduler_exceptions
|
||||
SET state = @State::scheduler.exception_state,
|
||||
activation_date = @ActivationDate,
|
||||
expiration_date = @ExpirationDate,
|
||||
activated_at = @ActivatedAt,
|
||||
expired_at = @ExpiredAt,
|
||||
justification = @Justification
|
||||
WHERE exception_id = @ExceptionId;
|
||||
""";
|
||||
|
||||
await conn.ExecuteAsync(sql, new
|
||||
{
|
||||
record.ExceptionId,
|
||||
State = record.State.ToString().ToLowerInvariant(),
|
||||
record.ActivationDate,
|
||||
record.ExpirationDate,
|
||||
record.ActivatedAt,
|
||||
record.ExpiredAt,
|
||||
record.Justification
|
||||
});
|
||||
}
|
||||
|
||||
private static ExceptionRecord Map(dynamic row)
|
||||
{
|
||||
return new ExceptionRecord(
|
||||
(string)row.exception_id,
|
||||
(string)row.tenant_id,
|
||||
(string)row.policy_id,
|
||||
(string)row.vulnerability_id,
|
||||
(string?)row.component_purl,
|
||||
Enum.Parse<ExceptionState>((string)row.state, true),
|
||||
DateTime.SpecifyKind(row.created_at, DateTimeKind.Utc),
|
||||
row.activation_date is null ? null : (DateTimeOffset?)DateTime.SpecifyKind(row.activation_date, DateTimeKind.Utc),
|
||||
row.expiration_date is null ? null : (DateTimeOffset?)DateTime.SpecifyKind(row.expiration_date, DateTimeKind.Utc),
|
||||
row.activated_at is null ? null : (DateTimeOffset?)DateTime.SpecifyKind(row.activated_at, DateTimeKind.Utc),
|
||||
row.expired_at is null ? null : (DateTimeOffset?)DateTime.SpecifyKind(row.expired_at, DateTimeKind.Utc),
|
||||
(string?)row.justification,
|
||||
(string?)row.created_by);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user