feat(audit): M5.1 audit tree endpoint + CLI audit tree (T8)
Add GET /api/audit/tree endpoint that accepts executionId query param, authenticates via HTTP Basic + LDAP (OperationalAudit permission), calls IAuditLogRepository.GetExecutionTreeAsync, and returns a JSON array of ExecutionTreeNode. Returns 400 for missing/invalid GUID, 401/403 as normal. Add `scadabridge audit tree --execution-id <guid> [--format table|json]` CLI subcommand in AuditCommands.Build(). Adds AuditTreeHelpers with: - BuildUrl: constructs the relative URL + query string - RunTreeAsync: calls the endpoint, dispatches to table or JSON renderer - WriteTable: indented ASCII tree (root → children, [*] marks queried node) - WriteJson: pretty-printed JSON array pass-through Tests: 7 new ManagementService endpoint tests (valid id, empty, 400, 401, 403, Viewer allowed, wrong role), 18 new CLI tests (parse, render, HTTP error codes, JSON output, multi-level indentation, queried-node marker).
This commit is contained in:
@@ -6,13 +6,15 @@ namespace ZB.MOM.WW.ScadaBridge.CLI.Commands;
|
||||
/// <summary>
|
||||
/// The <c>scadabridge audit</c> command group (Audit Log #23 M8). Provides read access to
|
||||
/// the centralized append-only Audit Log via the Bundle B REST endpoints
|
||||
/// (<c>GET /api/audit/query</c>, <c>GET /api/audit/export</c>), plus a v1 no-op
|
||||
/// <c>verify-chain</c> placeholder for the deferred hash-chain tamper-evidence feature.
|
||||
/// (<c>GET /api/audit/query</c>, <c>GET /api/audit/export</c>,
|
||||
/// <c>GET /api/audit/tree</c>), plus a v1 no-op <c>verify-chain</c> placeholder
|
||||
/// for the deferred hash-chain tamper-evidence feature.
|
||||
/// </summary>
|
||||
public static class AuditCommands
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the <c>audit</c> command group with query, export, and verify-chain sub-commands.
|
||||
/// Builds the <c>audit</c> command group with query, export, tree, and verify-chain
|
||||
/// sub-commands.
|
||||
/// </summary>
|
||||
/// <param name="urlOption">Global <c>--url</c> option for the management API endpoint.</param>
|
||||
/// <param name="formatOption">Global <c>--format</c> option for output format.</param>
|
||||
@@ -25,6 +27,7 @@ public static class AuditCommands
|
||||
|
||||
command.Add(BuildQuery(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildExport(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildTree(urlOption, formatOption, usernameOption, passwordOption));
|
||||
command.Add(BuildVerifyChain(urlOption, formatOption, usernameOption, passwordOption));
|
||||
|
||||
return command;
|
||||
@@ -224,6 +227,44 @@ public static class AuditCommands
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildTree(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var executionIdOption = new Option<string>("--execution-id")
|
||||
{
|
||||
Description = "Execution ID (GUID) to look up — may be any node in the chain",
|
||||
Required = true,
|
||||
};
|
||||
|
||||
var cmd = new Command("tree") { Description = "Display the full execution-chain tree for an audit execution" };
|
||||
cmd.Add(executionIdOption);
|
||||
|
||||
cmd.SetAction(async (ParseResult result) =>
|
||||
{
|
||||
var connection = AuditCommandHelpers.ResolveConnection(result, urlOption, usernameOption, passwordOption);
|
||||
if (connection.Error != null)
|
||||
{
|
||||
OutputFormatter.WriteError(connection.Error, connection.ErrorCode!);
|
||||
return 1;
|
||||
}
|
||||
|
||||
var rawId = result.GetValue(executionIdOption);
|
||||
if (!Guid.TryParse(rawId, out var executionId))
|
||||
{
|
||||
OutputFormatter.WriteError(
|
||||
$"Invalid execution ID '{rawId}'. Expected a GUID (e.g. 11111111-1111-1111-1111-111111111111).",
|
||||
"INVALID_ARGUMENT");
|
||||
return 1;
|
||||
}
|
||||
|
||||
var format = AuditCommandHelpers.ResolveFormat(result, formatOption);
|
||||
|
||||
using var client = new ManagementHttpClient(connection.Url!, connection.Username!, connection.Password!);
|
||||
return await AuditTreeHelpers.RunTreeAsync(client, executionId, format, Console.Out);
|
||||
});
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private static Command BuildVerifyChain(Option<string> urlOption, Option<string> formatOption, Option<string> usernameOption, Option<string> passwordOption)
|
||||
{
|
||||
var monthOption = new Option<string>("--month") { Description = "Month to verify (YYYY-MM)", Required = true };
|
||||
|
||||
Reference in New Issue
Block a user