Add SBOM, symbols, traces, and VEX files for CVE-2022-21661 SQLi case
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images. - Added symbols.json detailing function entry and sink points in the WordPress code. - Included runtime traces for function calls in both reachable and unreachable scenarios. - Developed OpenVEX files indicating vulnerability status and justification for both cases. - Updated README for evaluator harness to guide integration with scanner output.
This commit is contained in:
@@ -18,7 +18,8 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Spectre.Console;
|
||||
using Spectre.Console.Rendering;
|
||||
using StellaOps.Auth.Client;
|
||||
@@ -28,7 +29,8 @@ using StellaOps.Cli.Services;
|
||||
using StellaOps.Cli.Services.Models;
|
||||
using StellaOps.Cli.Services.Models.AdvisoryAi;
|
||||
using StellaOps.Cli.Telemetry;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography.DependencyInjection;
|
||||
using StellaOps.Cryptography.Kms;
|
||||
|
||||
namespace StellaOps.Cli.Commands;
|
||||
@@ -6437,35 +6439,223 @@ internal static class CommandHandlers
|
||||
return source;
|
||||
}
|
||||
|
||||
private static async Task TriggerJobAsync(
|
||||
IBackendOperationsClient client,
|
||||
ILogger logger,
|
||||
string jobKind,
|
||||
IDictionary<string, object?> parameters,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
JobTriggerResult result = await client.TriggerJobAsync(jobKind, parameters, cancellationToken).ConfigureAwait(false);
|
||||
if (result.Success)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(result.Location))
|
||||
{
|
||||
logger.LogInformation("Job accepted. Track status at {Location}.", result.Location);
|
||||
}
|
||||
else if (result.Run is not null)
|
||||
{
|
||||
logger.LogInformation("Job accepted. RunId: {RunId} Status: {Status}", result.Run.RunId, result.Run.Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Job accepted.");
|
||||
}
|
||||
|
||||
Environment.ExitCode = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("Job '{JobKind}' failed: {Message}", jobKind, result.Message);
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static async Task TriggerJobAsync(
|
||||
IBackendOperationsClient client,
|
||||
ILogger logger,
|
||||
string jobKind,
|
||||
IDictionary<string, object?> parameters,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
JobTriggerResult result = await client.TriggerJobAsync(jobKind, parameters, cancellationToken).ConfigureAwait(false);
|
||||
if (result.Success)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(result.Location))
|
||||
{
|
||||
logger.LogInformation("Job accepted. Track status at {Location}.", result.Location);
|
||||
}
|
||||
else if (result.Run is not null)
|
||||
{
|
||||
logger.LogInformation("Job accepted. RunId: {RunId} Status: {Status}", result.Run.RunId, result.Run.Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Job accepted.");
|
||||
}
|
||||
|
||||
Environment.ExitCode = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("Job '{JobKind}' failed: {Message}", jobKind, result.Message);
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static Task HandleCryptoProvidersAsync(
|
||||
IServiceProvider services,
|
||||
bool verbose,
|
||||
bool jsonOutput,
|
||||
string? profileOverride,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var scope = services.CreateScope();
|
||||
var loggerFactory = scope.ServiceProvider.GetRequiredService<ILoggerFactory>();
|
||||
var logger = loggerFactory.CreateLogger("crypto-providers");
|
||||
var verbosity = scope.ServiceProvider.GetRequiredService<VerbosityState>();
|
||||
var previousLevel = verbosity.MinimumLevel;
|
||||
verbosity.MinimumLevel = verbose ? LogLevel.Debug : LogLevel.Information;
|
||||
using var activity = CliActivitySource.Instance.StartActivity("cli.crypto.providers", ActivityKind.Internal);
|
||||
using var duration = CliMetrics.MeasureCommandDuration("crypto providers");
|
||||
|
||||
try
|
||||
{
|
||||
var registry = scope.ServiceProvider.GetService<ICryptoProviderRegistry>();
|
||||
if (registry is null)
|
||||
{
|
||||
logger.LogWarning("Crypto provider registry not available in this environment.");
|
||||
AnsiConsole.MarkupLine("[yellow]Crypto subsystem is not configured in this environment.[/]");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var optionsMonitor = scope.ServiceProvider.GetService<IOptionsMonitor<CryptoProviderRegistryOptions>>();
|
||||
var registryOptions = optionsMonitor?.CurrentValue ?? new CryptoProviderRegistryOptions();
|
||||
var preferredOrder = DeterminePreferredOrder(registryOptions, profileOverride);
|
||||
var providers = registry.Providers
|
||||
.Select(provider => new ProviderInfo(
|
||||
provider.Name,
|
||||
provider.GetType().FullName ?? provider.GetType().Name,
|
||||
DescribeProviderKeys(provider).ToList()))
|
||||
.ToList();
|
||||
|
||||
if (jsonOutput)
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
activeProfile = registryOptions.ActiveProfile,
|
||||
preferredOrder,
|
||||
providers = providers.Select(info => new
|
||||
{
|
||||
info.Name,
|
||||
info.Type,
|
||||
keys = info.Keys.Select(k => new
|
||||
{
|
||||
k.KeyId,
|
||||
k.AlgorithmId,
|
||||
Metadata = k.Metadata
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
Console.WriteLine(JsonSerializer.Serialize(payload, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
}));
|
||||
Environment.ExitCode = 0;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
RenderCryptoProviders(preferredOrder, providers);
|
||||
Environment.ExitCode = 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
verbosity.MinimumLevel = previousLevel;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static void RenderCryptoProviders(
|
||||
IReadOnlyList<string> preferredOrder,
|
||||
IReadOnlyCollection<ProviderInfo> providers)
|
||||
{
|
||||
if (preferredOrder.Count > 0)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[cyan]Preferred order:[/] {0}", Markup.Escape(string.Join(", ", preferredOrder)));
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.MarkupLine("[yellow]Preferred order is not configured; using registration order.[/]");
|
||||
}
|
||||
|
||||
var table = new Table().Border(TableBorder.Rounded);
|
||||
table.AddColumn("Provider");
|
||||
table.AddColumn("Type");
|
||||
table.AddColumn("Keys");
|
||||
|
||||
foreach (var provider in providers)
|
||||
{
|
||||
var keySummary = provider.Keys.Count == 0
|
||||
? "[grey]No signing keys exposed (managed externally).[/]"
|
||||
: string.Join(Environment.NewLine, provider.Keys.Select(FormatDescriptor));
|
||||
|
||||
table.AddRow(
|
||||
Markup.Escape(provider.Name),
|
||||
Markup.Escape(provider.Type),
|
||||
keySummary);
|
||||
}
|
||||
|
||||
AnsiConsole.Write(table);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<CryptoProviderKeyDescriptor> DescribeProviderKeys(ICryptoProvider provider)
|
||||
{
|
||||
if (provider is ICryptoProviderDiagnostics diagnostics)
|
||||
{
|
||||
return diagnostics.DescribeKeys().ToList();
|
||||
}
|
||||
|
||||
var signingKeys = provider.GetSigningKeys();
|
||||
if (signingKeys.Count == 0)
|
||||
{
|
||||
return Array.Empty<CryptoProviderKeyDescriptor>();
|
||||
}
|
||||
|
||||
var descriptors = new List<CryptoProviderKeyDescriptor>(signingKeys.Count);
|
||||
foreach (var signingKey in signingKeys)
|
||||
{
|
||||
var metadata = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["kind"] = signingKey.Kind.ToString(),
|
||||
["createdAt"] = signingKey.CreatedAt.UtcDateTime.ToString("O"),
|
||||
["providerHint"] = signingKey.Reference.ProviderHint
|
||||
};
|
||||
|
||||
if (signingKey.ExpiresAt.HasValue)
|
||||
{
|
||||
metadata["expiresAt"] = signingKey.ExpiresAt.Value.UtcDateTime.ToString("O");
|
||||
}
|
||||
|
||||
foreach (var pair in signingKey.Metadata)
|
||||
{
|
||||
metadata[$"meta.{pair.Key}"] = pair.Value;
|
||||
}
|
||||
|
||||
descriptors.Add(new CryptoProviderKeyDescriptor(
|
||||
provider.Name,
|
||||
signingKey.Reference.KeyId,
|
||||
signingKey.AlgorithmId,
|
||||
metadata));
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> DeterminePreferredOrder(
|
||||
CryptoProviderRegistryOptions? options,
|
||||
string? overrideProfile)
|
||||
{
|
||||
if (options is null)
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(overrideProfile) &&
|
||||
options.Profiles.TryGetValue(overrideProfile, out var profile) &&
|
||||
profile.PreferredProviders.Count > 0)
|
||||
{
|
||||
return profile.PreferredProviders
|
||||
.Where(static provider => !string.IsNullOrWhiteSpace(provider))
|
||||
.Select(static provider => provider.Trim())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return options.ResolvePreferredProviders();
|
||||
}
|
||||
|
||||
private static string FormatDescriptor(CryptoProviderKeyDescriptor descriptor)
|
||||
{
|
||||
if (descriptor.Metadata.Count == 0)
|
||||
{
|
||||
return $"{Markup.Escape(descriptor.KeyId)} ({Markup.Escape(descriptor.AlgorithmId)})";
|
||||
}
|
||||
|
||||
var metadataText = string.Join(
|
||||
", ",
|
||||
descriptor.Metadata.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||
|
||||
return $"{Markup.Escape(descriptor.KeyId)} ({Markup.Escape(descriptor.AlgorithmId)}){Environment.NewLine}[grey]{Markup.Escape(metadataText)}[/]";
|
||||
}
|
||||
|
||||
private sealed record ProviderInfo(string Name, string Type, IReadOnlyList<CryptoProviderKeyDescriptor> Keys);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user