diff --git a/src/commands/cli/release/automerge.ts b/src/commands/cli/release/automerge.ts index 50a9f6653..5769b72c9 100644 --- a/src/commands/cli/release/automerge.ts +++ b/src/commands/cli/release/automerge.ts @@ -16,6 +16,16 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-release-management', 'cli.release.automerge'); +/** + * Bot accounts whose PRs are eligible for automerge. Add to this list (via + * reviewed PR) to onboard a new bot. + */ +export const ALLOWED_BOT_USERS = ['svc-cli-bot', 'svc-idee-bot']; + +export function isAllowedBotUser(login: string | undefined | null): boolean { + return !!login && ALLOWED_BOT_USERS.includes(login); +} + type BaseRepoParams = { owner: string; repo: string; @@ -102,8 +112,8 @@ export default class AutoMerge extends SfCommand { stop(`Missing automerge label: [${automergeLabels.join(', ')}]`); } - if (prData.user?.login !== 'svc-cli-bot') { - stop('PR must be created by "svc-cli-bot"'); + if (!isAllowedBotUser(prData.user?.login)) { + stop(`PR must be created by one of: [${ALLOWED_BOT_USERS.join(', ')}]`); } if (!(await this.isGreen(prData, verbose))) { diff --git a/test/commands/cli.release.automerge.test.ts b/test/commands/cli.release.automerge.test.ts new file mode 100644 index 000000000..f409d1e10 --- /dev/null +++ b/test/commands/cli.release.automerge.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ + +import { expect } from 'chai'; +import { ALLOWED_BOT_USERS, isAllowedBotUser } from '../../src/commands/cli/release/automerge.js'; + +describe('cli:release:automerge bot allow-list', () => { + it('accepts svc-cli-bot', () => { + expect(isAllowedBotUser('svc-cli-bot')).to.equal(true); + }); + + it('accepts svc-idee-bot', () => { + expect(isAllowedBotUser('svc-idee-bot')).to.equal(true); + }); + + it('rejects an unknown user', () => { + expect(isAllowedBotUser('random-user')).to.equal(false); + }); + + it('rejects undefined login', () => { + expect(isAllowedBotUser(undefined)).to.equal(false); + }); + + it('rejects null login', () => { + expect(isAllowedBotUser(null)).to.equal(false); + }); + + it('rejects empty string login', () => { + expect(isAllowedBotUser('')).to.equal(false); + }); + + it('exports the canonical allow-list', () => { + expect(ALLOWED_BOT_USERS).to.deep.equal(['svc-cli-bot', 'svc-idee-bot']); + }); +});