diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index fdacecbdf4..f3bf929dd7 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -1015,6 +1015,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issue_comment,issues,workflow_dispatch" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml index 9d34e93bc6..676e352e53 100644 --- a/.github/workflows/auto-triage-issues.lock.yml +++ b/.github/workflows/auto-triage-issues.lock.yml @@ -1072,6 +1072,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues,workflow_dispatch" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/example-custom-error-patterns.lock.yml b/.github/workflows/example-custom-error-patterns.lock.yml index 890c0df337..e20898d296 100644 --- a/.github/workflows/example-custom-error-patterns.lock.yml +++ b/.github/workflows/example-custom-error-patterns.lock.yml @@ -509,6 +509,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index 010f60e827..919447be03 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -1140,6 +1140,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index e33cbc3169..6135f4f130 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -211,6 +211,7 @@ export default defineConfig({ { label: 'MCP Gateway', link: '/reference/mcp-gateway/' }, { label: 'Network Access', link: '/reference/network/' }, { label: 'Permissions', link: '/reference/permissions/' }, + { label: 'Rate Limiting Controls', link: '/reference/rate-limiting-controls/' }, { label: 'Safe Inputs', link: '/reference/safe-inputs/' }, { label: 'Safe Outputs', link: '/reference/safe-outputs/' }, { label: 'Schedule Syntax', link: '/reference/schedule-syntax/' }, diff --git a/docs/src/content/docs/agent-factory-status.mdx b/docs/src/content/docs/agent-factory-status.mdx index 96d79fc6b3..398f7ce702 100644 --- a/docs/src/content/docs/agent-factory-status.mdx +++ b/docs/src/content/docs/agent-factory-status.mdx @@ -144,7 +144,6 @@ These are experimental agentic workflows used by the GitHub Next team to learn, | [Test Create PR Error Handling](https://github.com/github/gh-aw/blob/main/.github/workflows/test-create-pr-error-handling.md) | claude | [![Test Create PR Error Handling](https://github.com/github/gh-aw/actions/workflows/test-create-pr-error-handling.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-create-pr-error-handling.lock.yml) | - | - | | [Test Dispatcher Workflow](https://github.com/github/gh-aw/blob/main/.github/workflows/test-dispatcher.md) | copilot | [![Test Dispatcher Workflow](https://github.com/github/gh-aw/actions/workflows/test-dispatcher.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-dispatcher.lock.yml) | - | - | | [Test Project URL Explicit Requirement](https://github.com/github/gh-aw/blob/main/.github/workflows/test-project-url-default.md) | copilot | [![Test Project URL Explicit Requirement](https://github.com/github/gh-aw/actions/workflows/test-project-url-default.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-project-url-default.lock.yml) | - | - | -| [Test Rate Limiting with Ignored Roles](https://github.com/github/gh-aw/blob/main/.github/workflows/test-rate-limit-ignored-roles.md) | copilot | [![Test Rate Limiting with Ignored Roles](https://github.com/github/gh-aw/actions/workflows/test-rate-limit-ignored-roles.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-rate-limit-ignored-roles.lock.yml) | - | - | | [Test Workflow](https://github.com/github/gh-aw/blob/main/.github/workflows/test-workflow.md) | copilot | [![Test Workflow](https://github.com/github/gh-aw/actions/workflows/test-workflow.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-workflow.lock.yml) | - | - | | [The Daily Repository Chronicle](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-repo-chronicle.md) | copilot | [![The Daily Repository Chronicle](https://github.com/github/gh-aw/actions/workflows/daily-repo-chronicle.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-repo-chronicle.lock.yml) | `0 16 * * 1-5` | - | | [The Great Escapi](https://github.com/github/gh-aw/blob/main/.github/workflows/firewall-escape.md) | copilot | [![The Great Escapi](https://github.com/github/gh-aw/actions/workflows/firewall-escape.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/firewall-escape.lock.yml) | - | - | diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md new file mode 100644 index 0000000000..c45a8e8b1f --- /dev/null +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -0,0 +1,170 @@ +--- +title: Rate Limiting Controls +description: Built-in protections to prevent runaway agentic workflows and exponential growth. +sidebar: + order: 1450 +--- + +GitHub Agentic Workflows uses defense-in-depth to prevent runaway workflows: bot non-triggering, concurrency controls, timeouts, rate limiting, read-only agents, safe output limits, built-in delays, and manual review gates. + +## Bot Non-Triggering + +The `github-actions[bot]` account does not trigger workflow events. When a workflow creates an issue or posts a comment via safe outputs, it won't trigger other workflows - preventing infinite loops. + +```yaml wrap +on: + issues: + types: [opened] +``` + +This workflow won't be triggered by issues created by safe outputs. + +## Concurrency Groups + +Workflows use dual concurrency control: per-workflow (based on context) and per-engine (one agent job at a time per AI engine). + +```yaml wrap +concurrency: + group: gh-aw-${{ github.workflow }} + +jobs: + agent: + concurrency: + group: gh-aw-copilot +``` + +This prevents parallel execution explosions and AI resource exhaustion. See [Concurrency Control](/gh-aw/reference/concurrency/) for trigger-specific patterns. + +## Timeouts + +Jobs have maximum execution times (default: 360 minutes) controlled by the top-level `timeout-minutes` field: + +```yaml wrap +timeout-minutes: 120 # Apply 120-minute timeout to all jobs +``` + +The `stop-after` field provides additional control for when workflows should stop running: + +```yaml wrap +stop-after: +48h # Stop after 48 hours from trigger +``` + +This evaluates in the agent job's `if:` condition, preventing execution if the time limit is exceeded. Supports absolute dates and relative time deltas (minimum unit is hours). + +## Read-Only Agent Tokens + +Agents run with read-only permissions. All write operations (creating issues, posting comments, triggering workflows) go through the [safe outputs system](/gh-aw/reference/safe-outputs/), which provides validation, auditing, and rate limiting. + +```yaml wrap +permissions: + contents: read + issues: read + pull-requests: read +``` + +## Safe Output Limits + +High-risk operations have default max limits to prevent exponential growth: + +| Operation | Default Max | Purpose | +|-----------|-------------|---------| +| `assign-to-agent` | 1 | Prevent agent cascades | +| `assign-to-bot` | 1 | Prevent bot loops | +| `dispatch-workflow` | 1 | Prevent workflow explosions | + +```yaml wrap +safe-outputs: + assign-to-agent: + max: 3 # Override default if needed +``` + +Without limits, one workflow could spawn three agents, each spawning three more, creating exponential growth. The default max of 1 ensures linear progression. + +## Built-In Delays + +Critical operations have hardcoded, non-disableable delays: + +- **Agent assignments**: 10-second delay between each assignment +- **Workflow dispatches**: 5-second delay between each dispatch + +```javascript +// Agent assignment delay +await sleep(10000); // 10 seconds + +// Workflow dispatch delay +await new Promise(resolve => setTimeout(resolve, 5000)); // 5 seconds +``` + +These prevent burst patterns and spread load over time. + +## Manual Review Gates + +Require manual approval for sensitive operations using GitHub Environments: + +```yaml wrap +safe-outputs: + dispatch-workflow: + environment: production # Requires approval +``` + +Configure environments in repository Settings → Environments, add reviewers, then reference the environment name. Use for production dispatches, cross-repo operations, or security-sensitive actions. + +## Rate Limiting Per User + +The `rate-limit` frontmatter field prevents users from triggering workflows too frequently: + +```yaml wrap +rate-limit: + max: 5 # Required: Maximum runs per window (1-10) + window: 60 # Optional: Time window in minutes (default: 60, max: 180) + events: [workflow_dispatch, issue_comment] # Optional: Specific events (auto-inferred if omitted) + ignored-roles: [admin, maintain] # Optional: Roles exempt from rate limiting (default: [admin, maintain, write]) +``` + +The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. + +**Role exemptions**: By default, users with `admin`, `maintain`, or `write` roles are exempt from rate limiting. To apply rate limiting to all users including admins, set `ignored-roles: []`. + +## Example: Multiple Protection Layers + +```yaml wrap +--- +name: Safe Agent Workflow +engine: + id: copilot +timeout-minutes: 60 # Job timeout +on: + issues: + types: [opened] +rate-limit: + max: 5 + window: 60 +stop-after: +2h # Workflow time limit +safe-outputs: + assign-to-agent: + max: 1 + environment: production +--- +``` + +This workflow combines: rate limiting (5/hour per user), concurrency control (one at a time), timeouts (60 min job, 2h workflow), manual approval (environment), and safe output limits (max 1 agent). The bot non-triggering and built-in delays provide additional protection. + +## Best Practices + +Start with conservative limits and increase as needed. Use environments for high-risk operations (workflow dispatches, cross-repo operations, production systems). Layer multiple controls: rate limiting with concurrency, timeouts with stop-after, safe output limits with environments. Monitor workflow runs, safe output logs, and rate limit cancellations to identify needed adjustments. + +## Troubleshooting + +**Workflow immediately cancelled**: Check rate limit in pre-activation logs, verify concurrency queue, or confirm stop-after hasn't exceeded. + +**Agent assignments slow**: Built-in 10-second delays are intentional. Five agents = ~40 seconds total. + +**Workflow dispatch not triggering**: Verify max dispatch limit (default: 1), check 5-second delay, confirm target workflow has `on: workflow_dispatch`, or check pending environment approvals. + +## Related Documentation + +- [Safe Outputs](/gh-aw/reference/safe-outputs/) - Write operations with validation +- [Concurrency Control](/gh-aw/reference/concurrency/) - Execution serialization +- [Frontmatter Reference](/gh-aw/reference/frontmatter/) - Complete configuration options +- [Permissions](/gh-aw/reference/permissions/) - Token scopes and access control +- [GitHub Actions Security](https://docs.github.com/en/actions/security-guides) - GitHub's security guidance