Skip to content

[SPIKE] Expand FGP per-tool permission annotations + consolidate docs#2679

Draft
SamMorrowDrums wants to merge 5 commits into
sammorrowdrums/fgp-requirementsfrom
sammorrowdrums/fgp-expand-permission-annotations
Draft

[SPIKE] Expand FGP per-tool permission annotations + consolidate docs#2679
SamMorrowDrums wants to merge 5 commits into
sammorrowdrums/fgp-requirementsfrom
sammorrowdrums/fgp-expand-permission-annotations

Conversation

@SamMorrowDrums

@SamMorrowDrums SamMorrowDrums commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Note

Stacked on #2676. Base branch is sammorrowdrums/fgp-requirements, not main. Review #2676 first. This PR only adds per-tool RequiredPermissions annotations and the docs they generate — it changes no runtime behaviour.

What this does

Expands the per-tool fine-grained-permission (FGP) RequiredPermissions annotations introduced by #2676 across the clearly-mappable tools, then regenerates the docs that are built from those annotations.

The pipeline is the same as the existing scope-filtering docs:

annotate ServerTool definitions (source of truth)
        │
        ▼
script/generate-docs  →  docs/permissions-filtering.md  (between the
                          <!-- START/END AUTOMATED PERMISSIONS --> markers)
  • The single source of truth is each tool's .WithPermissions(permissions.Require(...)) annotation on its ServerTool.
  • The table in docs/permissions-filtering.md is generated, never hand-edited. Re-running the generator is idempotent (zero diff on a second run).
  • The list-permissions CLI reads the same inventory, so it stays consistent with the table.
  • Per-tool FGP clutter was removed from the README/tool docs; a static NOTE (outside the generated markers) links to docs/permissions-filtering.md.

How the permissions were verified

