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
113 changes: 56 additions & 57 deletions .github/workflows/ai-moderator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 1 addition & 52 deletions .github/workflows/ai-moderator.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
issue_comment:
types: [created]
lock-for-agent: true
skip-roles: [admin, maintainer, write, triage]
rate-limit:
max: 5
window: 60
Expand All @@ -20,7 +21,6 @@ tools:
mode: local
read-only: true
toolsets: [default]
if: needs.check_external_user.outputs.should_skip != 'true'
permissions:
contents: read
issues: read
Expand All @@ -33,57 +33,6 @@ safe-outputs:
max: 5
allowed-reasons: [spam]
threat-detection: false
jobs:
check_external_user:
runs-on: ubuntu-slim
outputs:
should_skip: ${{ steps.check_actor.outputs.should_skip || github.event_name == 'workflow_dispatch' }}
steps:
- name: Check if actor is external user or GitHub Action bot
id: check_actor
uses: actions/github-script@v8
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
script: |
const actor = context.actor;
const { owner, repo } = context.repo;

// Skip if the issue was opened by GitHub Action bot or Copilot bot
const excludedBots = ['github-actions[bot]', 'github-actions', 'copilot[bot]'];
if (actor.endsWith('[bot]') && excludedBots.includes(actor)) {
core.info(`⏭️ Skipping workflow - issue opened by bot: ${actor}`);
core.setOutput('should_skip', 'true');
return;
}

try {
core.info(`Checking permissions for user: ${actor}`);

// Get the user's permission level
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner,
repo,
username: actor
});

const userPermission = permission.permission;
core.info(`User ${actor} has permission: ${userPermission}`);

// Skip workflow for team members (admin, maintain, write)
const teamPermissions = ['admin', 'maintain', 'write'];
if (teamPermissions.includes(userPermission)) {
core.info(`⏭️ Skipping workflow - ${actor} is a team member with ${userPermission} access`);
core.setOutput('should_skip', 'true');
} else {
core.info(`✅ Running workflow - ${actor} is external user with ${userPermission} access`);
core.setOutput('should_skip', 'false');
}
} catch (error) {
// If we can't determine permission (e.g., user not a collaborator), assume external and run
core.info(`⚠️ Could not determine permissions for ${actor}: ${error.message}`);
core.info(`✅ Running workflow - assuming external user`);
core.setOutput('should_skip', 'false');
}
imports:
- shared/mood.md
---
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bot-detection.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions actions/setup/js/check_skip_roles.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// @ts-check
/// <reference types="@actions/github-script" />

const { checkRepositoryPermission } = require("./check_permissions_utils.cjs");

/**
* Check if the workflow should be skipped based on user's role
* Reads skip-roles from GH_AW_SKIP_ROLES environment variable
* If the user has one of the skip-roles, set skip_roles_ok to false (skip the workflow)
* Otherwise, set skip_roles_ok to true (allow the workflow to proceed)
*/
async function main() {
const { eventName } = context;
const actor = context.actor;
const { owner, repo } = context.repo;

// Parse skip-roles from environment variable
const skipRolesEnv = process.env.GH_AW_SKIP_ROLES;
if (!skipRolesEnv || skipRolesEnv.trim() === "") {
// No skip-roles configured, workflow should proceed
core.info("✅ No skip-roles configured, workflow will proceed");
core.setOutput("skip_roles_ok", "true");
core.setOutput("result", "no_skip_roles");
return;
}

const skipRoles = skipRolesEnv
.split(",")
.map(r => r.trim())
.filter(r => r);
core.info(`Checking if user '${actor}' has any of the skip-roles: ${skipRoles.join(", ")}`);

// Check the user's repository permission
const result = await checkRepositoryPermission(actor, owner, repo, skipRoles);

if (result.error) {
// API error - fail safe and allow the workflow to proceed
core.warning(`⚠️ Repository permission check failed: ${result.error}`);
core.setOutput("skip_roles_ok", "true");
core.setOutput("result", "api_error");
core.setOutput("error_message", `Repository permission check failed: ${result.error}`);
return;
}

if (result.authorized) {
// User has one of the skip-roles, skip the workflow
core.info(`❌ User '${actor}' has role '${result.permission}' which is in skip-roles [${skipRoles.join(", ")}]. Workflow will be skipped.`);
core.setOutput("skip_roles_ok", "false");
core.setOutput("result", "skipped");
core.setOutput("user_permission", result.permission);
core.setOutput("error_message", `Workflow skipped: User '${actor}' has role '${result.permission}' which is in skip-roles: [${skipRoles.join(", ")}]`);
} else {
// User does NOT have any of the skip-roles, allow workflow to proceed
core.info(`✅ User '${actor}' has role '${result.permission}' which is NOT in skip-roles [${skipRoles.join(", ")}]. Workflow will proceed.`);
core.setOutput("skip_roles_ok", "true");
core.setOutput("result", "not_skipped");
core.setOutput("user_permission", result.permission);
}
}

module.exports = { main };
Loading