using System; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using StellaOps.AirGap.Policy; namespace StellaOps.Cli.Configuration; internal sealed class EgressPolicyHttpMessageHandler : DelegatingHandler { private readonly IEgressPolicy? _policy; private readonly ILogger _logger; private readonly string _component; private readonly string _intent; public EgressPolicyHttpMessageHandler(IEgressPolicy? policy, ILogger logger, string component, string intent) { _policy = policy; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _component = string.IsNullOrWhiteSpace(component) ? "stellaops-cli" : component; _intent = string.IsNullOrWhiteSpace(intent) ? "cli-http" : intent; } protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (_policy is null || request.RequestUri is not { IsAbsoluteUri: true } uri) { return base.SendAsync(request, cancellationToken); } try { var egressRequest = new EgressRequest( _component, uri, _intent, operation: request.Method.Method); _policy.EnsureAllowed(egressRequest); } catch (AirGapEgressBlockedException ex) { _logger.LogWarning(ex, "Egress blocked for {Component} when contacting {Destination}", _component, request.RequestUri); throw; } return base.SendAsync(request, cancellationToken); } }