using Microsoft.Extensions.Logging; using StellaOps.Excititor.Connectors.Abstractions.Trust; using StellaOps.Excititor.WebService.Contracts; using System; using System.IO; using System.Linq; namespace StellaOps.Excititor.WebService.Services; internal sealed class AirgapSignerTrustService { private readonly ILogger _logger; private readonly string? _metadataPath; private ConnectorSignerMetadataSet? _metadata; public AirgapSignerTrustService(ILogger logger) { _logger = logger; _metadataPath = Environment.GetEnvironmentVariable("STELLAOPS_CONNECTOR_SIGNER_METADATA_PATH"); } public bool Validate(AirgapImportRequest request, out string? errorCode, out string? message) { errorCode = null; message = null; if (string.IsNullOrWhiteSpace(_metadataPath) || !File.Exists(_metadataPath)) { _logger.LogDebug("Airgap signer metadata not configured; skipping trust enforcement."); return true; } _metadata ??= ConnectorSignerMetadataLoader.TryLoad(_metadataPath); if (_metadata is null) { _logger.LogWarning("Failed to load airgap signer metadata from {Path}; allowing import.", _metadataPath); return true; } if (string.IsNullOrWhiteSpace(request.Publisher)) { errorCode = "AIRGAP_SOURCE_UNTRUSTED"; message = "publisher is required for trust enforcement."; return false; } if (!_metadata.TryGet(request.Publisher, out var connector)) { errorCode = "AIRGAP_SOURCE_UNTRUSTED"; message = $"Publisher '{request.Publisher}' is not present in trusted signer metadata."; return false; } if (connector.Revoked) { errorCode = "AIRGAP_SOURCE_UNTRUSTED"; message = $"Publisher '{request.Publisher}' is revoked."; return false; } if (connector.Bundle?.Digest is { } digest && !string.IsNullOrWhiteSpace(digest)) { if (!string.Equals(digest.Trim(), request.PayloadHash?.Trim(), StringComparison.OrdinalIgnoreCase)) { errorCode = "AIRGAP_PAYLOAD_MISMATCH"; message = "Payload hash does not match trusted bundle digest."; return false; } } // Basic sanity: ensure at least one signer entry exists. if (connector.Signers.IsDefaultOrEmpty || connector.Signers.Sum(s => s.Fingerprints.Length) == 0) { errorCode = "AIRGAP_SOURCE_UNTRUSTED"; message = $"Publisher '{request.Publisher}' has no trusted signers configured."; return false; } return true; } }