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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant