zeroclaw 0.1.7

Zero overhead. Zero compromise. 100% Rust. The fastest, smallest AI assistant.
Documentation
// Extracted from ci-run.yml step: Require owner approval for workflow file changes

module.exports = async ({ github, context, core }) => {
    const owner = context.repo.owner;
    const repo = context.repo.repo;
    const prNumber = context.payload.pull_request?.number;
    const prAuthor = context.payload.pull_request?.user?.login?.toLowerCase() || "";
    if (!prNumber) {
      core.setFailed("Missing pull_request context.");
      return;
    }

    const baseOwners = ["theonlyhennygod", "willsarg", "chumyin"];
    const configuredOwners = (process.env.WORKFLOW_OWNER_LOGINS || "")
      .split(",")
      .map((login) => login.trim().toLowerCase())
      .filter(Boolean);
    const ownerAllowlist = [...new Set([...baseOwners, ...configuredOwners])];

    if (ownerAllowlist.length === 0) {
      core.setFailed("Workflow owner allowlist is empty.");
      return;
    }

    core.info(`Workflow owner allowlist: ${ownerAllowlist.join(", ")}`);

    const files = await github.paginate(github.rest.pulls.listFiles, {
      owner,
      repo,
      pull_number: prNumber,
      per_page: 100,
    });

    const workflowFiles = files
      .map((file) => file.filename)
      .filter((name) => name.startsWith(".github/workflows/"));

    if (workflowFiles.length === 0) {
      core.info("No workflow files changed in this PR.");
      return;
    }

    core.info(`Workflow files changed:\n- ${workflowFiles.join("\n- ")}`);

    if (prAuthor && ownerAllowlist.includes(prAuthor)) {
      core.info(`Workflow PR authored by allowlisted owner: @${prAuthor}`);
      return;
    }

    const reviews = await github.paginate(github.rest.pulls.listReviews, {
      owner,
      repo,
      pull_number: prNumber,
      per_page: 100,
    });

    const latestReviewByUser = new Map();
    for (const review of reviews) {
      const login = review.user?.login;
      if (!login) continue;
      latestReviewByUser.set(login.toLowerCase(), review.state);
    }

    const approvedUsers = [...latestReviewByUser.entries()]
      .filter(([, state]) => state === "APPROVED")
      .map(([login]) => login);

    if (approvedUsers.length === 0) {
      core.setFailed("Workflow files changed but no approving review is present.");
      return;
    }

    const ownerApprover = approvedUsers.find((login) => ownerAllowlist.includes(login));
    if (!ownerApprover) {
      core.setFailed(
        `Workflow files changed. Approvals found (${approvedUsers.join(", ")}), but none match workflow owner allowlist.`,
      );
      return;
    }

    core.info(`Workflow owner approval present: @${ownerApprover}`);

};