Restructure solution layout by module

This commit is contained in:
master
2025-10-28 15:10:40 +02:00
parent 95daa159c4
commit d870da18ce
4103 changed files with 192899 additions and 187024 deletions

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.Extensions.Logging;
namespace StellaOps.Scanner.EntryTrace;
/// <summary>
/// Combines OCI configuration and root filesystem data into the context required by the EntryTrace analyzer.
/// </summary>
public static class EntryTraceImageContextFactory
{
private const string DefaultUser = "root";
public static EntryTraceImageContext Create(
OciImageConfig config,
IRootFileSystem fileSystem,
EntryTraceAnalyzerOptions options,
string imageDigest,
string scanId,
ILogger? logger = null)
{
ArgumentNullException.ThrowIfNull(config);
ArgumentNullException.ThrowIfNull(fileSystem);
ArgumentNullException.ThrowIfNull(options);
ArgumentException.ThrowIfNullOrWhiteSpace(imageDigest);
ArgumentException.ThrowIfNullOrWhiteSpace(scanId);
var environment = BuildEnvironment(config.Environment);
var path = DeterminePath(environment, options);
var workingDir = NormalizeWorkingDirectory(config.WorkingDirectory);
var user = NormalizeUser(config.User);
var context = new EntryTraceContext(
fileSystem,
environment,
path,
workingDir,
user,
imageDigest,
scanId,
logger);
var entrypoint = EntrypointSpecification.FromExecForm(
config.Entrypoint.IsDefaultOrEmpty ? null : config.Entrypoint,
config.Command.IsDefaultOrEmpty ? null : config.Command);
return new EntryTraceImageContext(entrypoint, context);
}
private static ImmutableDictionary<string, string> BuildEnvironment(ImmutableArray<string> raw)
{
if (raw.IsDefaultOrEmpty)
{
return ImmutableDictionary<string, string>.Empty;
}
var dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
foreach (var entry in raw)
{
if (string.IsNullOrWhiteSpace(entry))
{
continue;
}
var separatorIndex = entry.IndexOf('=');
if (separatorIndex < 0)
{
var key = entry.Trim();
if (key.Length > 0)
{
dictionary[key] = string.Empty;
}
continue;
}
var keyPart = entry[..separatorIndex].Trim();
if (keyPart.Length == 0)
{
continue;
}
var valuePart = entry[(separatorIndex + 1)..];
dictionary[keyPart] = valuePart;
}
return ImmutableDictionary.CreateRange(StringComparer.Ordinal, dictionary);
}
private static ImmutableArray<string> DeterminePath(ImmutableDictionary<string, string> env, EntryTraceAnalyzerOptions options)
{
if (env.TryGetValue("PATH", out var pathValue) && !string.IsNullOrWhiteSpace(pathValue))
{
return SplitPath(pathValue);
}
var fallback = string.IsNullOrWhiteSpace(options.DefaultPath)
? EntryTraceDefaults.DefaultPath
: options.DefaultPath;
return SplitPath(fallback);
}
private static string NormalizeWorkingDirectory(string? workingDir)
{
if (string.IsNullOrWhiteSpace(workingDir))
{
return "/";
}
var text = workingDir.Replace('\\', '/').Trim();
if (!text.StartsWith("/", StringComparison.Ordinal))
{
text = "/" + text;
}
if (text.Length > 1 && text.EndsWith("/", StringComparison.Ordinal))
{
text = text.TrimEnd('/');
}
return text.Length == 0 ? "/" : text;
}
private static string NormalizeUser(string? user)
{
if (string.IsNullOrWhiteSpace(user))
{
return DefaultUser;
}
return user.Trim();
}
private static ImmutableArray<string> SplitPath(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return ImmutableArray<string>.Empty;
}
var builder = ImmutableArray.CreateBuilder<string>();
foreach (var segment in value.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (segment.Length == 0)
{
continue;
}
var normalized = segment.Replace('\\', '/');
if (!normalized.StartsWith("/", StringComparison.Ordinal))
{
normalized = "/" + normalized;
}
if (normalized.EndsWith("/", StringComparison.Ordinal) && normalized.Length > 1)
{
normalized = normalized.TrimEnd('/');
}
builder.Add(normalized);
}
return builder.ToImmutable();
}
}
/// <summary>
/// Bundles the resolved entrypoint and context required for the analyzer to operate.
/// </summary>
public sealed record EntryTraceImageContext(
EntrypointSpecification Entrypoint,
EntryTraceContext Context);
internal static class EntryTraceDefaults
{
public const string DefaultPath = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
}