Skip to content

Commit b9f2b46

Browse files
committed
Merge branch 'next' into setMebx
2 parents 62278d8 + 7a26225 commit b9f2b46

10 files changed

Lines changed: 273 additions & 17 deletions

File tree

internal/cli/integration_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ func (pr *prMockSuccess) ReadPassword() (string, error) {
2222
return utils.TestPassword, nil
2323
}
2424

25+
func (pr *prMockSuccess) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
26+
return utils.TestPassword, nil
27+
}
28+
2529
func TestCLIIntegration(t *testing.T) {
2630
// Always mock password prompts in this test suite to avoid EOF on stdin.
2731
oldPR := utils.PR

internal/commands/activate/activate_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,20 @@ func (mpr *MockPasswordReaderSuccess) ReadPassword() (string, error) {
2020
return utils.TestPassword, nil
2121
}
2222

23+
func (mpr *MockPasswordReaderSuccess) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
24+
return utils.TestPassword, nil
25+
}
26+
2327
type MockPasswordReaderFail struct{}
2428

2529
func (mpr *MockPasswordReaderFail) ReadPassword() (string, error) {
2630
return "", errors.New("Read password failed")
2731
}
2832

33+
func (mpr *MockPasswordReaderFail) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
34+
return "", errors.New("Read password failed")
35+
}
36+
2937
func TestActivateCmd_Structure(t *testing.T) {
3038
// Test that ActivateCmd has the correct structure
3139
cmd := &ActivateCmd{}

internal/commands/base.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,36 @@ type AMTBaseCmd struct {
4141
afterApplied bool `kong:"-"`
4242
}
4343

44-
// ValidatePasswordIfNeeded prompts for password if required and not already provided
45-
// EnsureAMTPassword prompts (once) if the command requires an AMT password and ctx.AMTPassword is empty.
44+
// EnsureAMTPassword prompts for an AMT password when required and ctx.AMTPassword is empty.
45+
// For non-activated devices (control mode 0), it also prompts for password confirmation to prevent typos.
4646
func (cmd *AMTBaseCmd) EnsureAMTPassword(ctx *Context, requirer PasswordRequirer) error {
4747
if !requirer.RequiresAMTPassword() {
4848
return nil
4949
}
5050

5151
if strings.TrimSpace(ctx.AMTPassword) != "" {
52-
return nil
52+
return nil // Password already provided, no prompting
5353
}
5454

55-
fmt.Print("AMT Password: ")
55+
var pw string
56+
57+
var err error
58+
59+
// If device not activated (control mode 0), require confirmation
60+
if cmd.ControlMode == 0 {
61+
pw, err = utils.PR.ReadPasswordWithConfirmation("AMT Password: ", "Confirm AMT Password: ")
62+
} else {
63+
fmt.Print("AMT Password: ")
64+
65+
pw, err = utils.PR.ReadPassword()
66+
67+
fmt.Println()
68+
}
5669

57-
pw, err := utils.PR.ReadPassword()
5870
if err != nil {
5971
return fmt.Errorf("failed to read AMT password: %w", err)
6072
}
6173

62-
fmt.Println()
63-
6474
if pw == "" {
6575
return fmt.Errorf("password cannot be empty")
6676
}

internal/commands/base_test.go

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,51 @@ import (
1414

1515
// MockPasswordReader for testing password prompting
1616
type MockPasswordReader struct {
17-
password string
18-
err error
17+
passwords []string // passwords to return in sequence
18+
index int
19+
err error
1920
}
2021

2122
func (m *MockPasswordReader) ReadPassword() (string, error) {
22-
return m.password, m.err
23+
if m.err != nil {
24+
return "", m.err
25+
}
26+
27+
if len(m.passwords) == 0 {
28+
return "", nil
29+
}
30+
31+
pw := m.passwords[m.index]
32+
if m.index < len(m.passwords)-1 {
33+
m.index++
34+
}
35+
36+
return pw, nil
37+
}
38+
39+
func (m *MockPasswordReader) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
40+
if m.err != nil {
41+
return "", m.err
42+
}
43+
44+
if len(m.passwords) < 2 {
45+
// Single password means both are the same (matching)
46+
if len(m.passwords) == 1 {
47+
return m.passwords[0], nil
48+
}
49+
50+
return "", nil
51+
}
52+
53+
pw1 := m.passwords[0]
54+
pw2 := m.passwords[1]
55+
m.index = 2
56+
57+
if pw1 != pw2 {
58+
return "", utils.PasswordsDoNotMatch
59+
}
60+
61+
return pw1, nil
2362
}
2463

2564
// MockPasswordRequirer for testing password requirements
@@ -35,9 +74,10 @@ func TestAMTBaseCmd_EnsureAMTPassword(t *testing.T) {
3574
tests := []struct {
3675
name string
3776
ctxPassword string
38-
mockPassword string
77+
mockPasswords []string
3978
mockError error
4079
requiresPass bool
80+
controlMode int
4181
expectedError bool
4282
expectedPass string
4383
}{
@@ -48,10 +88,25 @@ func TestAMTBaseCmd_EnsureAMTPassword(t *testing.T) {
4888
expectedPass: "existing-password",
4989
},
5090
{
51-
name: "password prompted successfully",
52-
mockPassword: "prompted-password",
53-
requiresPass: true,
54-
expectedPass: "prompted-password",
91+
name: "password prompted successfully - activated device",
92+
mockPasswords: []string{"prompted-password"},
93+
requiresPass: true,
94+
controlMode: 1, // activated (CCM)
95+
expectedPass: "prompted-password",
96+
},
97+
{
98+
name: "password prompted successfully - not activated with matching confirmation",
99+
mockPasswords: []string{"new-password", "new-password"},
100+
requiresPass: true,
101+
controlMode: 0, // not activated
102+
expectedPass: "new-password",
103+
},
104+
{
105+
name: "password mismatch - not activated device",
106+
mockPasswords: []string{"password1", "password2"},
107+
requiresPass: true,
108+
controlMode: 0, // not activated
109+
expectedError: true,
55110
},
56111
{
57112
name: "password prompting fails",
@@ -64,6 +119,13 @@ func TestAMTBaseCmd_EnsureAMTPassword(t *testing.T) {
64119
requiresPass: false,
65120
expectedPass: "",
66121
},
122+
{
123+
name: "activated device ACM - single prompt",
124+
mockPasswords: []string{"acm-password"},
125+
requiresPass: true,
126+
controlMode: 2, // activated (ACM)
127+
expectedPass: "acm-password",
128+
},
67129
}
68130

69131
for _, tt := range tests {
@@ -72,9 +134,9 @@ func TestAMTBaseCmd_EnsureAMTPassword(t *testing.T) {
72134

73135
defer func() { utils.PR = originalPR }()
74136

75-
utils.PR = &MockPasswordReader{password: tt.mockPassword, err: tt.mockError}
137+
utils.PR = &MockPasswordReader{passwords: tt.mockPasswords, err: tt.mockError}
76138

77-
cmd := &AMTBaseCmd{}
139+
cmd := &AMTBaseCmd{ControlMode: tt.controlMode}
78140
ctx := &Context{AMTPassword: tt.ctxPassword}
79141
requirer := &MockPasswordRequirer{requiresPassword: tt.requiresPass}
80142

@@ -89,6 +151,22 @@ func TestAMTBaseCmd_EnsureAMTPassword(t *testing.T) {
89151
}
90152
}
91153

154+
func TestAMTBaseCmd_EnsureAMTPassword_PasswordsDoNotMatch(t *testing.T) {
155+
originalPR := utils.PR
156+
157+
defer func() { utils.PR = originalPR }()
158+
159+
utils.PR = &MockPasswordReader{passwords: []string{"pass1", "pass2"}}
160+
161+
cmd := &AMTBaseCmd{ControlMode: 0} // not activated
162+
ctx := &Context{}
163+
requirer := &MockPasswordRequirer{requiresPassword: true}
164+
165+
err := cmd.EnsureAMTPassword(ctx, requirer)
166+
assert.Error(t, err)
167+
assert.ErrorIs(t, err, utils.PasswordsDoNotMatch)
168+
}
169+
92170
func TestAMTBaseCmd_RequiresAMTPassword(t *testing.T) {
93171
cmd := &AMTBaseCmd{}
94172
assert.True(t, cmd.RequiresAMTPassword(), "AMTBaseCmd should require password by default")

internal/commands/configure/cira_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ type mockPasswordReader struct {
109109

110110
func (m *mockPasswordReader) ReadPassword() (string, error) { return m.password, m.err }
111111

112+
func (m *mockPasswordReader) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
113+
return m.password, m.err
114+
}
115+
112116
func TestCIRACmd_Run(t *testing.T) {
113117
t.Run("successful_cira_configuration", func(t *testing.T) {
114118
ctrl := gomock.NewController(t)

internal/commands/deactivate_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,30 @@ func (mpr *MockPasswordReaderSuccess) ReadPassword() (string, error) {
2222
return utils.TestPassword, nil
2323
}
2424

25+
func (mpr *MockPasswordReaderSuccess) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
26+
return utils.TestPassword, nil
27+
}
28+
2529
type MockPasswordReaderFail struct{}
2630

2731
func (mpr *MockPasswordReaderFail) ReadPassword() (string, error) {
2832
return "", errors.New("Read password failed")
2933
}
3034

35+
func (mpr *MockPasswordReaderFail) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
36+
return "", errors.New("Read password failed")
37+
}
38+
3139
type MockPasswordReaderEmpty struct{}
3240

3341
func (mpr *MockPasswordReaderEmpty) ReadPassword() (string, error) {
3442
return "", nil
3543
}
3644

45+
func (mpr *MockPasswordReaderEmpty) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
46+
return "", nil
47+
}
48+
3749
func TestDeactivateCmd_Validate(t *testing.T) {
3850
tests := []struct {
3951
name string

internal/rps/message_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@ func (mpr *MockPasswordReaderSuccess) ReadPassword() (string, error) {
2727
return utils.TestPassword, nil
2828
}
2929

30+
func (mpr *MockPasswordReaderSuccess) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
31+
return utils.TestPassword, nil
32+
}
33+
3034
type MockPasswordReaderFail struct{}
3135

3236
func (mpr *MockPasswordReaderFail) ReadPassword() (string, error) {
3337
return "", errors.New("Read password failed")
3438
}
3539

40+
func (mpr *MockPasswordReaderFail) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
41+
return "", errors.New("Read password failed")
42+
}
43+
3644
// Mock the AMT Hardware
3745
type MockAMT struct{}
3846

pkg/smb/samba_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,20 @@ func (mpr *MockPasswordReaderSuccess) ReadPassword() (string, error) {
2525
return utils.TestPassword, nil
2626
}
2727

28+
func (mpr *MockPasswordReaderSuccess) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
29+
return utils.TestPassword, nil
30+
}
31+
2832
type MockPasswordReaderFail struct{}
2933

3034
func (mpr *MockPasswordReaderFail) ReadPassword() (string, error) {
3135
return "", errors.New("Read password failed")
3236
}
3337

38+
func (mpr *MockPasswordReaderFail) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
39+
return "", errors.New("Read password failed")
40+
}
41+
3442
func TestParseURL(t *testing.T) {
3543
service := NewSambaService(MockPRSuccess)
3644
curUser, err := user.Current()

pkg/utils/passwordReader.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package utils
66

77
import (
88
"bufio"
9+
"fmt"
910
"os"
1011

1112
"golang.org/x/term"
@@ -17,6 +18,7 @@ var PR PasswordReader = new(RealPasswordReader)
1718

1819
type PasswordReader interface {
1920
ReadPassword() (string, error)
21+
ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error)
2022
}
2123

2224
type RealPasswordReader struct{}
@@ -37,3 +39,29 @@ func (pr *RealPasswordReader) ReadPassword() (string, error) {
3739
return pass, nil
3840
}
3941
}
42+
43+
func (pr *RealPasswordReader) ReadPasswordWithConfirmation(prompt, confirmPrompt string) (string, error) {
44+
fmt.Print(prompt)
45+
46+
pw1, err := pr.ReadPassword()
47+
if err != nil {
48+
return "", err
49+
}
50+
51+
fmt.Println()
52+
53+
fmt.Print(confirmPrompt)
54+
55+
pw2, err := pr.ReadPassword()
56+
if err != nil {
57+
return "", err
58+
}
59+
60+
fmt.Println()
61+
62+
if pw1 != pw2 {
63+
return "", PasswordsDoNotMatch
64+
}
65+
66+
return pw1, nil
67+
}

0 commit comments

Comments
 (0)