fix(09): WR-13 read admin passwords from a prompt or stdin and deprecate the --password flag

This commit is contained in:
Jakub Zych
2026-10-01 21:20:20 +02:00
parent 331351a73c
commit c9bb14944a
5 changed files with 111 additions and 22 deletions

View File

@@ -226,3 +226,57 @@ func TestAdminCreateRejectsCrossFieldCollision(t *testing.T) {
t.Fatalf("admins after refused creates = %d, %v; want 1", n, err)
}
}
// TestAdminPasswordWithoutFlag pins WR-13: the password can come from stdin
// (the non-terminal path of the prompt) instead of the command line, the
// --password flag still works but warns that it is deprecated, and no password
// at all is refused.
func TestAdminPasswordWithoutFlag(t *testing.T) {
gdb := adminGorm(t)
app := commandApp(t, gdb)
create := commandByName(t, cabana.RuntimeCommands(app), "admin:create")
reset := commandByName(t, cabana.RuntimeCommands(app), "admin:reset-password")
const piped = "password-piped-on-stdin"
var buf bytes.Buffer
out := bonfire.NewOutput(strings.NewReader(piped+"\n"), &buf, &buf)
if err := create.Run(context.Background(), flagInput{flags: map[string]string{"email": "stdin-pw@example.test"}}, out); err != nil {
t.Fatalf("create with the password on stdin: %v", err)
}
var user cabana.BackendUser
if err := gdb.Where("login = ?", "stdin-pw@example.test").First(&user).Error; err != nil {
t.Fatal(err)
}
if !bouncer.CheckPassword(user.Password, piped) {
t.Fatal("password read from stdin was not stored")
}
if strings.Contains(buf.String(), piped) || strings.Contains(buf.String(), "deprecated") {
t.Fatalf("stdin path leaked the password or warned: %s", buf.String())
}
const next = "replacement-piped-on-stdin"
buf.Reset()
out = bonfire.NewOutput(strings.NewReader(next+"\n"), &buf, &buf)
if err := reset.Run(context.Background(), flagInput{args: []string{"stdin-pw@example.test"}}, out); err != nil {
t.Fatalf("reset with the password on stdin: %v", err)
}
if err := gdb.Where("login = ?", "stdin-pw@example.test").First(&user).Error; err != nil || !bouncer.CheckPassword(user.Password, next) {
t.Fatalf("reset did not store the stdin password: %v", err)
}
buf.Reset()
out = bonfire.NewOutput(strings.NewReader(""), &buf, &buf)
err := reset.Run(context.Background(), flagInput{args: []string{"stdin-pw@example.test"}}, out)
if err == nil || !strings.Contains(err.Error(), "password is required") {
t.Fatalf("reset with no password err = %v", err)
}
buf.Reset()
out = bonfire.NewOutput(strings.NewReader(""), &buf, &buf)
if err := reset.Run(context.Background(), flagInput{args: []string{"stdin-pw@example.test"}, flags: map[string]string{"password": "flag-password-value"}}, out); err != nil {
t.Fatalf("reset with the deprecated flag: %v", err)
}
if !strings.Contains(buf.String(), "deprecated") || strings.Contains(buf.String(), "flag-password-value") {
t.Fatalf("deprecated flag output = %s", buf.String())
}
}