fix tests. new product advisories enhancements
This commit is contained in:
137
src/Attestor/StellaOps.Attestor.TileProxy/Program.cs
Normal file
137
src/Attestor/StellaOps.Attestor.TileProxy/Program.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// Program.cs
|
||||
// Sprint: SPRINT_20260125_002_Attestor_trust_automation
|
||||
// Task: PROXY-002 - Implement tile-proxy service
|
||||
// Description: Tile proxy web service entry point
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog;
|
||||
using StellaOps.Attestor.TileProxy;
|
||||
using StellaOps.Attestor.TileProxy.Endpoints;
|
||||
using StellaOps.Attestor.TileProxy.Jobs;
|
||||
using StellaOps.Attestor.TileProxy.Services;
|
||||
|
||||
const string ConfigurationSection = "tile_proxy";
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Configure logging
|
||||
builder.Host.UseSerilog((context, config) =>
|
||||
{
|
||||
config
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
|
||||
});
|
||||
|
||||
// Load configuration
|
||||
builder.Configuration
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||
.AddEnvironmentVariables("TILE_PROXY__");
|
||||
|
||||
// Configure options
|
||||
builder.Services.Configure<TileProxyOptions>(builder.Configuration.GetSection(ConfigurationSection));
|
||||
|
||||
// Validate options
|
||||
builder.Services.AddSingleton<IValidateOptions<TileProxyOptions>, TileProxyOptionsValidator>();
|
||||
|
||||
// Register services
|
||||
builder.Services.AddSingleton<ContentAddressedTileStore>();
|
||||
builder.Services.AddSingleton<TileProxyService>();
|
||||
|
||||
// Register sync job as hosted service
|
||||
builder.Services.AddHostedService<TileSyncJob>();
|
||||
|
||||
// Configure HTTP client for upstream
|
||||
builder.Services.AddHttpClient<TileProxyService>((sp, client) =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<TileProxyOptions>>().Value;
|
||||
client.BaseAddress = new Uri(options.UpstreamUrl);
|
||||
client.Timeout = TimeSpan.FromSeconds(options.Request.TimeoutSeconds);
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "StellaOps-TileProxy/1.0");
|
||||
});
|
||||
|
||||
// Add OpenAPI
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Validate options on startup
|
||||
var optionsValidator = app.Services.GetRequiredService<IValidateOptions<TileProxyOptions>>();
|
||||
var options = app.Services.GetRequiredService<IOptions<TileProxyOptions>>().Value;
|
||||
var validationResult = optionsValidator.Validate(null, options);
|
||||
if (validationResult.Failed)
|
||||
{
|
||||
throw new InvalidOperationException($"Configuration validation failed: {validationResult.FailureMessage}");
|
||||
}
|
||||
|
||||
// Configure pipeline
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
// Map endpoints
|
||||
app.MapTileProxyEndpoints();
|
||||
|
||||
// Startup message
|
||||
var logger = app.Services.GetRequiredService<ILogger<Program>>();
|
||||
logger.LogInformation(
|
||||
"Tile Proxy starting - Upstream: {Upstream}, Cache: {CachePath}",
|
||||
options.UpstreamUrl,
|
||||
options.Cache.BasePath);
|
||||
|
||||
app.Run();
|
||||
|
||||
/// <summary>
|
||||
/// Options validator for tile proxy configuration.
|
||||
/// </summary>
|
||||
public sealed class TileProxyOptionsValidator : IValidateOptions<TileProxyOptions>
|
||||
{
|
||||
public ValidateOptionsResult Validate(string? name, TileProxyOptions options)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.UpstreamUrl))
|
||||
{
|
||||
errors.Add("UpstreamUrl is required");
|
||||
}
|
||||
else if (!Uri.TryCreate(options.UpstreamUrl, UriKind.Absolute, out _))
|
||||
{
|
||||
errors.Add("UpstreamUrl must be a valid absolute URI");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.Origin))
|
||||
{
|
||||
errors.Add("Origin is required");
|
||||
}
|
||||
|
||||
if (options.Cache.MaxSizeGb < 0)
|
||||
{
|
||||
errors.Add("Cache.MaxSizeGb cannot be negative");
|
||||
}
|
||||
|
||||
if (options.Cache.CheckpointTtlMinutes < 1)
|
||||
{
|
||||
errors.Add("Cache.CheckpointTtlMinutes must be at least 1");
|
||||
}
|
||||
|
||||
if (options.Request.TimeoutSeconds < 1)
|
||||
{
|
||||
errors.Add("Request.TimeoutSeconds must be at least 1");
|
||||
}
|
||||
|
||||
if (options.Tuf.Enabled && string.IsNullOrWhiteSpace(options.Tuf.Url))
|
||||
{
|
||||
errors.Add("Tuf.Url is required when TUF is enabled");
|
||||
}
|
||||
|
||||
return errors.Count > 0
|
||||
? ValidateOptionsResult.Fail(errors)
|
||||
: ValidateOptionsResult.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user