Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
// command-authorization.ts (normalize → typed policy + warnings).
import type { ContributorBlacklistEntry } from "../types/manifest-deps-types.js";

// GitHub logins: 1–39 chars, alphanumeric or single hyphens (not leading/trailing). Anything else is dropped so a
// malformed entry can never widen the match or break the close path.
const GITHUB_LOGIN = /^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/;
// GitHub logins: 1–39 chars, alphanumeric or single hyphens (not leading/trailing), plus an optional trailing
// `[bot]` App-actor suffix (e.g. `dependabot[bot]`) so a maintainer can blacklist a repo-specific bot — the same
// login shape auto-close-exempt.ts already accepts for exemptions (#6190). Anything else is dropped so a malformed
// entry can never widen the match or break the close path.
const GITHUB_LOGIN = /^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}(?:\[bot\])?$/;
const MAX_ENTRIES = 1000;
const MAX_REASON_CHARS = 200;
const MAX_EVIDENCE = 10;
Expand Down
15 changes: 15 additions & 0 deletions test/unit/contributor-blacklist-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ describe("normalizeContributorBlacklist (#1425) [engine]", () => {
expect(entries.map((e) => e.login)).toEqual(["a-b", "user123", "a".repeat(39)]);
});

it("accepts a `[bot]`-suffixed App-actor login and enforces it against a matching author (#6190)", () => {
const { entries, warnings } = normalizeContributorBlacklist(["evilbot[bot]", "dependabot[bot]", "github-actions[bot]"]);
expect(entries.map((e) => e.login)).toEqual(["evilbot[bot]", "dependabot[bot]", "github-actions[bot]"]);
expect(warnings).toEqual([]);
expect(isAuthorBlacklisted("evilbot[bot]", entries)).toBe(true);
expect(isAuthorBlacklisted("EvilBot[bot]", entries)).toBe(true);
expect(findBlacklistEntry("dependabot[bot]", entries)?.login).toBe("dependabot[bot]");
expect(isAuthorBlacklisted("innocent[bot]", entries)).toBe(false);
});

it("still drops malformed bot-ish logins (bare `[bot]`, doubled suffix, wrong-case or mid-string brackets)", () => {
const { entries } = normalizeContributorBlacklist(["[bot]", "weird[bot][bot]", "user[Bot]", "a[bot]b"]);
expect(entries).toEqual([]);
});

it("de-duplicates by case-insensitive login, keeping the FIRST (richer) occurrence", () => {
const { entries } = normalizeContributorBlacklist([{ login: "Mona", reason: "first" }, { login: "mona", reason: "second" }]);
expect(entries).toEqual([{ login: "Mona", reason: "first" }]);
Expand Down
16 changes: 16 additions & 0 deletions test/unit/contributor-blacklist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ describe("normalizeContributorBlacklist (#1425)", () => {
expect(entries.map((e) => e.login)).toEqual(["a-b", "user123", "a".repeat(39)]);
});

it("accepts a `[bot]`-suffixed App-actor login and enforces it against a matching author (#6190)", () => {
const { entries, warnings } = normalizeContributorBlacklist(["evilbot[bot]", "dependabot[bot]", "github-actions[bot]"]);
expect(entries.map((e) => e.login)).toEqual(["evilbot[bot]", "dependabot[bot]", "github-actions[bot]"]);
expect(warnings).toEqual([]);
// enforcement path: a PR author with the blacklisted bot login is actually matched (case-insensitively)
expect(isAuthorBlacklisted("evilbot[bot]", entries)).toBe(true);
expect(isAuthorBlacklisted("EvilBot[bot]", entries)).toBe(true);
expect(findBlacklistEntry("dependabot[bot]", entries)?.login).toBe("dependabot[bot]");
expect(isAuthorBlacklisted("innocent[bot]", entries)).toBe(false);
});

it("still drops malformed bot-ish logins (bare `[bot]`, doubled suffix, wrong-case or mid-string brackets)", () => {
const { entries } = normalizeContributorBlacklist(["[bot]", "weird[bot][bot]", "user[Bot]", "a[bot]b"]);
expect(entries).toEqual([]);
});

it("de-duplicates by case-insensitive login, keeping the FIRST (richer) occurrence", () => {
const { entries } = normalizeContributorBlacklist([{ login: "Mona", reason: "first" }, { login: "mona", reason: "second" }]);
expect(entries).toEqual([{ login: "Mona", reason: "first" }]);
Expand Down