fix(CLI-45): standardize the CLI credential env var and fail fast on empty passwords
All five client CLIs now share one credential contract for `authenticate-user`: flags `--password` / `--password-env` (Go: `-password` / `-password-env`) with default env `MXGATEWAY_VERIFY_PASSWORD`, resolution flag-then-env, and a resolved credential that is missing *or empty* is a usage error naming the flag and the variable. The value is never echoed and never reaches the wire. Go and Java previously sent an empty credential when the variable was unset, turning a misconfigured environment into a real MXAccess authentication attempt. Go now returns the guard error before dialing; Java throws a picocli ParameterException instead of falling back to "". Python's `--password-env` gained the canonical default and its UsageError names the resolved variable. Rust treats an empty flag or env value as missing, with the resolution extracted into a testable `resolve_verify_user_password`. .NET adopts the canonical flags and keeps `--verify-user-password`, `--verify-user-password-env`, and MXGATEWAY_VERIFY_USER_PASSWORD as deprecated aliases for one release. Docs same commit: CrossLanguageSmokeMatrix.md gains the credential contract and the per-CLI subcommand-coverage table (the documented-not-fixed half of the finding); all five READMEs name the canonical variable and the fail-fast rule, and the .NET README carries the deprecation note. Tracking flipped to Done in both remediation registers with a change-log row. No .proto changed; no generated code regenerated.
This commit is contained in:
@@ -598,6 +598,69 @@ func TestRunAuthenticateUserRequiresVerifyUser(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunAuthenticateUserRejectsEmptyPassword pins the CLI-45 fail-fast contract:
|
||||
// an unresolved credential must abort before dialing rather than authenticating
|
||||
// with an empty password, and the usage error must name both -password and the
|
||||
// canonical environment variable without echoing any value.
|
||||
func TestRunAuthenticateUserRejectsEmptyPassword(t *testing.T) {
|
||||
t.Setenv("MXGATEWAY_VERIFY_PASSWORD", "")
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
err := runWithIO(t.Context(), []string{
|
||||
"authenticate-user",
|
||||
"-session-id", "s1",
|
||||
"-verify-user", "operator",
|
||||
"-plaintext",
|
||||
"-api-key", "test",
|
||||
}, &stdout, &stderr)
|
||||
if err == nil {
|
||||
t.Fatal("authenticate-user without a credential must fail before dialing")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "-password") {
|
||||
t.Fatalf("error must name the -password flag: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "MXGATEWAY_VERIFY_PASSWORD") {
|
||||
t.Fatalf("error must name the canonical environment variable: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunAuthenticateUserReadsPasswordFromCanonicalEnv pins that the default
|
||||
// -password-env is MXGATEWAY_VERIFY_PASSWORD: with it set the credential guard
|
||||
// passes and the command proceeds past it to the dial, which fails against an
|
||||
// unused port under a short context — proving the guard was cleared without
|
||||
// needing a live gateway.
|
||||
func TestRunAuthenticateUserReadsPasswordFromCanonicalEnv(t *testing.T) {
|
||||
t.Setenv("MXGATEWAY_VERIFY_PASSWORD", "env-sourced-credential")
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), 200*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
err := runWithIO(ctx, []string{
|
||||
"authenticate-user",
|
||||
"-session-id", "s1",
|
||||
"-verify-user", "operator",
|
||||
"-endpoint", "127.0.0.1:1",
|
||||
"-plaintext",
|
||||
"-api-key", "test",
|
||||
"-call-timeout", "1s",
|
||||
}, &stdout, &stderr)
|
||||
if err == nil {
|
||||
t.Fatal("expected the dial/RPC to fail against an unused port")
|
||||
}
|
||||
if strings.Contains(err.Error(), "flag provided but not defined") {
|
||||
t.Fatalf("test invoked an unknown flag, so it never reached the guard: %v", err)
|
||||
}
|
||||
if strings.Contains(err.Error(), "a password is required") {
|
||||
t.Fatalf("credential guard must be satisfied from %s: %v", "MXGATEWAY_VERIFY_PASSWORD", err)
|
||||
}
|
||||
if strings.Contains(err.Error(), "env-sourced-credential") ||
|
||||
strings.Contains(stdout.String(), "env-sourced-credential") ||
|
||||
strings.Contains(stderr.String(), "env-sourced-credential") {
|
||||
t.Fatal("the resolved credential must never be echoed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunWriteBulkVariantRejectsMismatchedHandlesAndValues pins the len-mismatch
|
||||
// guard so a write-bulk with unequal item-handles / values counts fails fast
|
||||
// before any dial.
|
||||
|
||||
Reference in New Issue
Block a user