-
Notifications
You must be signed in to change notification settings - Fork 20
Use collaborator permission level instead of author_association for integrity filtering #2862
Description
Problem
Integrity filtering currently determines a user's trust level based on the author_association field from GitHub API responses. This field is unreliable for org admins who haven't been explicitly added as collaborators on a specific repository.
How it works today
The Rust guard maps author_association to integrity levels in helpers.rs:960-980:
| author_association | Integrity Level |
|---|---|
| OWNER, MEMBER, COLLABORATOR | approved (writer) |
| CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR | unapproved (reader) |
| FIRST_TIMER, NONE | none |
The bug
GitHub's author_association field reflects the user's direct relationship with the repository, not their effective permissions. An org admin who:
- Has full admin access to a repo via org ownership
- But hasn't been explicitly added as a collaborator
...gets author_association: "CONTRIBUTOR" (if they've contributed before) or "NONE" (if they haven't). This maps to unapproved or none integrity, causing their issues, PRs, and comments to be filtered out by the integrity filter.
This is a fundamental limitation of the GitHub API's author_association field — it doesn't know about org-level permissions.
Impact
- Org admins' content is silently filtered from agentic workflow results
- Users must work around this by explicitly adding themselves as collaborators, using
min-integrity: none, or configuringtrusted-users - The workarounds defeat the purpose of integrity filtering or require per-user configuration
Upstream issue
Proposed Solution
Supplement author_association with a call to the collaborator permission endpoint:
GET /repos/{owner}/{repo}/collaborators/{username}/permission
This endpoint returns the user's effective permission level, which correctly includes inherited org permissions:
{
"permission": "admin",
"user": {
"login": "example-user",
"id": 12345
}
}Permission-to-integrity mapping
| Collaborator Permission | Integrity Level |
|---|---|
| admin, maintain, write | approved (writer) |
| read (triage) | unapproved (reader) |
| none | none |
Implementation approach
Option A: Gateway-side enrichment (recommended)
Add a new enrichment call in the gateway proxy (internal/proxy/proxy.go) alongside the existing pull_request_read and issue_read enrichment paths:
- When the Rust guard needs to determine integrity for an issue/PR author, the gateway calls
GET /repos/{owner}/{repo}/collaborators/{username}/permissionusing the enrichment token - Pass the
permissionfield to the guard alongside (or instead of)author_association - The guard uses
permissionas the primary signal, falling back toauthor_associationif the permission call fails (e.g., insufficient token scopes)
This fits naturally into the existing restBackendCaller pattern in proxy.go:274-341.
Option B: Guard-side callback
Extend the WASM guard's backend callback interface to support a new get_collaborator_permission call. The guard would call this from tool_rules.rs when labeling issues/PRs, similar to the existing get_pull_request_facts() and get_issue_author_info() callbacks in backend.rs.
Key considerations
-
Token permissions: The
GET /repos/{owner}/{repo}/collaborators/{username}/permissionendpoint works with the standardGITHUB_TOKENin Actions as long as the query is scoped to the same repository (see gh-aw#23565 comment). No additional token scopes needed. -
Caching: Permission lookups could be cached per
(repo, username)pair for the duration of a session to avoid redundant API calls. -
Fallback: If the permission endpoint returns an error (403, 404), fall back to the existing
author_associationlogic so the feature degrades gracefully. -
Existing precedent: The gh-aw compiler already uses
github.rest.repos.getCollaboratorPermissionLevel()for/slash_commandpermission checks (seecheckRepositoryPermissionin gh-aw'scheck_membership.cjs).
Files that would need changes
internal/proxy/proxy.go— Add enrichment call for collaborator permissionguards/github-guard/rust-guard/src/labels/backend.rs— Addget_collaborator_permissioncallback and data structureguards/github-guard/rust-guard/src/labels/helpers.rs— Addcollaborator_permission_floor()mapping functionguards/github-guard/rust-guard/src/labels/tool_rules.rs— Use permission-based integrity as primary signal for issues/PRs