Skip to content

Commit 8f561f6

Browse files
authored
Merge pull request #1372 from salesforcecli/jf/W-21055697
feat: generated passwords default to 20 if unspecified or a lower value is provided @W-21055697@
2 parents 0bc86c1 + f0a1bb7 commit 8f561f6

6 files changed

Lines changed: 62 additions & 22 deletions

File tree

messages/password.generate.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ To see a password that was previously generated, run "org display user".
2525

2626
<%= config.bin %> <%= command.id %>
2727

28-
- Generate a password that contains 12 characters for the original admin user of the scratch org with alias "my-scratch":
28+
- Generate a password that contains 25 characters for the original admin user of the scratch org with alias "my-scratch":
2929

30-
<%= config.bin %> <%= command.id %> --length 12 --target-org my-scratch
30+
<%= config.bin %> <%= command.id %> --length 25 --target-org my-scratch
3131

3232
- Generate a password for your default scratch org admin user that uses lower and upper case letters and numbers only:
3333

@@ -43,7 +43,7 @@ Comma-separated list of usernames or aliases to assign the password to; must hav
4343

4444
# flags.length.summary
4545

46-
Number of characters in the generated password; valid values are between 8 and 100.
46+
Number of characters in the generated password; valid values are between 20 and 100. Default value is 20.
4747

4848
# flags.complexity.summary
4949

@@ -66,6 +66,10 @@ version 51.0 of the Metadata API.
6666
- "features": ["EnableSetPasswordInApi"]
6767
- Then try creating the scratch org again.
6868

69+
# defaultingToLength20Password
70+
71+
Starting in Summer '26, this command will fail if you specify a password length below 20. For now, the command is generating a password of length 20 instead of the requested length.
72+
6973
# scratchFeaturesUrl
7074

7175
see https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_def_file_config_values.htm

src/commands/force/user/password/generate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class ForceUserPasswordGenerateCommand extends UserPasswordGenerateBaseCo
4343
summary: messages.getMessage('flags.length.summary'),
4444
min: 8,
4545
max: 1000,
46-
default: 13,
46+
default: 20,
4747
}),
4848
// the higher the value, the stronger the password
4949
complexity: Flags.integer({

src/commands/org/generate/password.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class GenerateUserPasswordCommand extends UserPasswordGenerateBaseCommand
5050
summary: messages.getMessage('flags.length.summary'),
5151
min: 8,
5252
max: 1000,
53-
default: 13,
53+
default: 20,
5454
}),
5555
// the higher the value, the stronger the password
5656
complexity: Flags.integer({
@@ -66,9 +66,14 @@ export class GenerateUserPasswordCommand extends UserPasswordGenerateBaseCommand
6666

6767
public async run(): Promise<GenerateResult> {
6868
const { flags } = await this.parse(GenerateUserPasswordCommand);
69+
let length: number = flags.length;
70+
if (length < 20) {
71+
this.warn(messages.getMessage('defaultingToLength20Password'));
72+
length = 20;
73+
}
6974
return this.generate({
7075
usernames: ensureArray(flags['on-behalf-of'] ?? flags['target-org'].getUsername()),
71-
length: flags.length,
76+
length,
7277
complexity: flags.complexity,
7378
conn: flags['target-org'].getConnection(flags['api-version']),
7479
});

test/allCommands.nut.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe('verifies all commands run successfully ', () => {
132132
ensureExitCode: 0,
133133
}).jsonOutput?.result;
134134
// testing default length
135-
expect(output?.password?.length).to.equal(13);
135+
expect(output?.password?.length).to.equal(20);
136136
const complexity5Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$|%^&*()[\\]_-])');
137137
// testing default complexity
138138
expect(complexity5Regex.test(output?.password ?? '')).to.be.true;
@@ -142,7 +142,8 @@ describe('verifies all commands run successfully ', () => {
142142
const output = execCmd<{ username: string; password: string }>('org:generate:password --json -l 11 -c 3', {
143143
ensureExitCode: 0,
144144
}).jsonOutput?.result;
145-
expect(output?.password.length).to.equal(11);
145+
// Password length gets overridden to 20
146+
expect(output?.password.length).to.equal(20);
146147
const complexity3Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])');
147148
expect(complexity3Regex.test(output?.password ?? ''));
148149
});
@@ -157,7 +158,8 @@ describe('verifies all commands run successfully ', () => {
157158
ensureExitCode: 0,
158159
}).jsonOutput?.result;
159160

