up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7810,4 +7810,198 @@ internal static class CommandHandlers
|
||||
}
|
||||
|
||||
private sealed record ProviderInfo(string Name, string Type, IReadOnlyList<CryptoProviderKeyDescriptor> Keys);
|
||||
|
||||
#region Risk Profile Commands
|
||||
|
||||
public static async Task HandleRiskProfileValidateAsync(
|
||||
string inputPath,
|
||||
string format,
|
||||
string? outputPath,
|
||||
bool strict,
|
||||
bool verbose)
|
||||
{
|
||||
_ = verbose;
|
||||
using var activity = CliActivitySource.Instance.StartActivity("cli.riskprofile.validate", ActivityKind.Client);
|
||||
using var duration = CliMetrics.MeasureCommandDuration("risk-profile validate");
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(inputPath))
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] Input file not found: {0}", Markup.Escape(inputPath));
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var profileJson = await File.ReadAllTextAsync(inputPath).ConfigureAwait(false);
|
||||
var schema = StellaOps.Policy.RiskProfile.Schema.RiskProfileSchemaProvider.GetSchema();
|
||||
var schemaVersion = StellaOps.Policy.RiskProfile.Schema.RiskProfileSchemaProvider.GetSchemaVersion();
|
||||
|
||||
JsonNode? profileNode;
|
||||
try
|
||||
{
|
||||
profileNode = JsonNode.Parse(profileJson);
|
||||
if (profileNode is null)
|
||||
{
|
||||
throw new InvalidOperationException("Parsed JSON is null.");
|
||||
}
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] Invalid JSON: {0}", Markup.Escape(ex.Message));
|
||||
Environment.ExitCode = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var result = schema.Evaluate(profileNode);
|
||||
var issues = new List<RiskProfileValidationIssue>();
|
||||
|
||||
if (!result.IsValid)
|
||||
{
|
||||
CollectValidationIssues(result, issues);
|
||||
}
|
||||
|
||||
var report = new RiskProfileValidationReport(
|
||||
FilePath: inputPath,
|
||||
IsValid: result.IsValid,
|
||||
SchemaVersion: schemaVersion,
|
||||
Issues: issues);
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var reportJson = JsonSerializer.Serialize(report, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
await File.WriteAllTextAsync(outputPath, reportJson).ConfigureAwait(false);
|
||||
AnsiConsole.MarkupLine("Validation report written to [cyan]{0}[/]", Markup.Escape(outputPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(reportJson);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.IsValid)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[green]✓[/] Profile is valid (schema v{0})", schemaVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]✗[/] Profile is invalid (schema v{0})", schemaVersion);
|
||||
AnsiConsole.WriteLine();
|
||||
|
||||
var table = new Table();
|
||||
table.AddColumn("Path");
|
||||
table.AddColumn("Error");
|
||||
table.AddColumn("Message");
|
||||
|
||||
foreach (var issue in issues)
|
||||
{
|
||||
table.AddRow(
|
||||
Markup.Escape(issue.Path),
|
||||
Markup.Escape(issue.Error),
|
||||
Markup.Escape(issue.Message));
|
||||
}
|
||||
|
||||
AnsiConsole.Write(table);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
var reportJson = JsonSerializer.Serialize(report, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
});
|
||||
await File.WriteAllTextAsync(outputPath, reportJson).ConfigureAwait(false);
|
||||
AnsiConsole.MarkupLine("Validation report written to [cyan]{0}[/]", Markup.Escape(outputPath));
|
||||
}
|
||||
}
|
||||
|
||||
Environment.ExitCode = result.IsValid ? 0 : (strict ? 1 : 0);
|
||||
if (!result.IsValid && !strict)
|
||||
{
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] {0}", Markup.Escape(ex.Message));
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
|
||||
await Task.CompletedTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task HandleRiskProfileSchemaAsync(string? outputPath, bool verbose)
|
||||
{
|
||||
_ = verbose;
|
||||
using var activity = CliActivitySource.Instance.StartActivity("cli.riskprofile.schema", ActivityKind.Client);
|
||||
using var duration = CliMetrics.MeasureCommandDuration("risk-profile schema");
|
||||
|
||||
try
|
||||
{
|
||||
var schemaText = StellaOps.Policy.RiskProfile.Schema.RiskProfileSchemaProvider.GetSchemaText();
|
||||
var schemaVersion = StellaOps.Policy.RiskProfile.Schema.RiskProfileSchemaProvider.GetSchemaVersion();
|
||||
|
||||
if (!string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
await File.WriteAllTextAsync(outputPath, schemaText).ConfigureAwait(false);
|
||||
AnsiConsole.MarkupLine("Risk profile schema v{0} written to [cyan]{1}[/]", schemaVersion, Markup.Escape(outputPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(schemaText);
|
||||
}
|
||||
|
||||
Environment.ExitCode = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] {0}", Markup.Escape(ex.Message));
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectValidationIssues(
|
||||
Json.Schema.EvaluationResults results,
|
||||
List<RiskProfileValidationIssue> issues,
|
||||
string path = "")
|
||||
{
|
||||
if (results.Errors is not null)
|
||||
{
|
||||
foreach (var (key, message) in results.Errors)
|
||||
{
|
||||
var instancePath = results.InstanceLocation?.ToString() ?? path;
|
||||
issues.Add(new RiskProfileValidationIssue(instancePath, key, message));
|
||||
}
|
||||
}
|
||||
|
||||
if (results.Details is not null)
|
||||
{
|
||||
foreach (var detail in results.Details)
|
||||
{
|
||||
if (!detail.IsValid)
|
||||
{
|
||||
CollectValidationIssues(detail, issues, detail.InstanceLocation?.ToString() ?? path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed record RiskProfileValidationReport(
|
||||
string FilePath,
|
||||
bool IsValid,
|
||||
string SchemaVersion,
|
||||
IReadOnlyList<RiskProfileValidationIssue> Issues);
|
||||
|
||||
private sealed record RiskProfileValidationIssue(string Path, string Error, string Message);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Java/StellaOps.Scanner.Analyzers.Lang.Java.csproj" />
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Env/StellaOps.Scanner.Surface.Env.csproj" />
|
||||
<ProjectReference Include="../../Scanner/__Libraries/StellaOps.Scanner.Surface.Validation/StellaOps.Scanner.Surface.Validation.csproj" />
|
||||
<ProjectReference Include="../../Policy/StellaOps.Policy.RiskProfile/StellaOps.Policy.RiskProfile.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(StellaOpsEnableCryptoPro)' == 'true'">
|
||||
|
||||
Reference in New Issue
Block a user