feat: normalize bot names for allowed_bots validation

- Strip [bot] suffix from both actor names and allowed bot list for comparison
- Allow both "dependabot" and "dependabot[bot]" formats in allowed_bots input
- Display normalized bot names in error messages for consistency
- Add comprehensive test coverage for both naming formats

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Yuku Kotani
2025-08-06 14:24:17 +09:00
parent 28cc702619
commit bd0b40e98e
2 changed files with 40 additions and 11 deletions

View File

@@ -25,12 +25,6 @@ export async function checkHumanActor(
if (actorType !== "User") { if (actorType !== "User") {
const allowedBots = githubContext.inputs.allowedBots; const allowedBots = githubContext.inputs.allowedBots;
// Parse allowed bots list
const allowedBotsList = allowedBots
.split(",")
.map((bot) => bot.trim().toLowerCase())
.filter((bot) => bot.length > 0);
// Check if all bots are allowed // Check if all bots are allowed
if (allowedBots.trim() === "*") { if (allowedBots.trim() === "*") {
console.log( console.log(
@@ -39,17 +33,30 @@ export async function checkHumanActor(
return; return;
} }
// Parse allowed bots list
const allowedBotsList = allowedBots
.split(",")
.map((bot) =>
bot
.trim()
.toLowerCase()
.replace(/\[bot\]$/, ""),
)
.filter((bot) => bot.length > 0);
const botName = githubContext.actor.toLowerCase().replace(/\[bot\]$/, "");
// Check if specific bot is allowed // Check if specific bot is allowed
if (allowedBotsList.includes(githubContext.actor.toLowerCase())) { if (allowedBotsList.includes(botName)) {
console.log( console.log(
`Bot ${githubContext.actor} is in allowed list, skipping human actor check`, `Bot ${botName} is in allowed list, skipping human actor check`,
); );
return; return;
} }
// Bot not allowed // Bot not allowed
throw new Error( throw new Error(
`Workflow initiated by non-human actor: ${githubContext.actor} (type: ${actorType}). Add bot to allowed_bots list or use '*' to allow all bots.`, `Workflow initiated by non-human actor: ${botName} (type: ${actorType}). Add bot to allowed_bots list or use '*' to allow all bots.`,
); );
} }

View File

@@ -35,7 +35,7 @@ describe("checkHumanActor", () => {
context.inputs.allowedBots = ""; context.inputs.allowedBots = "";
await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow( await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow(
"Workflow initiated by non-human actor: test-bot[bot] (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.", "Workflow initiated by non-human actor: test-bot (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.",
); );
}); });
@@ -61,6 +61,17 @@ describe("checkHumanActor", () => {
).resolves.toBeUndefined(); ).resolves.toBeUndefined();
}); });
test("should pass for specific bot when in allowed list (without [bot])", async () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "dependabot[bot]";
context.inputs.allowedBots = "dependabot,renovate";
await expect(
checkHumanActor(mockOctokit, context),
).resolves.toBeUndefined();
});
test("should throw error for bot not in allowed list", async () => { test("should throw error for bot not in allowed list", async () => {
const mockOctokit = createMockOctokit("Bot"); const mockOctokit = createMockOctokit("Bot");
const context = createMockContext(); const context = createMockContext();
@@ -68,7 +79,18 @@ describe("checkHumanActor", () => {
context.inputs.allowedBots = "dependabot[bot],renovate[bot]"; context.inputs.allowedBots = "dependabot[bot],renovate[bot]";
await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow( await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow(
"Workflow initiated by non-human actor: other-bot[bot] (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.", "Workflow initiated by non-human actor: other-bot (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.",
);
});
test("should throw error for bot not in allowed list (without [bot])", async () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "other-bot[bot]";
context.inputs.allowedBots = "dependabot,renovate";
await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow(
"Workflow initiated by non-human actor: other-bot (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.",
); );
}); });
}); });