fix(#5421): authorize stop-fix via collaborator permission API#5467
Conversation
PR Summary by QodoHarden stop-fix authorization using collaborator permission API
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
|
🤖 Review · |
Site previewPreview: https://96f013e8-site.fullsend-ai.workers.dev Commit: |
Code Review by Qodo
1.
|
0d7836b to
02dc6bb
Compare
|
🤖 Finished Review · ✅ Success · Started 3:17 PM UTC · Completed 3:34 PM UTC |
ReviewFindingsMedium
Low
Previous runReviewFindingsMedium
Low
Labels: PR fixes authorization logic in dispatch shim templates (component/dispatch) and is a bug fix (bug) |
The stop-fix job in the scaffold shim templates gated the /fs-fix-stop command on author_association, including CONTRIBUTOR. GitHub grants CONTRIBUTOR to anyone with a single merged PR, so any external contributor could comment /fs-fix-stop on another user's PR and disable the fix agent without write access — a denial-of-service vector inconsistent with the authorization model established by ADR 0054 (#1688). Move authorization to a collaborator permission API check in the label step (mirroring the has_repo_permission helper in dispatch.yml): the command requires an admin/maintain/write role, with the PR author retaining an escape hatch on their own PR. The runtime check is now the sole authority — the job-level if: no longer gates on author_association at all, so a maintainer whose association is not MEMBER (e.g. private org membership) is no longer filtered out before the authoritative check runs. On API failure the step emits a ::warning:: and falls through to a fail-closed denial. Changes: - Update both shim templates (shim-workflow-call.yaml, shim-per-repo.yaml). - Regenerate this repo's own managed workflow (.github/workflows/fullsend.yaml) from the fixed template so the fullsend repo itself is no longer vulnerable before reconciliation runs. - Add TestShimStopFixAuthorization (static invariants + gate-before-label ordering), TestShimStopFixAuthorizationRuntime (executes the embedded bash against a stubbed gh: author hatch, write approval, read denial, API-failure fail-closed), and TestManagedShimStopFixNotStale (guards against template -> managed-workflow drift). Assisted-by: Claude (fix), Claude (review), Grok (review) Signed-off-by: Wayne Sun <gsun@redhat.com>
02dc6bb to
497dc71
Compare
|
🤖 Finished Review · ✅ Success · Started 3:43 PM UTC · Completed 3:58 PM UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
🤖 Finished Retro · ✅ Success · Started 2:22 PM UTC · Completed 2:36 PM UTC |
Retro: PR #5467 — authorize stop-fix via collaborator permission APITimeline: Issue #5421 was filed 2026-07-21 reporting that the What went well:
Concerns identified (covered by existing issues):
No new proposals. The workflow executed well across all stages. The review agent outperformed the initial human review on this PR, and the concerns identified are already tracked in existing issues. |
Summary
The
stop-fixjob in both scaffold shim templates gated the/fs-fix-stopcommand onauthor_association(includingCONTRIBUTOR). GitHub grantsCONTRIBUTORto anyone with a single merged PR, so any external contributor could comment/fs-fix-stopon another user's PR and disable the fix agent without holding write access — a denial-of-service vector inconsistent with the authorization model established by ADR 0054 (#1688).Related Issue
Fixes #5421
Changes
stop-fixlabel step in bothshim-workflow-call.yamlandshim-per-repo.yaml. The command now requires anadmin/maintain/writerole, mirroring thehas_repo_permissionhelper indispatch.yml.CONTRIBUTORfrom theif:condition as defense in depth (the runtime API check is authoritative).TestShimStopFixAuthorizationcovering both shim templates: noCONTRIBUTORgate, permission API call present,admin|maintain|writerequired, author escape hatch preserved, and labeling gated on the authorization result.Existing repos using the shim will need a reconciliation pass to pick up the fixed templates.
Testing
make lintpasses (staged changes first, then ran)go test ./internal/scaffold/passes)Checklist
!for breaking changes)