Problem
When a user calls list_commits specifying a non-default branch (e.g., dev), commits authored by the repo owner are labeled with none:all integrity instead of the expected approved or writer level. This causes the commits to be filtered out when the agent's min-integrity is set to approved (the public-repo default).
Example log entry for a blocked commit:
{
"tool_name": "list_commits",
"author_login": "ahmadabdalla",
"integrity_tags": ["none:all"],
"reason": "...lower integrity than agent requires...\"approved\""
}
The author is the repo owner on a public personal repository.
Source: github/gh-aw#27473
Analysis
Three compounding issues in guards/github-guard/rust-guard/src/labels/helpers.rs and guards/github-guard/rust-guard/src/labels/response_items.rs:
1. GitHub's list_commits API response does not include author_association
In response_items.rs (line ~15831), the list_commits/get_commit case calls commit_integrity(). Inside commit_integrity() in helpers.rs (~line 64719), the first step is author_association_floor(item, ...), which reads author_association / authorAssociation from the item. For commit items returned by list_commits, the GitHub REST API does not include this field. The function returns an empty vec (i.e., none integrity).
2. elevate_via_collaborator_permission skips personal (non-org) repos
After author_association_floor returns none, commit_integrity calls elevate_via_collaborator_permission() as a fallback for public repos. However, inside that function:
let is_org = super::backend::is_repo_org_owned(owner, repo).unwrap_or(false);
if !is_org {
return integrity; // early return — no elevation for personal repos
}
This guard was added to handle org owners whose author_association incorrectly shows NONE. But because list_commits never provides author_association at all, personal repo owners are equally affected and receive no elevation.
3. is_default_branch_ref hardcodes only main/master/HEAD
In is_default_branch_ref():
pub fn is_default_branch_ref(branch_ref: &str) -> bool {
branch_ref.is_empty()
|| branch_ref.eq_ignore_ascii_case("main")
|| branch_ref.eq_ignore_ascii_case("master")
|| branch_ref.eq_ignore_ascii_case("HEAD")
}
Repos whose actual default branch is named something other than main/master (e.g., trunk, develop) would face the same issue even without specifying a non-default branch. Additionally, list_commits + any SHA is treated as non-default-branch context (see is_default_branch_commit_context).
Net effect: On a public personal repo, list_commits on any non-default branch always produces none integrity for every commit, regardless of authorship.
Relevant files:
guards/github-guard/rust-guard/src/labels/helpers.rs — commit_integrity, elevate_via_collaborator_permission, is_default_branch_ref
guards/github-guard/rust-guard/src/labels/response_items.rs — list_commits / get_commit labeling case (~line 15831)
guards/github-guard/rust-guard/src/labels/mod.rs — test test_default_branch_commit_context_helper
Proposed Solution
Primary fix — lift the is_org guard in elevate_via_collaborator_permission
The collaborator permission endpoint (GET /repos/{owner}/{repo}/collaborators/{username}/permission) works for both personal and org repos. Removing (or relaxing) the is_org early-return allows the function to correctly elevate personal repo owners to writer_integrity:
// Before:
let is_org = super::backend::is_repo_org_owned(owner, repo).unwrap_or(false);
if !is_org {
return integrity;
}
// After: remove the is_org guard entirely, or extend it to non-org repos
// (The original motivation was avoiding extra API calls for personal repos,
// but commits never carry author_association so the fallback is equally needed.)
Secondary fix — owner-login shortcut (avoids extra API call)
As a lightweight alternative (no extra API call), add a check in commit_integrity: if author_login matches the repo owner (the first path segment of repo_full_name) and the repo is public, elevate to at least writer_integrity without needing the collaborator permission API call:
// In commit_integrity(), before calling elevate_via_collaborator_permission:
if !repo_private && !author_login.is_empty() {
let owner = repo_full_name.split('/').next().unwrap_or("");
if author_login.eq_ignore_ascii_case(owner) {
integrity = max_integrity(repo_full_name, integrity, writer_integrity(repo_full_name, ctx), ctx);
}
}
Tertiary fix — query actual repo default branch
For the is_default_branch_ref issue, response_items.rs already fetches the repo visibility via backend::is_repo_private. A similar backend call (backend::get_repo_default_branch) could return the actual default branch name, allowing accurate comparison instead of relying on the hardcoded main/master/HEAD list. This is a lower-priority improvement but would help repos using non-standard default branch names.
Documentation fix
The integrity docs should clarify that commits on non-default branches of public personal repos currently receive none integrity regardless of authorship, and that min-integrity: none is the current workaround until this is fixed.
Testing
- Configure a workflow with
list_commits on a public personal repo's feature branch, as the repo owner.
- Verify that commits authored by the owner get at least
approved (writer) integrity in the integrity_tags log field.
- Run the existing Rust guard unit tests:
cd guards/github-guard/rust-guard && cargo test
- Add a new test case in
mod.rs covering list_commits on a non-default branch for a personal repo where the author is the repo owner, asserting writer_integrity output from commit_integrity.
Generated by Gateway Issue Dispatcher · ● 1.3M · ◷
Problem
When a user calls
list_commitsspecifying a non-default branch (e.g.,dev), commits authored by the repo owner are labeled withnone:allintegrity instead of the expectedapprovedorwriterlevel. This causes the commits to be filtered out when the agent'smin-integrityis set toapproved(the public-repo default).Example log entry for a blocked commit:
{ "tool_name": "list_commits", "author_login": "ahmadabdalla", "integrity_tags": ["none:all"], "reason": "...lower integrity than agent requires...\"approved\"" }The author is the repo owner on a public personal repository.
Source: github/gh-aw#27473
Analysis
Three compounding issues in
guards/github-guard/rust-guard/src/labels/helpers.rsandguards/github-guard/rust-guard/src/labels/response_items.rs:1. GitHub's
list_commitsAPI response does not includeauthor_associationIn
response_items.rs(line ~15831), thelist_commits/get_commitcase callscommit_integrity(). Insidecommit_integrity()inhelpers.rs(~line 64719), the first step isauthor_association_floor(item, ...), which readsauthor_association/authorAssociationfrom the item. For commit items returned bylist_commits, the GitHub REST API does not include this field. The function returns an empty vec (i.e.,noneintegrity).2.
elevate_via_collaborator_permissionskips personal (non-org) reposAfter
author_association_floorreturnsnone,commit_integritycallselevate_via_collaborator_permission()as a fallback for public repos. However, inside that function:This guard was added to handle org owners whose
author_associationincorrectly showsNONE. But becauselist_commitsnever providesauthor_associationat all, personal repo owners are equally affected and receive no elevation.3.
is_default_branch_refhardcodes onlymain/master/HEADIn
is_default_branch_ref():Repos whose actual default branch is named something other than
main/master(e.g.,trunk,develop) would face the same issue even without specifying a non-default branch. Additionally,list_commits+ any SHA is treated as non-default-branch context (seeis_default_branch_commit_context).Net effect: On a public personal repo,
list_commitson any non-default branch always producesnoneintegrity for every commit, regardless of authorship.Relevant files:
guards/github-guard/rust-guard/src/labels/helpers.rs—commit_integrity,elevate_via_collaborator_permission,is_default_branch_refguards/github-guard/rust-guard/src/labels/response_items.rs—list_commits/get_commitlabeling case (~line 15831)guards/github-guard/rust-guard/src/labels/mod.rs— testtest_default_branch_commit_context_helperProposed Solution
Primary fix — lift the
is_orgguard inelevate_via_collaborator_permissionThe collaborator permission endpoint (
GET /repos/{owner}/{repo}/collaborators/{username}/permission) works for both personal and org repos. Removing (or relaxing) theis_orgearly-return allows the function to correctly elevate personal repo owners towriter_integrity:Secondary fix — owner-login shortcut (avoids extra API call)
As a lightweight alternative (no extra API call), add a check in
commit_integrity: ifauthor_loginmatches the repo owner (the first path segment ofrepo_full_name) and the repo is public, elevate to at leastwriter_integritywithout needing the collaborator permission API call:Tertiary fix — query actual repo default branch
For the
is_default_branch_refissue,response_items.rsalready fetches the repo visibility viabackend::is_repo_private. A similar backend call (backend::get_repo_default_branch) could return the actual default branch name, allowing accurate comparison instead of relying on the hardcodedmain/master/HEADlist. This is a lower-priority improvement but would help repos using non-standard default branch names.Documentation fix
The integrity docs should clarify that commits on non-default branches of public personal repos currently receive
noneintegrity regardless of authorship, and thatmin-integrity: noneis the current workaround until this is fixed.Testing
list_commitson a public personal repo's feature branch, as the repo owner.approved(writer) integrity in theintegrity_tagslog field.cd guards/github-guard/rust-guard && cargo testmod.rscoveringlist_commitson a non-default branch for a personal repo where the author is the repo owner, assertingwriter_integrityoutput fromcommit_integrity.