Per-tool requirements were verified against the GitHub REST docs' embedded fine-grained permissions — the rendered "The fine-grained token must have the following permission set: …" line on each endpoint's docs page (from the page's progAccess.permissions). Only the public OpenAPI (api.github.com.json) omits this data; the docs pages carry it, so they are the source used here. Only GraphQL-only tools (ProjectsV2, issue-fields) lack a docs-REST source and remain best-guess or ungated.

Semantics (from #2676): a requirement is an OR of AND-sets. permissions.Require(a, b) is a single AND-set (the token needs a and b). Reads map to *:read, mutations to *:write.

Guardrails held: only consts that exist in pkg/permissions/catalog_generated.go are used (none invented); the catalog itself is not regenerated (that hits the network — #2676 owns it); genuinely non-FGP tools stay ungated.

Authoritative (verified against the REST docs' embedded permissions)

Toolset Tool Permission
actions actions_get, actions_list, get_job_logs actions:read
actions actions_run_trigger actions:write
code_security get_code_scanning_alert, list_code_scanning_alerts security_events:read
context get_teams, get_team_members members:read
dependabot get_dependabot_alert, list_dependabot_alerts vulnerability_alerts:read
discussions get_discussion, get_discussion_comments, list_discussions, list_discussion_categories discussions:read
discussions discussion_comment_write discussions:write
git get_repository_tree contents:read
issues issue_read, list_issues, get_label issues:read
issues issue_write, add_issue_comment, sub_issue_write issues:write
labels list_label, get_label issues:read
labels label_write issues:write
pull_requests pull_request_read, list_pull_requests pull_requests:read
pull_requests create_pull_request, update_pull_request, pull_request_review_write, add_comment_to_pending_review, add_reply_to_pull_request_comment, update_pull_request_branch pull_requests:write
pull_requests merge_pull_request contents:write
repos get_file_contents, get_commit, list_commits, list_branches, list_tags, get_tag, list_releases, get_latest_release, get_release_by_tag contents:read
repos create_or_update_file, push_files, delete_file, create_branch contents:write
repos list_repository_collaborators metadata:read
repos create_repository administration:write
repos fork_repository administration:write AND contents:read
secret_protection get_secret_scanning_alert, list_secret_scanning_alerts secret_scanning_alerts:read
stargazers list_starred_repositories starring:read
stargazers star_repository, unstar_repository starring:write

Notes on the two asymmetric PR endpoints and the repo-management ones (all docs-verified):

  • merge_pull_requestContents:write only (docs "Merge a pull request"; pull_requests:write is not required, so requiring it would over-hide the tool for a contents-only token).
  • update_pull_request_branchPull requests:write only (docs "Update a pull request branch"; contents:write not required).
  • list_repository_collaboratorsMetadata:read (docs "List repository collaborators").
  • create_repositoryAdministration:write (POST /user/repos and POST /orgs/{org}/repos).
  • fork_repositoryAdministration:write AND Contents:read (docs "Create a fork").
  • star_repository / unstar_repositorystarring:write. (Docs also list Metadata:read, omitted here as the universal baseline — consistent with the rest of the set, which doesn't spell out implicit metadata:read.)

Best-guess (one entry, flagged for review)

Tool Permission Why it's a guess
list_issue_fields issues:read GraphQL-backed (Projects/issue-field API); no REST docs page with embedded FGP to verify against. issues:read is the closest catalog const. Feature-flag-gated, so it appears in list-permissions --toolsets=all but not in the docs table.

Intentionally ungated (no clear public FGP mapping)

Tool(s) Reason
projects_get, projects_list, projects_write ProjectsV2 is GraphQL with no REST docs endpoint to verify; the classic organization_projects const is a poor fit (deprecated, wrong scope shape).
search_* (search_code, search_issues, search_pull_requests, search_repositories, search_users, search_orgs, search_commits) Cross-cutting search; works with baseline token.
get_me Identity/context baseline.
assign_copilot_to_issue, request_copilot_review Copilot / plan-gated, not FGP.
create_gist, get_gist, list_gists, update_gist No matching catalog const for gists.
list_notifications Cross-cutting; notifications const not in catalog.
list_global_security_advisories, get_global_security_advisory, list_repository_security_advisories, list_org_repository_security_advisories Global/public advisory data; no matching catalog const.
list_issue_types Org metadata with no clear FGP mapping.

Validation

  • go build ./...
  • script/generate-docs ✅ — table is 55 rows; second run produces zero diff (idempotent).
  • bin/golangci-lint run ./pkg/github/... ./cmd/... ✅ — 0 issues.
  • go test -race ./... ✅ — all packages pass.
SamMorrowDrums and others added 5 commits June 12, 2026 19:24
Expand RequiredPermissions annotations across the remaining
clearly-mappable tools (discussions, git, issues, labels, pull
requests, repositories/stargazers, and the granular issue/PR write
tools) so the generated fine-grained-permission table in
docs/permissions-filtering.md is comprehensive.

Stop rendering the per-tool "Required Permissions (fine-grained)" line
in the large generated tool listings (README, feature-flags.md,
insiders-features.md): it cluttered those listings. The consolidated
requirement table now lives solely in docs/permissions-filtering.md,
and the README Tools section links to it.

Permission catalog and tool behaviour are unchanged; only annotations
and generated docs are affected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Annotate the remaining clearly-mappable tools with RequiredPermissions and
regenerate the permissions docs table from the tool definitions:

- repos: create_repository, fork_repository (administration:write);
  list_repository_collaborators (administration:read)
- context: get_teams, get_team_members (members:read)
- projects: projects_get/list (organization_projects:read),
  projects_write (organization_projects:write)
- issues: list_issue_fields (issues:read)

list_issue_types stays ungated (org-level issue-type config has no clean
repo/org catalog permission). Docs table grows 50->58 rows and is idempotent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- list_repository_collaborators: administration:read -> metadata:read
  (the list endpoint requires Fine-grained Metadata read; administration
  only covers adding/removing collaborators)
- create_repository, fork_repository: revert to ungated (administration
  mapping is genuinely ambiguous between user- and org-owned repos)
- projects_get/list/write: revert to ungated (ProjectsV2 GraphQL does not
  map cleanly to the classic repository_projects/organization_projects
  catalog consts)

get_teams/get_team_members keep members:read; list_issue_fields keeps
issues:read. Docs table regenerated (idempotent).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The collaborators list endpoint requires write/maintain/admin repo
privileges (and read:org for classic tokens), so it is not a
low-privilege metadata read. administration:read is the better-grounded
best-guess. Docs table regenerated (idempotent).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verify per-tool fine-grained permissions against the GitHub REST docs'
embedded permission sets (progAccess.permissions):

- merge_pull_request: contents:write only (was contents:write AND
  pull_requests:write)
- update_pull_request_branch: pull_requests:write only (was contents:write
  AND pull_requests:write)
- list_repository_collaborators: metadata:read (was administration:read)
- create_repository: re-add administration:write
- fork_repository: re-add administration:write AND contents:read

Regenerate docs/permissions-filtering.md (55 rows; idempotent).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant