From 1c9cc32d284c5c586cc65fdb906cae2bfcdb3dd3 Mon Sep 17 00:00:00 2001 From: bircni Date: Sun, 11 Oct 2026 22:00:29 +0200 Subject: [PATCH] fix(admin): keep must_change_password unless it is passed to user edit --must-change-password defaulted to true on admin user edit as well, so changing a password with --password silently forced the user to change it again at the next sign-in. On edit the flag now defaults to unset and is sent only when passed; create keeps requiring a change by default. Signed-off-by: bircni --- internal/app/admin_users.go | 6 +++--- internal/app/admin_users_test.go | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/internal/app/admin_users.go b/internal/app/admin_users.go index 33e9906e..1c87deaf 100644 --- a/internal/app/admin_users.go +++ b/internal/app/admin_users.go @@ -73,7 +73,7 @@ func (a *application) adminCommand() *cobra.Command { } command.Flags().StringVar(&password, "password", "", "Password (prefer --password-file)") command.Flags().StringVar(&passwordFile, "password-file", "", "Read password from file or - for stdin; remove one trailing line ending") - command.Flags().BoolVar(&mustChangePassword, "must-change-password", true, "Require password change on next sign-in (use =false to disable)") + command.Flags().BoolVar(&mustChangePassword, "must-change-password", verb == "create", "Require password change on next sign-in (use =false to disable)") } command.RunE = func(cmd *cobra.Command, args []string) error { if verb == "create" { @@ -161,8 +161,8 @@ func (a *application) adminCommand() *cobra.Command { return clierr.Wrap(clierr.Usage, errors.New("password cannot be empty")) } opts.Password = password - opts.MustChangePassword = &mustChangePassword - } else if cmd.Flags().Changed("must-change-password") { + } + if verb == "create" || cmd.Flags().Changed("must-change-password") { opts.MustChangePassword = &mustChangePassword } diff --git a/internal/app/admin_users_test.go b/internal/app/admin_users_test.go index ced85cd8..5ca481e8 100644 --- a/internal/app/admin_users_test.go +++ b/internal/app/admin_users_test.go @@ -38,3 +38,25 @@ func TestAdminPromptAndFlagsReachEquivalentPayloads(t *testing.T) { require.Len(t, prompt.secrets, 2) require.NotContains(t, out.String(), "password") } + +func TestAdminUserEditSetsMustChangePasswordOnlyWhenPassed(t *testing.T) { + var edits []map[string]any + server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPatch { + var payload map[string]any + require.NoError(t, json.NewDecoder(r.Body).Decode(&payload)) + edits = append(edits, payload) + } + _, _ = w.Write([]byte(`{"id":2,"login":"bob"}`)) + })) + defer server.Close() + deps, _, _ := serverDeps(t, server.URL) + for _, flags := range [][]string{{"--password", "new password"}, {"--password", "new password", "--must-change-password"}, {"--must-change-password=false"}} { + require.NoError(t, Execute(context.Background(), deps, append([]string{"admin", "user", "edit", "bob", "--no-input"}, flags...))) + } + require.Len(t, edits, 3) + require.Equal(t, "new password", edits[0]["password"]) + require.Nil(t, edits[0]["must_change_password"]) + require.Equal(t, true, edits[1]["must_change_password"]) + require.Equal(t, false, edits[2]["must_change_password"]) +}