Skip to content

[SPIKE] Add declarative fine-grained permission (FGP) requirement subsystem#2676

Draft
SamMorrowDrums wants to merge 1 commit into
mainfrom
sammorrowdrums/fgp-requirements
Draft

[SPIKE] Add declarative fine-grained permission (FGP) requirement subsystem#2676
SamMorrowDrums wants to merge 1 commit into
mainfrom
sammorrowdrums/fgp-requirements

Conversation

@SamMorrowDrums

Copy link
Copy Markdown
Collaborator

Summary

SPIKE / DRAFT — iterating, not final. Adds a declarative fine-grained-permission (FGP) requirement subsystem to MCP tools, mirroring the existing pkg/scopes subsystem, so this OSS repo becomes the public source of truth for which fine-grained permission each tool needs. A separate remote server consumes this mapping to hide tools a caller's token cannot use; that runtime/grant-source piece is out of scope here — the subsystem ships dormant in OSS.

Guardrail honored

Only public data is used. The catalog is generated solely from the public github/rest-api-description (components/schemas/app-permissions). No internal sources are referenced.

What's implemented

New pkg/permissions package (leaf, stdlib-only — mirrors pkg/scopes)

  • permissions.go: typed Permission, Level (Read<Write<Admin lattice), Scope (Repo/Org/Account), PermReq, and Requirement (OR-of-AND). Combinators: Require, AllOf, AnyOf, (r).And(other), SatisfiedBy, Permissions, IsZero, String. Ergonomic Permission.Read()/.Write()/.Admin() + ParseLevel. Normalizes/dedupes for deterministic output.
  • catalog.go + catalog_generated.go: CatalogEntry (scope + valid levels) and the generated Catalog (54 permissions; enterprise excluded).
  • gen.go: //go:build ignore generator reading ONLY the public spec (go generate ./pkg/permissions).
  • map.go: ToolPermissionMap, global get/set, UniquePermissions.

Wiring

  • inventory.ServerTool gains RequiredPermissions permissions.Requirement + chainable WithPermissions(r). Zero value = no gate (always shown). NewTool/NewToolFromHandler signatures unchanged.
  • pkg/github/permission_filter.go: GetToolPermissionMapFromInventory, SetToolPermissionMapFromInventory, UnionPermissions, and CreateToolPermissionFilter(granted) which fails open on nil granted (OSS has no granted source).

Seed per-tool requirements (high-signal subset; everything else left ungated): issues, pull requests, contents (file/branch/commit/tag), actions, code scanning (security_events), secret scanning (secret_scanning_alerts), dependabot (vulnerability_alerts).

Docs & CLI

  • writeToolDoc emits a Required Permissions (fine-grained) line; new docs/permissions-filtering.md with a generated table between <!-- START/END AUTOMATED PERMISSIONS -->; linked from README + docs/server-configuration.md.
  • New list-permissions CLI + script/list-permissions (text/json/summary).
  • Unit tests for the combinators/lattice/catalog and the fail-open filter.

Deviations / stubbed (spike findings)

  • Catalog source: the public spec does not carry structured per-endpoint x-github-permissions on main; it does carry the authoritative permission catalog (names + valid levels) in app-permissions. The generator targets that. Per-tool requirements are hand-authored (as planned), since MCP tools don't record REST operationIds and many are composite/GraphQL.
  • suggest-permissions authoring assist: omitted — no reliable public per-endpoint permission data to print.
  • GetToolPermissionMapFromInventory lives in pkg/github, not pkg/permissions — to avoid an import cycle (inventory imports permissions for the typed field, so permissions must stay a leaf). This mirrors where scope_filter.go lives.

Validation

  • go build ./...
  • script/test (race) ✅
  • script/lint (golangci-lint) — 0 issues ✅
  • script/generate-docs produces a clean, committed tree ✅

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Mirror the existing pkg/scopes subsystem with a new pkg/permissions
package so this repo is the public source of truth for the fine-grained
permission each MCP tool requires.

- pkg/permissions: typed Permission/Level/Scope, Requirement combinators
  (Require/AllOf/AnyOf/And, SatisfiedBy, Permissions), and a generated
  catalog (catalog_generated.go) produced from the PUBLIC
  github/rest-api-description app-permissions schema via gen.go.
- inventory.ServerTool gains RequiredPermissions + chainable WithPermissions;
  zero value means "no gate" (tool always shown).
- pkg/github/permission_filter.go: inventory bridge helpers and a fail-open
  CreateToolPermissionFilter (dormant in OSS; no granted source).
- Seed hand-authored requirements for a high-signal subset of tools.
- generate-docs emits a "Required Permissions (fine-grained)" line and a
  generated table in new docs/permissions-filtering.md; README + server
  configuration link it.
- New list-permissions CLI + script/list-permissions.

Catalog data is exclusively public (names + levels as in the REST docs and
the X-Accepted-GitHub-Permissions header); enterprise permissions excluded.

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