using System; using System.Collections.Generic; using System.Globalization; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using StellaOps.Concelier.Core.Jobs; namespace StellaOps.Concelier.Exporter.TrivyDb; public sealed class TrivyDbExportJob : IJob { public const string JobKind = "export:trivy-db"; public static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(20); public static readonly TimeSpan DefaultLeaseDuration = TimeSpan.FromMinutes(10); private readonly TrivyDbFeedExporter _exporter; private readonly ILogger _logger; public TrivyDbExportJob(TrivyDbFeedExporter exporter, ILogger logger) { _exporter = exporter ?? throw new ArgumentNullException(nameof(exporter)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task ExecuteAsync(JobExecutionContext context, CancellationToken cancellationToken) { _logger.LogInformation("Executing Trivy DB export job {RunId}", context.RunId); var overrides = CreateOverrides(context.Parameters); if (overrides?.HasOverrides == true) { using var scope = TrivyDbExportOverrideScope.Begin(overrides); await _exporter.ExportAsync(context.Services, cancellationToken).ConfigureAwait(false); } else { await _exporter.ExportAsync(context.Services, cancellationToken).ConfigureAwait(false); } _logger.LogInformation("Completed Trivy DB export job {RunId}", context.RunId); } private static TrivyDbExportOverrides? CreateOverrides(IReadOnlyDictionary parameters) { if (parameters is null || parameters.Count == 0) { return null; } var publishFull = TryReadBoolean(parameters, "publishFull"); var publishDelta = TryReadBoolean(parameters, "publishDelta"); var includeFull = TryReadBoolean(parameters, "includeFull"); var includeDelta = TryReadBoolean(parameters, "includeDelta"); var overrides = new TrivyDbExportOverrides(publishFull, publishDelta, includeFull, includeDelta); return overrides.HasOverrides ? overrides : null; } private static bool? TryReadBoolean(IReadOnlyDictionary parameters, string key) { if (!parameters.TryGetValue(key, out var value) || value is null) { return null; } switch (value) { case bool b: return b; case string s when bool.TryParse(s, out var result): return result; case JsonElement element: return element.ValueKind switch { JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.String when bool.TryParse(element.GetString(), out var parsed) => parsed, _ => null, }; case IConvertible convertible: try { return convertible.ToBoolean(CultureInfo.InvariantCulture); } catch { return null; } } return null; } }