Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
271
src/Cli/StellaOps.Cli/Commands/Binary/BinaryCommandGroup.cs
Normal file
271
src/Cli/StellaOps.Cli/Commands/Binary/BinaryCommandGroup.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// BinaryCommandGroup.cs
|
||||
// Sprint: SPRINT_3850_0001_0001_oci_storage_cli
|
||||
// Tasks: T3, T4, T5, T6
|
||||
// Description: CLI command group for binary reachability operations.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.CommandLine;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Cli.Extensions;
|
||||
|
||||
namespace StellaOps.Cli.Commands.Binary;
|
||||
|
||||
/// <summary>
|
||||
/// CLI command group for binary reachability operations.
|
||||
/// </summary>
|
||||
internal static class BinaryCommandGroup
|
||||
{
|
||||
internal static Command BuildBinaryCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var binary = new Command("binary", "Binary reachability analysis operations.");
|
||||
|
||||
binary.Add(BuildSubmitCommand(services, verboseOption, cancellationToken));
|
||||
binary.Add(BuildInfoCommand(services, verboseOption, cancellationToken));
|
||||
binary.Add(BuildSymbolsCommand(services, verboseOption, cancellationToken));
|
||||
binary.Add(BuildVerifyCommand(services, verboseOption, cancellationToken));
|
||||
|
||||
return binary;
|
||||
}
|
||||
|
||||
private static Command BuildSubmitCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var graphOption = new Option<string?>("--graph", new[] { "-g" })
|
||||
{
|
||||
Description = "Path to pre-generated rich graph JSON."
|
||||
};
|
||||
|
||||
var binaryOption = new Option<string?>("--binary", new[] { "-b" })
|
||||
{
|
||||
Description = "Path to binary for analysis."
|
||||
};
|
||||
|
||||
var analyzeOption = new Option<bool>("--analyze")
|
||||
{
|
||||
Description = "Generate graph from binary (requires --binary)."
|
||||
};
|
||||
|
||||
var signOption = new Option<bool>("--sign")
|
||||
{
|
||||
Description = "Sign the graph with DSSE attestation."
|
||||
};
|
||||
|
||||
var registryOption = new Option<string?>("--registry", new[] { "-r" })
|
||||
{
|
||||
Description = "OCI registry to push graph (e.g., ghcr.io/myorg/graphs)."
|
||||
};
|
||||
|
||||
var command = new Command("submit", "Submit binary graph for reachability analysis.")
|
||||
{
|
||||
graphOption,
|
||||
binaryOption,
|
||||
analyzeOption,
|
||||
signOption,
|
||||
registryOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
command.SetAction(parseResult =>
|
||||
{
|
||||
var graphPath = parseResult.GetValue(graphOption);
|
||||
var binaryPath = parseResult.GetValue(binaryOption);
|
||||
var analyze = parseResult.GetValue(analyzeOption);
|
||||
var sign = parseResult.GetValue(signOption);
|
||||
var registry = parseResult.GetValue(registryOption);
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return BinaryCommandHandlers.HandleSubmitAsync(
|
||||
services,
|
||||
graphPath,
|
||||
binaryPath,
|
||||
analyze,
|
||||
sign,
|
||||
registry,
|
||||
verbose,
|
||||
cancellationToken);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildInfoCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var hashArg = new Argument<string>("hash")
|
||||
{
|
||||
Description = "Graph digest (e.g., blake3:abc123...)."
|
||||
};
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
{
|
||||
Description = "Output format: text (default), json."
|
||||
}.SetDefaultValue("text").FromAmong("text", "json");
|
||||
|
||||
var command = new Command("info", "Display binary graph information.")
|
||||
{
|
||||
hashArg,
|
||||
formatOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
command.SetAction(parseResult =>
|
||||
{
|
||||
var hash = parseResult.GetValue(hashArg)!;
|
||||
var format = parseResult.GetValue(formatOption)!;
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return BinaryCommandHandlers.HandleInfoAsync(
|
||||
services,
|
||||
hash,
|
||||
format,
|
||||
verbose,
|
||||
cancellationToken);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildSymbolsCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var hashArg = new Argument<string>("hash")
|
||||
{
|
||||
Description = "Graph digest (e.g., blake3:abc123...)."
|
||||
};
|
||||
|
||||
var strippedOnlyOption = new Option<bool>("--stripped-only")
|
||||
{
|
||||
Description = "Show only stripped (heuristic) symbols."
|
||||
};
|
||||
|
||||
var exportedOnlyOption = new Option<bool>("--exported-only")
|
||||
{
|
||||
Description = "Show only exported symbols."
|
||||
};
|
||||
|
||||
var entrypointsOnlyOption = new Option<bool>("--entrypoints-only")
|
||||
{
|
||||
Description = "Show only entrypoint symbols."
|
||||
};
|
||||
|
||||
var searchOption = new Option<string?>("--search", new[] { "-s" })
|
||||
{
|
||||
Description = "Search pattern (supports wildcards, e.g., ssl_*)."
|
||||
};
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
{
|
||||
Description = "Output format: text (default), json."
|
||||
}.SetDefaultValue("text").FromAmong("text", "json");
|
||||
|
||||
var limitOption = new Option<int>("--limit", new[] { "-n" })
|
||||
{
|
||||
Description = "Limit number of results."
|
||||
}.SetDefaultValue(100);
|
||||
|
||||
var command = new Command("symbols", "List symbols from binary graph.")
|
||||
{
|
||||
hashArg,
|
||||
strippedOnlyOption,
|
||||
exportedOnlyOption,
|
||||
entrypointsOnlyOption,
|
||||
searchOption,
|
||||
formatOption,
|
||||
limitOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
command.SetAction(parseResult =>
|
||||
{
|
||||
var hash = parseResult.GetValue(hashArg)!;
|
||||
var strippedOnly = parseResult.GetValue(strippedOnlyOption);
|
||||
var exportedOnly = parseResult.GetValue(exportedOnlyOption);
|
||||
var entrypointsOnly = parseResult.GetValue(entrypointsOnlyOption);
|
||||
var search = parseResult.GetValue(searchOption);
|
||||
var format = parseResult.GetValue(formatOption)!;
|
||||
var limit = parseResult.GetValue(limitOption);
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return BinaryCommandHandlers.HandleSymbolsAsync(
|
||||
services,
|
||||
hash,
|
||||
strippedOnly,
|
||||
exportedOnly,
|
||||
entrypointsOnly,
|
||||
search,
|
||||
format,
|
||||
limit,
|
||||
verbose,
|
||||
cancellationToken);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildVerifyCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var graphOption = new Option<string>("--graph", new[] { "-g" })
|
||||
{
|
||||
Description = "Path to graph file.",
|
||||
IsRequired = true
|
||||
};
|
||||
|
||||
var dsseOption = new Option<string>("--dsse", new[] { "-d" })
|
||||
{
|
||||
Description = "Path to DSSE envelope.",
|
||||
IsRequired = true
|
||||
};
|
||||
|
||||
var publicKeyOption = new Option<string?>("--public-key", new[] { "-k" })
|
||||
{
|
||||
Description = "Path to public key for signature verification."
|
||||
};
|
||||
|
||||
var rekorUrlOption = new Option<string?>("--rekor-url")
|
||||
{
|
||||
Description = "Rekor transparency log URL."
|
||||
};
|
||||
|
||||
var command = new Command("verify", "Verify binary graph attestation.")
|
||||
{
|
||||
graphOption,
|
||||
dsseOption,
|
||||
publicKeyOption,
|
||||
rekorUrlOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
command.SetAction(parseResult =>
|
||||
{
|
||||
var graphPath = parseResult.GetValue(graphOption)!;
|
||||
var dssePath = parseResult.GetValue(dsseOption)!;
|
||||
var publicKey = parseResult.GetValue(publicKeyOption);
|
||||
var rekorUrl = parseResult.GetValue(rekorUrlOption);
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return BinaryCommandHandlers.HandleVerifyAsync(
|
||||
services,
|
||||
graphPath,
|
||||
dssePath,
|
||||
publicKey,
|
||||
rekorUrl,
|
||||
verbose,
|
||||
cancellationToken);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
}
|
||||
356
src/Cli/StellaOps.Cli/Commands/Binary/BinaryCommandHandlers.cs
Normal file
356
src/Cli/StellaOps.Cli/Commands/Binary/BinaryCommandHandlers.cs
Normal file
@@ -0,0 +1,356 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// BinaryCommandHandlers.cs
|
||||
// Sprint: SPRINT_3850_0001_0001_oci_storage_cli
|
||||
// Tasks: T3, T4, T5, T6
|
||||
// Description: Command handlers for binary reachability operations.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace StellaOps.Cli.Commands.Binary;
|
||||
|
||||
/// <summary>
|
||||
/// Command handlers for binary reachability CLI commands.
|
||||
/// </summary>
|
||||
internal static class BinaryCommandHandlers
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'stella binary submit' command.
|
||||
/// </summary>
|
||||
public static async Task<int> HandleSubmitAsync(
|
||||
IServiceProvider services,
|
||||
string? graphPath,
|
||||
string? binaryPath,
|
||||
bool analyze,
|
||||
bool sign,
|
||||
string? registry,
|
||||
bool verbose,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(graphPath) && string.IsNullOrWhiteSpace(binaryPath))
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] Either --graph or --binary must be specified.");
|
||||
return ExitCodes.InvalidArguments;
|
||||
}
|
||||
|
||||
if (analyze && string.IsNullOrWhiteSpace(binaryPath))
|
||||
{
|
||||
AnsiConsole.MarkupLine("[red]Error:[/] --analyze requires --binary.");
|
||||
return ExitCodes.InvalidArguments;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await AnsiConsole.Status()
|
||||
.StartAsync("Submitting binary graph...", async ctx =>
|
||||
{
|
||||
if (analyze)
|
||||
{
|
||||
ctx.Status("Analyzing binary...");
|
||||
AnsiConsole.MarkupLine($"[yellow]Analyzing binary:[/] {binaryPath}");
|
||||
// TODO: Invoke binary analysis service
|
||||
await Task.Delay(100, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(graphPath))
|
||||
{
|
||||
ctx.Status($"Reading graph from {graphPath}...");
|
||||
if (!File.Exists(graphPath))
|
||||
{
|
||||
throw new FileNotFoundException($"Graph file not found: {graphPath}");
|
||||
}
|
||||
|
||||
var graphJson = await File.ReadAllTextAsync(graphPath, cancellationToken);
|
||||
AnsiConsole.MarkupLine($"[green]✓[/] Graph loaded: {graphJson.Length} bytes");
|
||||
}
|
||||
|
||||
if (sign)
|
||||
{
|
||||
ctx.Status("Signing graph with DSSE...");
|
||||
AnsiConsole.MarkupLine("[yellow]Signing:[/] Generating DSSE attestation");
|
||||
// TODO: Invoke signing service
|
||||
await Task.Delay(100, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(registry))
|
||||
{
|
||||
ctx.Status($"Pushing to {registry}...");
|
||||
AnsiConsole.MarkupLine($"[yellow]Pushing:[/] {registry}");
|
||||
// TODO: Invoke OCI push service
|
||||
await Task.Delay(100, cancellationToken);
|
||||
}
|
||||
|
||||
ctx.Status("Submitting to Scanner API...");
|
||||
// TODO: Invoke Scanner API
|
||||
await Task.Delay(100, cancellationToken);
|
||||
});
|
||||
|
||||
var mockDigest = "blake3:abc123def456789...";
|
||||
|
||||
AnsiConsole.MarkupLine($"[green]✓ Graph submitted successfully[/]");
|
||||
AnsiConsole.MarkupLine($" Digest: [cyan]{mockDigest}[/]");
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
logger.LogInformation(
|
||||
"Binary graph submitted: graph={GraphPath}, binary={BinaryPath}, sign={Sign}",
|
||||
graphPath,
|
||||
binaryPath,
|
||||
sign);
|
||||
}
|
||||
|
||||
return ExitCodes.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]Error:[/] {ex.Message}");
|
||||
logger.LogError(ex, "Failed to submit binary graph");
|
||||
return ExitCodes.GeneralError;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'stella binary info' command.
|
||||
/// </summary>
|
||||
public static async Task<int> HandleInfoAsync(
|
||||
IServiceProvider services,
|
||||
string hash,
|
||||
string format,
|
||||
bool verbose,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: Query Scanner API for graph info
|
||||
await Task.Delay(50, cancellationToken);
|
||||
|
||||
var mockInfo = new
|
||||
{
|
||||
Digest = hash,
|
||||
Format = "ELF x86_64",
|
||||
BuildId = "gnu-build-id:5f0c7c3c...",
|
||||
Nodes = 1247,
|
||||
Edges = 3891,
|
||||
Entrypoints = 5,
|
||||
Attestation = "Signed (Rekor #12345678)"
|
||||
};
|
||||
|
||||
if (format == "json")
|
||||
{
|
||||
var json = JsonSerializer.Serialize(mockInfo, JsonOptions);
|
||||
AnsiConsole.WriteLine(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[bold]Binary Graph:[/] {mockInfo.Digest}");
|
||||
AnsiConsole.MarkupLine($"Format: {mockInfo.Format}");
|
||||
AnsiConsole.MarkupLine($"Build-ID: {mockInfo.BuildId}");
|
||||
AnsiConsole.MarkupLine($"Nodes: [cyan]{mockInfo.Nodes}[/]");
|
||||
AnsiConsole.MarkupLine($"Edges: [cyan]{mockInfo.Edges}[/]");
|
||||
AnsiConsole.MarkupLine($"Entrypoints: [cyan]{mockInfo.Entrypoints}[/]");
|
||||
AnsiConsole.MarkupLine($"Attestation: [green]{mockInfo.Attestation}[/]");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
logger.LogInformation("Retrieved graph info for {Hash}", hash);
|
||||
}
|
||||
|
||||
return ExitCodes.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]Error:[/] {ex.Message}");
|
||||
logger.LogError(ex, "Failed to retrieve graph info for {Hash}", hash);
|
||||
return ExitCodes.GeneralError;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'stella binary symbols' command.
|
||||
/// </summary>
|
||||
public static async Task<int> HandleSymbolsAsync(
|
||||
IServiceProvider services,
|
||||
string hash,
|
||||
bool strippedOnly,
|
||||
bool exportedOnly,
|
||||
bool entrypointsOnly,
|
||||
string? search,
|
||||
string format,
|
||||
int limit,
|
||||
bool verbose,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: Query Scanner API for symbols
|
||||
await Task.Delay(50, cancellationToken);
|
||||
|
||||
var mockSymbols = new[]
|
||||
{
|
||||
new { Symbol = "main", Type = "entrypoint", Exported = true, Stripped = false },
|
||||
new { Symbol = "ssl_connect", Type = "function", Exported = true, Stripped = false },
|
||||
new { Symbol = "verify_cert", Type = "function", Exported = false, Stripped = false },
|
||||
new { Symbol = "sub_401234", Type = "function", Exported = false, Stripped = true }
|
||||
};
|
||||
|
||||
var filtered = mockSymbols.AsEnumerable();
|
||||
|
||||
if (strippedOnly)
|
||||
filtered = filtered.Where(s => s.Stripped);
|
||||
if (exportedOnly)
|
||||
filtered = filtered.Where(s => s.Exported);
|
||||
if (entrypointsOnly)
|
||||
filtered = filtered.Where(s => s.Type == "entrypoint");
|
||||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
var pattern = search.Replace("*", ".*");
|
||||
filtered = filtered.Where(s => System.Text.RegularExpressions.Regex.IsMatch(s.Symbol, pattern));
|
||||
}
|
||||
|
||||
var results = filtered.Take(limit).ToArray();
|
||||
|
||||
if (format == "json")
|
||||
{
|
||||
var json = JsonSerializer.Serialize(results, JsonOptions);
|
||||
AnsiConsole.WriteLine(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
var table = new Table();
|
||||
table.AddColumn("Symbol");
|
||||
table.AddColumn("Type");
|
||||
table.AddColumn("Exported");
|
||||
table.AddColumn("Stripped");
|
||||
|
||||
foreach (var sym in results)
|
||||
{
|
||||
table.AddRow(
|
||||
sym.Symbol,
|
||||
sym.Type,
|
||||
sym.Exported ? "[green]yes[/]" : "no",
|
||||
sym.Stripped ? "[yellow]yes[/]" : "no");
|
||||
}
|
||||
|
||||
AnsiConsole.Write(table);
|
||||
AnsiConsole.MarkupLine($"\n[dim]Showing {results.Length} symbols (limit: {limit})[/]");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
logger.LogInformation(
|
||||
"Retrieved {Count} symbols for {Hash}",
|
||||
results.Length,
|
||||
hash);
|
||||
}
|
||||
|
||||
return ExitCodes.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]Error:[/] {ex.Message}");
|
||||
logger.LogError(ex, "Failed to retrieve symbols for {Hash}", hash);
|
||||
return ExitCodes.GeneralError;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'stella binary verify' command.
|
||||
/// </summary>
|
||||
public static async Task<int> HandleVerifyAsync(
|
||||
IServiceProvider services,
|
||||
string graphPath,
|
||||
string dssePath,
|
||||
string? publicKey,
|
||||
string? rekorUrl,
|
||||
bool verbose,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(graphPath))
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]Error:[/] Graph file not found: {graphPath}");
|
||||
return ExitCodes.FileNotFound;
|
||||
}
|
||||
|
||||
if (!File.Exists(dssePath))
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]Error:[/] DSSE envelope not found: {dssePath}");
|
||||
return ExitCodes.FileNotFound;
|
||||
}
|
||||
|
||||
await AnsiConsole.Status()
|
||||
.StartAsync("Verifying attestation...", async ctx =>
|
||||
{
|
||||
ctx.Status("Parsing DSSE envelope...");
|
||||
await Task.Delay(50, cancellationToken);
|
||||
|
||||
ctx.Status("Verifying signature...");
|
||||
// TODO: Invoke signature verification
|
||||
await Task.Delay(100, cancellationToken);
|
||||
|
||||
ctx.Status("Verifying graph digest...");
|
||||
// TODO: Verify graph hash matches predicate
|
||||
await Task.Delay(50, cancellationToken);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(rekorUrl))
|
||||
{
|
||||
ctx.Status("Verifying Rekor inclusion...");
|
||||
// TODO: Verify Rekor transparency log
|
||||
await Task.Delay(100, cancellationToken);
|
||||
}
|
||||
});
|
||||
|
||||
AnsiConsole.MarkupLine("[green]✓ Verification successful[/]");
|
||||
AnsiConsole.MarkupLine(" Signature: [green]Valid[/]");
|
||||
AnsiConsole.MarkupLine(" Graph digest: [green]Matches[/]");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(rekorUrl))
|
||||
{
|
||||
AnsiConsole.MarkupLine($" Rekor: [green]Verified (entry #12345678)[/]");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
logger.LogInformation(
|
||||
"Verified graph attestation: graph={GraphPath}, dsse={DssePath}",
|
||||
graphPath,
|
||||
dssePath);
|
||||
}
|
||||
|
||||
return ExitCodes.Success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[red]✗ Verification failed:[/] {ex.Message}");
|
||||
logger.LogError(ex, "Failed to verify attestation");
|
||||
return ExitCodes.VerificationFailed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ExitCodes
|
||||
{
|
||||
public const int Success = 0;
|
||||
public const int GeneralError = 1;
|
||||
public const int InvalidArguments = 2;
|
||||
public const int FileNotFound = 3;
|
||||
public const int VerificationFailed = 4;
|
||||
}
|
||||
Reference in New Issue
Block a user