diff --git a/messages/password.generate.md b/messages/password.generate.md index 8138f64f..cfbc6443 100644 --- a/messages/password.generate.md +++ b/messages/password.generate.md @@ -8,11 +8,8 @@ By default, new scratch orgs contain one admin user with no password. Use this c You can also use the --on-behalf-of flag to generate a password for a scratch org user that you've created locally with the "org create user" command. This command doesn't work for users you created in the scratch org using Setup. -To change the password strength, set the --complexity flag to a value between 0 and 5. Each value specifies the types of characters used in the generated password: +To change the password strength, set the --complexity flag to a value between 3 and 5. Each value specifies the types of characters used in the generated password: -0 - lower case letters only -1 - lower case letters and numbers only -2 - lower case letters and symbols only 3 - lower and upper case letters and numbers only 4 - lower and upper case letters and symbols only 5 - lower and upper case letters and numbers and symbols only @@ -43,7 +40,7 @@ Comma-separated list of usernames or aliases to assign the password to; must hav # flags.length.summary -Number of characters in the generated password; valid values are between 20 and 100. Default value is 20. +Number of characters in the generated password; valid values are between 20 and 1000. Default value is 20. # flags.complexity.summary @@ -66,14 +63,6 @@ version 51.0 of the Metadata API. - "features": ["EnableSetPasswordInApi"] - Then try creating the scratch org again. -# defaultingToLength20Password - -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. - -# defaultingToComplexity3Password - -Starting in Summer '26, this command will fail if you specify a password complexity below 3. For now, the command is generating a password of complexity 3 instead of the requested complexity. - # scratchFeaturesUrl see https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs_def_file_config_values.htm diff --git a/src/commands/force/user/password/generate.ts b/src/commands/force/user/password/generate.ts index b42640ae..f59658c2 100644 --- a/src/commands/force/user/password/generate.ts +++ b/src/commands/force/user/password/generate.ts @@ -41,7 +41,7 @@ export class ForceUserPasswordGenerateCommand extends UserPasswordGenerateBaseCo length: Flags.integer({ char: 'l', summary: messages.getMessage('flags.length.summary'), - min: 8, + min: 20, max: 1000, default: 20, }), @@ -49,7 +49,7 @@ export class ForceUserPasswordGenerateCommand extends UserPasswordGenerateBaseCo complexity: Flags.integer({ char: 'c', summary: messages.getMessage('flags.complexity.summary'), - min: 0, + min: 3, max: 5, default: 5, }), diff --git a/src/commands/org/generate/password.ts b/src/commands/org/generate/password.ts index d71271bf..9cb42342 100644 --- a/src/commands/org/generate/password.ts +++ b/src/commands/org/generate/password.ts @@ -48,7 +48,7 @@ export class GenerateUserPasswordCommand extends UserPasswordGenerateBaseCommand length: Flags.integer({ char: 'l', summary: messages.getMessage('flags.length.summary'), - min: 8, + min: 20, max: 1000, default: 20, }), @@ -56,7 +56,7 @@ export class GenerateUserPasswordCommand extends UserPasswordGenerateBaseCommand complexity: Flags.integer({ char: 'c', summary: messages.getMessage('flags.complexity.summary'), - min: 0, + min: 3, max: 5, default: 5, }), @@ -66,16 +66,7 @@ export class GenerateUserPasswordCommand extends UserPasswordGenerateBaseCommand public async run(): Promise { const { flags } = await this.parse(GenerateUserPasswordCommand); - let length: number = flags.length; - if (length < 20) { - this.warn(messages.getMessage('defaultingToLength20Password')); - length = 20; - } - let complexity: number = flags.complexity; - if (complexity < 3) { - this.warn(messages.getMessage('defaultingToComplexity3Password')); - complexity = 3; - } + const { length, complexity } = flags; return this.generate({ usernames: ensureArray(flags['on-behalf-of'] ?? flags['target-org'].getUsername()), length, diff --git a/test/allCommands.nut.ts b/test/allCommands.nut.ts index 5f72928b..8a1945b9 100644 --- a/test/allCommands.nut.ts +++ b/test/allCommands.nut.ts @@ -158,8 +158,8 @@ describe('verifies all commands run successfully ', () => { ); }); - it('generates new passwords for main user testing length 11 and complexity 5', () => { - const output = execCmd<{ username: string; password: string }>('org:generate:password --json -l 11 -c 5', { + it('generates new passwords for main user testing length 20 and complexity 5', () => { + const output = execCmd<{ username: string; password: string }>('org:generate:password --json -l 20 -c 5', { ensureExitCode: 0, }).jsonOutput?.result; // Password length gets overridden to 20 @@ -188,13 +188,12 @@ describe('verifies all commands run successfully ', () => { expect(output).to.have.property('result').includes.keys(['username', 'password']); }); - it('generates new password for secondary user (onbehalfof) with length 12', () => { - const output = execCmd<{ username: string; password: string }>('org:generate:password -b Other --json -l 12', { + it('generates new password for secondary user (onbehalfof) with length 22', () => { + const output = execCmd<{ username: string; password: string }>('org:generate:password -b Other --json -l 22', { ensureExitCode: 0, }).jsonOutput?.result; - // Password length overridden to 20 - expect(output?.password.length).to.equal(20); + expect(output?.password.length).to.equal(22); // testing the default complexity const passwordAsCharArray = (output?.password ?? '').split(''); expect(passwordAsCharArray.some((c) => digitArray.includes(c))).to.equal( @@ -246,7 +245,7 @@ describe('verifies all commands run successfully ', () => { }); it('generates new password for secondary user (onbehalfof) with length 7 should thrown an error', () => { const output = execCmd('org:generate:password -b Other --json -l 7', { ensureExitCode: 'nonZero' }).jsonOutput; - expect(output?.message).to.include('Expected an integer greater than or equal to 8 but received: 7'); + expect(output?.message).to.include('Expected an integer greater than or equal to 20 but received: 7'); }); it('assigns 2 permsets to the main user', () => { const output = execCmd('org:assign:permset -n PS2 -n PS3 --json', { diff --git a/test/commands/password/generate.test.ts b/test/commands/password/generate.test.ts index 03d295c9..2c2b9b0b 100644 --- a/test/commands/password/generate.test.ts +++ b/test/commands/password/generate.test.ts @@ -119,36 +119,15 @@ describe('org:generate:password', () => { ); }); - it('when complexity <3 is specified, logs warn-level message and defaults to 3', async () => { + it('when complexity <3 is specified, throws a validation error', async () => { await prepareStubs(false, false); - const uxStubs = stubSfCommandUx($$.SANDBOX); - const result = (await GenerateUserPasswordCommand.run([ - '--target-org', - testOrg.username, - '--complexity', - '2', - '--json', - ])) as PasswordData; - - const passwordAsCharArray: string[] = result.password.split(''); - - expect(passwordAsCharArray.some((c) => digitArray.includes(c))).to.equal( - true, - 'complexity 3 passwords have digits' - ); - expect(passwordAsCharArray.some((c) => upperArray.includes(c))).to.equal( - true, - 'complexity 3 passwords have uppercase chars' - ); - expect(passwordAsCharArray.some((c) => lowerArray.includes(c))).to.equal( - true, - 'complexity 3 passwords have lowercase chars' - ); - expect(passwordAsCharArray.some((c) => symbolArray.includes(c))).to.equal( - false, - 'complexity 3 passwords do not have symbols' - ); - expect(uxStubs.warn.args.flat()).to.include(messages.getMessage('defaultingToComplexity3Password')); + try { + await GenerateUserPasswordCommand.run(['--target-org', testOrg.username, '--complexity', '2', '--json']); + expect.fail('should have thrown an error'); + } catch (result) { + assert(result instanceof Error); + expect(result.message).to.include('Expected an integer greater than or equal to 3'); + } }); it('when complexity >=3 is specified, complexity is used as-is', async () => { @@ -198,18 +177,15 @@ describe('org:generate:password', () => { expect(result.password.length).to.equal(20); }); - it('when length <20 is specified, logs warn-level message and defaults to 20', async () => { + it('when length <20 is specified, throws a validation error', async () => { await prepareStubs(false, false); - const uxStubs = stubSfCommandUx($$.SANDBOX); - const result = (await GenerateUserPasswordCommand.run([ - '--target-org', - testOrg.username, - '--length', - '12', - '--json', - ])) as PasswordData; - expect(result.password.length).to.equal(20); - expect(uxStubs.warn.args.flat()).to.include(messages.getMessage('defaultingToLength20Password')); + try { + await GenerateUserPasswordCommand.run(['--target-org', testOrg.username, '--length', '12', '--json']); + expect.fail('should have thrown an error'); + } catch (result) { + assert(result instanceof Error); + expect(result.message).to.include('Expected an integer greater than or equal to 20'); + } }); it('when length >20 is specified, length is used as-is', async () => { diff --git a/test/forceCommands.nut.ts b/test/forceCommands.nut.ts index e000d9fd..cbe01923 100644 --- a/test/forceCommands.nut.ts +++ b/test/forceCommands.nut.ts @@ -161,11 +161,11 @@ describe('verifies legacy force commands run successfully ', () => { ); }); - it('generates new password for main user testing length 11 and complexity 3', () => { - const output = execCmd<{ username: string; password: string }>('force:user:password:generate --json -l 11 -c 3', { + it('generates new password for main user testing length 20 and complexity 3', () => { + const output = execCmd<{ username: string; password: string }>('force:user:password:generate --json -l 20 -c 3', { ensureExitCode: 0, }).jsonOutput?.result; - expect(output?.password.length).to.equal(11); + expect(output?.password.length).to.equal(20); const passwordAsCharArray = (output?.password ?? '').split(''); expect(passwordAsCharArray.some((c) => digitArray.includes(c))).to.equal( true, @@ -190,15 +190,15 @@ describe('verifies legacy force commands run successfully ', () => { expect(output).to.have.property('result').includes.keys(['username', 'password']); }); - it('generates new password for secondary user (onbehalfof) with length 12', () => { + it('generates new password for secondary user (onbehalfof) with length 30', () => { const output = execCmd<{ username: string; password: string }>( - 'force:user:password:generate -o Other --json -l 12', + 'force:user:password:generate -o Other --json -l 30', { ensureExitCode: 0, } ).jsonOutput?.result; - expect(output?.password.length).to.equal(12); + expect(output?.password.length).to.equal(30); // testing the default complexity const passwordAsCharArray = (output?.password ?? '').split(''); expect(passwordAsCharArray.some((c) => digitArray.includes(c))).to.equal( @@ -253,11 +253,17 @@ describe('verifies legacy force commands run successfully ', () => { }).jsonOutput; expect(output?.message).to.include('Expected an integer less than or equal to 5 but received: 7'); }); + it('generates new password for secondary user (onbehalfof) with complexity 2 should thrown an error', () => { + const output = execCmd('force:user:password:generate -o Other --json -c 2', { + ensureExitCode: 'nonZero', + }).jsonOutput; + expect(output?.message).to.include('Expected an integer greater than or equal to 3 but received: 2'); + }); it('generates new password for secondary user (onbehalfof) with length 7 should thrown an error', () => { const output = execCmd('force:user:password:generate -o Other --json -l 7', { ensureExitCode: 'nonZero', }).jsonOutput; - expect(output?.message).to.include('Expected an integer greater than or equal to 8 but received: 7'); + expect(output?.message).to.include('Expected an integer greater than or equal to 20 but received: 7'); }); it('assigns 2 permsets to the main user', () => { const output = execCmd('force:user:permset:assign -n PS2,PS3 --json', {