feat: Initialize Zastava Webhook service with TLS and Authority authentication
- Added Program.cs to set up the web application with Serilog for logging, health check endpoints, and a placeholder admission endpoint. - Configured Kestrel server to use TLS 1.3 and handle client certificates appropriately. - Created StellaOps.Zastava.Webhook.csproj with necessary dependencies including Serilog and Polly. - Documented tasks in TASKS.md for the Zastava Webhook project, outlining current work and exit criteria for each task.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Plugin;
|
||||
using StellaOps.Plugin.Hosting;
|
||||
using StellaOps.Scanner.Analyzers.OS.Abstractions;
|
||||
using StellaOps.Scanner.Core.Security;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.OS.Plugin;
|
||||
|
||||
public sealed class OsAnalyzerPluginCatalog
|
||||
{
|
||||
private readonly ILogger<OsAnalyzerPluginCatalog> _logger;
|
||||
private readonly IPluginCatalogGuard _guard;
|
||||
private readonly ConcurrentDictionary<string, Assembly> _assemblies = new(StringComparer.OrdinalIgnoreCase);
|
||||
private IReadOnlyList<IOSAnalyzerPlugin> _plugins = Array.Empty<IOSAnalyzerPlugin>();
|
||||
|
||||
public OsAnalyzerPluginCatalog(IPluginCatalogGuard guard, ILogger<OsAnalyzerPluginCatalog> logger)
|
||||
{
|
||||
_guard = guard ?? throw new ArgumentNullException(nameof(guard));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<IOSAnalyzerPlugin> Plugins => _plugins;
|
||||
|
||||
public void LoadFromDirectory(string directory, bool seal = true)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(directory);
|
||||
var fullDirectory = Path.GetFullPath(directory);
|
||||
|
||||
var options = new PluginHostOptions
|
||||
{
|
||||
PluginsDirectory = fullDirectory,
|
||||
EnsureDirectoryExists = false,
|
||||
RecursiveSearch = false,
|
||||
};
|
||||
options.SearchPatterns.Add("StellaOps.Scanner.Analyzers.*.dll");
|
||||
|
||||
var result = PluginHost.LoadPlugins(options, _logger);
|
||||
if (result.Plugins.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("No OS analyzer plug-ins discovered under '{Directory}'.", fullDirectory);
|
||||
}
|
||||
|
||||
foreach (var descriptor in result.Plugins)
|
||||
{
|
||||
try
|
||||
{
|
||||
_guard.EnsureRegistrationAllowed(descriptor.AssemblyPath);
|
||||
_assemblies[descriptor.AssemblyPath] = descriptor.Assembly;
|
||||
_logger.LogInformation("Registered OS analyzer plug-in assembly '{Assembly}' from '{Path}'.",
|
||||
descriptor.Assembly.FullName,
|
||||
descriptor.AssemblyPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to register analyzer plug-in '{Path}'.", descriptor.AssemblyPath);
|
||||
}
|
||||
}
|
||||
|
||||
RefreshPluginList();
|
||||
|
||||
if (seal)
|
||||
{
|
||||
_guard.Seal();
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<IOSPackageAnalyzer> CreateAnalyzers(IServiceProvider services)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
|
||||
if (_plugins.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("No OS analyzer plug-ins available; scanning will skip OS package extraction.");
|
||||
return Array.Empty<IOSPackageAnalyzer>();
|
||||
}
|
||||
|
||||
var analyzers = new List<IOSPackageAnalyzer>(_plugins.Count);
|
||||
foreach (var plugin in _plugins)
|
||||
{
|
||||
if (!IsPluginAvailable(plugin, services))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var analyzer = plugin.CreateAnalyzer(services);
|
||||
if (analyzer is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
analyzers.Add(analyzer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Analyzer plug-in '{Plugin}' failed to create analyzer instance.", plugin.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (analyzers.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("All OS analyzer plug-ins were unavailable.");
|
||||
return Array.Empty<IOSPackageAnalyzer>();
|
||||
}
|
||||
|
||||
analyzers.Sort(static (a, b) => string.CompareOrdinal(a.AnalyzerId, b.AnalyzerId));
|
||||
return new ReadOnlyCollection<IOSPackageAnalyzer>(analyzers);
|
||||
}
|
||||
|
||||
private void RefreshPluginList()
|
||||
{
|
||||
var assemblies = _assemblies.Values.ToArray();
|
||||
var plugins = PluginLoader.LoadPlugins<IOSAnalyzerPlugin>(assemblies);
|
||||
_plugins = plugins is IReadOnlyList<IOSAnalyzerPlugin> list
|
||||
? list
|
||||
: new ReadOnlyCollection<IOSAnalyzerPlugin>(plugins.ToArray());
|
||||
}
|
||||
|
||||
private static bool IsPluginAvailable(IOSAnalyzerPlugin plugin, IServiceProvider services)
|
||||
{
|
||||
try
|
||||
{
|
||||
return plugin.IsAvailable(services);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user