bde042b4d4
Every parity-critical single-item MXAccess command now has a typed session helper instead of only a raw-Invoke escape hatch. Added per client: - Phase 1: AdviseSupervisory, WriteSecured, WriteSecured2, AuthenticateUser, ArchestrAUserToId - Phase 2: AddBufferedItem, SetBufferedUpdateInterval, Suspend, Activate - CLI-30: Unregister (Rust + .NET; Go/Python already had it) Each wraps the existing raw-command machinery (no new wire surface) and runs the same MXAccess-level reply validation (hresult < 0 + MxStatusProxy). MXAccess parity preserved: WriteSecured before AuthenticateUser+AdviseSupervisory surfaces the native failure unchanged (not pre-validated/reordered). Credentials (AuthenticateUser password, WriteSecured payloads) route through each client's secret-redaction seam and never reach logs/exceptions/ToString/Debug/Display; each suite asserts a distinctive credential is absent from surfaced errors. New CLI subcommands source credentials via flag/env, never echoed. - .NET: 21 helpers (validated + Raw), CLI subcommands, multi-secret CLI redactor. Build clean (0 warn), 102 passed. - Go: 9 helpers + *Raw variants, redactSecrets seam, promoted CLI advise-supervisory to typed. gofmt/vet/build/test clean. - Rust: 10 helpers incl. unregister; verified ensure_mxaccess_success runs on secured paths; error.rs credential scrub. fmt/check/test/clippy clean. - Python: 9 async helpers, redact_secret seam + _invoke_redacted, CLI commands. 145 passed. - Shared doc: ClientLibrariesDesign "Typed Command Parity" section. Java client typed parity is batched to windev (no local JRE); CLI-04 + CLI-30 stay open until it lands. Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
32 lines
1.1 KiB
C#
32 lines
1.1 KiB
C#
namespace ZB.MOM.WW.MxGateway.Client.Cli;
|
|
|
|
/// <summary>Utility to redact secrets (API keys, MXAccess credentials) from error messages for safe output.</summary>
|
|
internal static class MxGatewayCliSecretRedactor
|
|
{
|
|
/// <summary>
|
|
/// Replaces every occurrence of any supplied secret in the value with a
|
|
/// redacted placeholder. Null or empty secrets are ignored, so callers can
|
|
/// pass optional credentials without pre-filtering.
|
|
/// </summary>
|
|
/// <param name="value">The message text to redact.</param>
|
|
/// <param name="secrets">The secret values to remove (API key, verify-user password, secured payloads).</param>
|
|
public static string Redact(string value, params string?[] secrets)
|
|
{
|
|
if (string.IsNullOrEmpty(value) || secrets is null)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
string redacted = value;
|
|
foreach (string? secret in secrets)
|
|
{
|
|
if (!string.IsNullOrEmpty(secret))
|
|
{
|
|
redacted = redacted.Replace(secret, "[redacted]", StringComparison.Ordinal);
|
|
}
|
|
}
|
|
|
|
return redacted;
|
|
}
|
|
}
|