134 lines
5.4 KiB
C#
134 lines
5.4 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using StellaOps.Plugin;
|
|
using StellaOps.Excititor.Connectors.Abstractions;
|
|
using StellaOps.Excititor.Core;
|
|
using StellaOps.Excititor.Core.Aoc;
|
|
using StellaOps.Excititor.Core.Storage;
|
|
using StellaOps.Excititor.Core.Orchestration;
|
|
using StellaOps.Excititor.Formats.CSAF;
|
|
using StellaOps.Excititor.Formats.CycloneDX;
|
|
using StellaOps.Excititor.Formats.OpenVEX;
|
|
using StellaOps.Excititor.Persistence.Extensions;
|
|
using StellaOps.Excititor.Worker.Auth;
|
|
using StellaOps.Excititor.Worker.Options;
|
|
using StellaOps.Excititor.Worker.Orchestration;
|
|
using StellaOps.Excititor.Worker.Plugins;
|
|
using StellaOps.Excititor.Worker.Scheduling;
|
|
using StellaOps.Excititor.Worker.Signature;
|
|
using StellaOps.Excititor.Attestation.Extensions;
|
|
using StellaOps.Excititor.Attestation.Verification;
|
|
using StellaOps.IssuerDirectory.Client;
|
|
|
|
var builder = Host.CreateApplicationBuilder(args);
|
|
var services = builder.Services;
|
|
var configuration = builder.Configuration;
|
|
var workerConfig = configuration.GetSection("Excititor:Worker");
|
|
var workerConfigSnapshot = workerConfig.Get<VexWorkerOptions>() ?? new VexWorkerOptions();
|
|
services.AddOptions<VexWorkerOptions>()
|
|
.Bind(workerConfig)
|
|
.ValidateOnStart();
|
|
|
|
services.Configure<VexWorkerPluginOptions>(configuration.GetSection("Excititor:Worker:Plugins"));
|
|
services.Configure<TenantAuthorityOptions>(configuration.GetSection("Excititor:Authority"));
|
|
services.AddSingleton<IValidateOptions<TenantAuthorityOptions>, TenantAuthorityOptionsValidator>();
|
|
services.PostConfigure<VexWorkerOptions>(options =>
|
|
{
|
|
if (options.DisableConsensus)
|
|
{
|
|
options.Refresh.Enabled = false;
|
|
}
|
|
});
|
|
// VEX connectors are loaded via plugin catalog below
|
|
// Direct connector registration removed in favor of plugin-based loading
|
|
|
|
services.AddOptions<VexStorageOptions>()
|
|
.Bind(configuration.GetSection("Excititor:Storage"))
|
|
.ValidateOnStart();
|
|
|
|
services.AddExcititorPersistence(configuration);
|
|
services.TryAddSingleton<IVexProviderStore, InMemoryVexProviderStore>();
|
|
services.TryAddScoped<IVexConnectorStateRepository, InMemoryVexConnectorStateRepository>();
|
|
services.TryAddSingleton<IVexClaimStore, InMemoryVexClaimStore>();
|
|
services.AddCsafNormalizer();
|
|
services.AddCycloneDxNormalizer();
|
|
services.AddOpenVexNormalizer();
|
|
services.AddSingleton<IVexSignatureVerifier, WorkerSignatureVerifier>();
|
|
services.AddVexAttestation();
|
|
services.Configure<VexAttestationVerificationOptions>(configuration.GetSection("Excititor:Attestation:Verification"));
|
|
var issuerDirectorySection = configuration.GetSection("Excititor:IssuerDirectory");
|
|
if (issuerDirectorySection.Exists())
|
|
{
|
|
services.AddIssuerDirectoryClient(issuerDirectorySection);
|
|
}
|
|
else
|
|
{
|
|
services.AddIssuerDirectoryClient(configuration);
|
|
}
|
|
services.PostConfigure<VexAttestationVerificationOptions>(options =>
|
|
{
|
|
// Workers operate in offline-first environments; allow verification to succeed without Rekor.
|
|
options.AllowOfflineTransparency = true;
|
|
if (!configuration.GetSection("Excititor:Attestation:Verification").Exists())
|
|
{
|
|
options.RequireTransparencyLog = false;
|
|
}
|
|
});
|
|
services.AddExcititorAocGuards();
|
|
|
|
services.AddSingleton<IValidateOptions<VexWorkerOptions>, VexWorkerOptionsValidator>();
|
|
services.AddSingleton(TimeProvider.System);
|
|
services.TryAddSingleton<IGuidGenerator, DefaultGuidGenerator>();
|
|
services.PostConfigure<VexWorkerOptions>(options =>
|
|
{
|
|
if (!options.Providers.Any(provider => string.Equals(provider.ProviderId, "excititor:redhat", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
options.Providers.Add(new VexWorkerProviderOptions
|
|
{
|
|
ProviderId = "excititor:redhat",
|
|
});
|
|
}
|
|
});
|
|
// Load VEX connector plugins
|
|
services.AddSingleton<VexWorkerPluginCatalogLoader>();
|
|
services.AddSingleton<PluginCatalog>(provider =>
|
|
provider.GetRequiredService<VexWorkerPluginCatalogLoader>().Load().Catalog);
|
|
|
|
// Orchestrator worker SDK integration
|
|
services.AddOptions<VexWorkerOrchestratorOptions>()
|
|
.Bind(configuration.GetSection("Excititor:Worker:Orchestrator"))
|
|
.ValidateOnStart();
|
|
services.AddHttpClient(TenantAuthorityClientFactory.AuthorityClientName);
|
|
services.AddHttpClient<IVexWorkerOrchestratorClient, VexWorkerOrchestratorClient>((provider, client) =>
|
|
{
|
|
var opts = provider.GetRequiredService<IOptions<VexWorkerOrchestratorOptions>>().Value;
|
|
if (opts.BaseAddress is not null)
|
|
{
|
|
client.BaseAddress = opts.BaseAddress;
|
|
}
|
|
|
|
client.Timeout = opts.RequestTimeout;
|
|
});
|
|
services.AddSingleton<VexWorkerHeartbeatService>();
|
|
|
|
services.AddSingleton<IVexProviderRunner, DefaultVexProviderRunner>();
|
|
services.AddHostedService<VexWorkerHostedService>();
|
|
if (!workerConfigSnapshot.DisableConsensus)
|
|
{
|
|
services.AddSingleton<VexConsensusRefreshService>();
|
|
services.AddSingleton<IVexConsensusRefreshScheduler>(static provider => provider.GetRequiredService<VexConsensusRefreshService>());
|
|
services.AddHostedService(static provider => provider.GetRequiredService<VexConsensusRefreshService>());
|
|
}
|
|
services.AddSingleton<ITenantAuthorityClientFactory, TenantAuthorityClientFactory>();
|
|
|
|
var host = builder.Build();
|
|
await host.RunAsync();
|
|
|
|
// Make Program class file-scoped to prevent it from being exposed to referencing assemblies
|
|
file sealed partial class Program;
|