This commit is contained in:
km-anthropic
2025-08-08 09:38:33 -07:00
14 changed files with 170 additions and 5 deletions

96
test/actor.test.ts Normal file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bun
import { describe, test, expect } from "bun:test";
import { checkHumanActor } from "../src/github/validation/actor";
import type { Octokit } from "@octokit/rest";
import { createMockContext } from "./mockContext";
function createMockOctokit(userType: string): Octokit {
return {
users: {
getByUsername: async () => ({
data: {
type: userType,
},
}),
},
} as unknown as Octokit;
}
describe("checkHumanActor", () => {
test("should pass for human actor", async () => {
const mockOctokit = createMockOctokit("User");
const context = createMockContext();
context.actor = "human-user";
await expect(
checkHumanActor(mockOctokit, context),
).resolves.toBeUndefined();
});
test("should throw error for bot actor when not allowed", async () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "test-bot[bot]";
context.inputs.allowedBots = "";
await expect(checkHumanActor(mockOctokit, context)).rejects.toThrow(
"Workflow initiated by non-human actor: test-bot (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots.",
);
});
test("should pass for bot actor when all bots allowed", async () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "test-bot[bot]";
context.inputs.allowedBots = "*";
await expect(
checkHumanActor(mockOctokit, context),
).resolves.toBeUndefined();
});
test("should pass for specific bot when in allowed list", async () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "dependabot[bot]";
context.inputs.allowedBots = "dependabot[bot],renovate[bot]";
await expect(
checkHumanActor(mockOctokit, context),
).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 () => {
const mockOctokit = createMockOctokit("Bot");
const context = createMockContext();
context.actor = "other-bot[bot]";
context.inputs.allowedBots = "dependabot[bot],renovate[bot]";
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.",
);
});
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.",
);
});
});

View File

@@ -31,6 +31,7 @@ describe("prepareMcpConfig", () => {
branchPrefix: "",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
};

View File

@@ -18,6 +18,7 @@ const defaultInputs = {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
};
const defaultRepository = {

View File

@@ -67,6 +67,7 @@ describe("checkWritePermissions", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
@@ -120,6 +121,16 @@ describe("checkWritePermissions", () => {
);
});
test("should return true for bot user", async () => {
const mockOctokit = createMockOctokit("none");
const context = createContext();
context.actor = "test-bot[bot]";
const result = await checkWritePermissions(mockOctokit, context);
expect(result).toBe(true);
});
test("should throw error when permission check fails", async () => {
const error = new Error("API error");
const mockOctokit = {

View File

@@ -35,6 +35,7 @@ describe("checkContainsTrigger", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -62,6 +63,7 @@ describe("checkContainsTrigger", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(false);
@@ -273,6 +275,7 @@ describe("checkContainsTrigger", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -301,6 +304,7 @@ describe("checkContainsTrigger", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(true);
@@ -329,6 +333,7 @@ describe("checkContainsTrigger", () => {
branchPrefix: "claude/",
useStickyComment: false,
useCommitSigning: false,
allowedBots: "",
},
});
expect(checkContainsTrigger(context)).toBe(false);