160-
expect(output?.password.length).to.equal(12);
161+
// Password length overridden to 20
162+
expect(output?.password.length).to.equal(20);
161163
const complexity5Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$|%^&*()[\\]_-])');
162164
// testing the default complexity
163165
expect(complexity5Regex.test(output?.password ?? ''));
@@ -168,7 +170,7 @@ describe('verifies all commands run successfully ', () => {
168170
ensureExitCode: 0,
169171
}).jsonOutput?.result;
170172
// testing default length
171-
expect(output?.password.length).to.equal(13);
173+
expect(output?.password.length).to.equal(20);
172174
const complexity3Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])');
173175
expect(complexity3Regex.test(output?.password ?? ''));
174176
});

test/commands/password/generate.test.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import { Connection, Messages, User } from '@salesforce/core';
1818
import { MockTestOrgData, TestContext } from '@salesforce/core/testSetup';
19+
import { stubSfCommandUx } from '@salesforce/sf-plugins-core';
1920
import { assert, expect } from 'chai';
2021
// dirty import to stub something we don't want to export from sfdx-core
2122
import { SecureBuffer } from '../../../node_modules/@salesforce/core/lib/crypto/secureBuffer.js';
@@ -83,16 +84,44 @@ describe('org:generate:password', () => {
8384
expect(result).to.deep.equal(expected);
8485
expect(queryStub.callCount).to.equal(1);
8586
});
86-
it('should generate a new passsword of length 12', async () => {
87-
await prepareStubs(false, false);
88-
const result = (await GenerateUserPasswordCommand.run([
89-
'--target-org',
90-
testOrg.username,
91-
'-l',
92-
'12',
93-
'--json',
94-
])) as PasswordData;
95-
expect(result.password.length).to.equal(12);
87+
88+
describe('--length handling', () => {
89+
it('when no length is specified, password should default to length 20', async () => {
90+
await prepareStubs(false, false);
91+
const result = (await GenerateUserPasswordCommand.run([
92+
'--target-org',
93+
testOrg.username,
94+
'--json',
95+
])) as PasswordData;
96+
97+
expect(result.password.length).to.equal(20);
98+
});
99+
100+
it('when length <20 is specified, logs info-level message and defaults to 20', async () => {
101+
await prepareStubs(false, false);
102+
const uxStubs = stubSfCommandUx($$.SANDBOX);
103+
const result = (await GenerateUserPasswordCommand.run([
104+
'--target-org',
105+
testOrg.username,
106+
'--length',
107+
'12',
108+
'--json',
109+
])) as PasswordData;
110+
expect(result.password.length).to.equal(20);
111+
expect(uxStubs.warn.args.flat()).to.include(messages.getMessage('defaultingToLength20Password'));
112+
});
113+
114+
it('when length >20 is specified, length is used as-is', async () => {
115+
await prepareStubs(false, false);
116+
const result = (await GenerateUserPasswordCommand.run([
117+
'--target-org',
118+
testOrg.username,
119+
'--length',
120+
'50',
121+
'--json',
122+
])) as PasswordData;
123+
expect(result.password.length).to.equal(50);
124+
});
96125
});
97126
it('should throw the correct error with warning message', async () => {
98127
await prepareStubs(true);

test/forceCommands.nut.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ describe('verifies legacy force commands run successfully ', () => {
135135
ensureExitCode: 0,
136136
}).jsonOutput?.result;
137137
// testing default length
138-
expect(output?.password?.length).to.equal(13);
138+
expect(output?.password?.length).to.equal(20);
139139
const complexity5Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$|%^&*()[\\]_-])');
140140
// testing default complexity
141141
expect(complexity5Regex.test(output?.password ?? '')).to.be.true;
@@ -177,7 +177,7 @@ describe('verifies legacy force commands run successfully ', () => {
177177
}
178178
).jsonOutput?.result;
179179
// testing default length
180-
expect(output?.password.length).to.equal(13);
180+
expect(output?.password.length).to.equal(20);
181181
const complexity3Regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])');
182182
expect(complexity3Regex.test(output?.password ?? ''));
183183
});

0 commit comments

Comments
 (0)