Skip to content

Commit f340ea4

Browse files
refactor(governance): consolidate ruleset tools with dynamic scope challenges
Rebase onto main (which now includes #3128's per-call OAuth scope checks) and redesign the ruleset tools around that API instead of the old tool-name-keyed challenge middleware that motivated splitting by level. - Collapse the 5 level-specific tools (repository_ruleset_read, organization_repository_ruleset_read, create_repository_ruleset, create_organization_repository_ruleset, create_enterprise_repository_ruleset) into 2: repository_ruleset_read and create_repository_ruleset. Both take a "level" argument (repository/organization/enterprise) and use scopes.DynamicChallenge to return the exact repo / read:org / admin:org / read:enterprise / admin:enterprise challenge for that call, using the scope hierarchy so a broader granted scope still satisfies the challenge. - A missing or unrecognized "level" (or a non-string value) returns no challenge so normal handler argument validation produces the error, instead of prompting for scopes on a malformed call. - Keep repository_ruleset_read and create_repository_ruleset as separate tools since ReadOnlyHint-based read-only filtering depends on that split. - Add enterprise-level "get" and "list" read support (list issued directly via GET /enterprises/{enterprise}/rulesets, matching the existing rule suite pattern, since go-github has no typed wrapper for it) so all three levels have symmetric read coverage. - Re-add read:enterprise/admin:enterprise to pkg/scopes as opt-in (non-default) OAuth scopes, alongside admin:org which no tool had previously requested, and register them in oauthScopeDefinitions so they are advertised in OAuth protected-resource metadata. - Fetch the "law" toolset icon into the new icons_data_uris.txt embed (required_icons.txt already listed it) and bump go-github v87 -> v89 to match main. - Update README/toolsnaps via script/generate-docs and UPDATE_TOOLSNAPS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a1bf6c3 commit f340ea4

14 files changed

Lines changed: 906 additions & 777 deletions

README.md

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -886,64 +886,45 @@ The following sets of tools are available:
886886

887887
<summary><picture><source media="(prefers-color-scheme: dark)" srcset="pkg/octicons/icons/law-dark.png"><source media="(prefers-color-scheme: light)" srcset="pkg/octicons/icons/law-light.png"><img src="pkg/octicons/icons/law-light.png" width="20" height="20" alt="law"></picture> Governance</summary>
888888

889-
- **create_enterprise_repository_ruleset** - Create enterprise repository ruleset
890-
- **Required OAuth Scopes**: `admin:enterprise`
891-
- `bypass_actors`: The actors that can bypass the rules in this ruleset (object[], optional)
892-
- `conditions`: Conditions for when this ruleset applies, e.g. {"ref_name": {"include": ["refs/heads/main"], "exclude": []}} (object, optional)
893-
- `enforcement`: The enforcement level of the ruleset. 'evaluate' allows admins to test rules before enforcing them (string, required)
894-
- `enterprise`: Enterprise slug (string, required)
895-
- `name`: The name of the ruleset (string, required)
896-
- `rules`: An array of rules within the ruleset. Each rule is an object with a 'type' (e.g. 'creation', 'deletion', 'non_fast_forward', 'required_signatures', 'pull_request', 'required_status_checks') and, for rules that need configuration, a 'parameters' object (object[], required)
897-
- `target`: The target of the ruleset. Defaults to 'branch' (string, optional)
898-
899-
- **create_organization_repository_ruleset** - Create organization repository ruleset
900-
- **Required OAuth Scopes**: `admin:org`
901-
- `bypass_actors`: The actors that can bypass the rules in this ruleset (object[], optional)
902-
- `conditions`: Conditions for when this ruleset applies, e.g. {"ref_name": {"include": ["refs/heads/main"], "exclude": []}} (object, optional)
903-
- `enforcement`: The enforcement level of the ruleset. 'evaluate' allows admins to test rules before enforcing them (string, required)
904-
- `name`: The name of the ruleset (string, required)
905-
- `org`: Organization name (string, required)
906-
- `rules`: An array of rules within the ruleset. Each rule is an object with a 'type' (e.g. 'creation', 'deletion', 'non_fast_forward', 'required_signatures', 'pull_request', 'required_status_checks') and, for rules that need configuration, a 'parameters' object (object[], required)
907-
- `target`: The target of the ruleset. Defaults to 'branch' (string, optional)
908-
909889
- **create_repository_ruleset** - Create repository ruleset
910-
- **Required OAuth Scopes**: `repo`
890+
- **OAuth Challenge Scopes**: `repo`, `admin:org`, `admin:enterprise`
911891
- `bypass_actors`: The actors that can bypass the rules in this ruleset (object[], optional)
912892
- `conditions`: Conditions for when this ruleset applies, e.g. {"ref_name": {"include": ["refs/heads/main"], "exclude": []}} (object, optional)
913893
- `enforcement`: The enforcement level of the ruleset. 'evaluate' allows admins to test rules before enforcing them (string, required)
894+
- `enterprise`: Enterprise slug. Required when level is 'enterprise'. (string, optional)
895+
- `level`: The level at which the ruleset is configured:
896+
- 'repository': A ruleset on a single repository (requires 'owner' and 'repo').
897+
- 'organization': A ruleset covering repositories in an organization (requires 'org').
898+
- 'enterprise': A ruleset covering repositories across an enterprise (requires 'enterprise'). (string, required)
914899
- `name`: The name of the ruleset (string, required)
915-
- `owner`: Repository owner (string, required)
916-
- `repo`: Repository name (string, required)
900+
- `org`: Organization name. Required when level is 'organization'. (string, optional)
901+
- `owner`: Repository owner. Required when level is 'repository'. (string, optional)
902+
- `repo`: Repository name. Required when level is 'repository'. (string, optional)
917903
- `rules`: An array of rules within the ruleset. Each rule is an object with a 'type' (e.g. 'creation', 'deletion', 'non_fast_forward', 'required_signatures', 'pull_request', 'required_status_checks') and, for rules that need configuration, a 'parameters' object (object[], required)
918-
- `target`: The target of the ruleset. Defaults to 'branch' (string, optional)
919-
920-
- **organization_repository_ruleset_read** - Read organization repository rulesets
921-
- **Required OAuth Scopes**: `read:org`
922-
- **Accepted OAuth Scopes**: `admin:org`, `read:org`, `write:org`
923-
- `method`: Operation to perform:
924-
- 'get': Get a specific repository ruleset by ID (requires 'ruleset_id').
925-
- 'list': List all repository rulesets for the organization. (string, required)
926-
- `org`: Organization name (string, required)
927-
- `page`: Page number for pagination (min 1) (number, optional)
928-
- `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
929-
- `ruleset_id`: Ruleset ID. Required for the 'get' method. (number, optional)
904+
- `target`: The target of the ruleset. Defaults to 'branch'. 'repository' is only valid for 'organization' and 'enterprise' level rulesets. (string, optional)
930905

931906
- **repository_ruleset_read** - Read repository rulesets
932-
- **Required OAuth Scopes**: `repo`
907+
- **OAuth Challenge Scopes**: `repo`, `read:org`, `read:enterprise`
933908
- `actor_name`: The handle for the GitHub user account to filter rule suites on. Used by the 'list_rule_suites' method. (string, optional)
934909
- `branch`: Branch name. Required for the 'get_rules_for_branch' method. (string, optional)
935-
- `includes_parents`: Include rulesets configured at higher levels that also apply. Defaults to true. Used by the 'get' and 'list' methods. (boolean, optional)
910+
- `enterprise`: Enterprise slug. Required when level is 'enterprise'. (string, optional)
911+
- `includes_parents`: Include rulesets configured at higher levels that also apply. Defaults to true. Used by the 'get' and 'list' methods at the repository level. (boolean, optional)
912+
- `level`: The level at which the ruleset is configured:
913+
- 'repository': A ruleset on a single repository (requires 'owner' and 'repo').
914+
- 'organization': A ruleset covering repositories in an organization (requires 'org').
915+
- 'enterprise': A ruleset covering repositories across an enterprise (requires 'enterprise'). (string, required)
936916
- `method`: Operation to perform:
937-
- 'get': Get a specific ruleset by ID (requires 'ruleset_id').
938-
- 'list': List all rulesets for the repository.
939-
- 'get_rules_for_branch': Get all rules that apply to a branch (requires 'branch').
940-
- 'list_rule_suites': List rule suites, the evaluations of rules against pushes.
941-
- 'get_rule_suite': Get a specific rule suite by ID (requires 'rule_suite_id'). (string, required)
942-
- `owner`: Repository owner (string, required)
917+
- 'get': Get a specific ruleset by ID (requires 'ruleset_id'). Supported at every level.
918+
- 'list': List all rulesets. Supported at every level.
919+
- 'get_rules_for_branch': Get all rules that apply to a branch (requires 'branch'). Repository level only.
920+
- 'list_rule_suites': List rule suites, the evaluations of rules against pushes. Repository level only.
921+
- 'get_rule_suite': Get a specific rule suite by ID (requires 'rule_suite_id'). Repository level only. (string, required)
922+
- `org`: Organization name. Required when level is 'organization'. (string, optional)
923+
- `owner`: Repository owner. Required when level is 'repository'. (string, optional)
943924
- `page`: Page number for pagination (min 1) (number, optional)
944925
- `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
945926
- `ref`: The name of the ref (branch, tag, etc.) to filter rule suites by. Used by the 'list_rule_suites' method. (string, optional)
946-
- `repo`: Repository name (string, required)
927+
- `repo`: Repository name. Required when level is 'repository'. (string, optional)
947928
- `rule_suite_id`: Rule suite ID. Required for the 'get_rule_suite' method. (number, optional)
948929
- `rule_suite_result`: The rule suite result to filter by. Used by the 'list_rule_suites' method. (string, optional)
949930
- `ruleset_id`: Ruleset ID. Required for the 'get' method. (number, optional)

docs/scope-filtering.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Some scopes implicitly include others:
6363

6464
- `repo` → includes `public_repo`, `security_events`
6565
- `admin:org` → includes `write:org` → includes `read:org`
66+
- `admin:enterprise` → includes `read:enterprise`
6667
- `project` → includes `read:project`
6768

6869
This means if your token has `repo`, tools requiring `security_events` will also be available.

pkg/github/__toolsnaps__/create_enterprise_repository_ruleset.snap

Lines changed: 0 additions & 101 deletions
This file was deleted.

pkg/github/__toolsnaps__/create_organization_repository_ruleset.snap

Lines changed: 0 additions & 101 deletions
This file was deleted.

pkg/github/__toolsnaps__/create_repository_ruleset.snap

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"annotations": {
3+
"idempotentHint": false,
4+
"readOnlyHint": false,
35
"title": "Create repository ruleset"
46
},
5-
"description": "Create a new ruleset for a repository",
7+
"description": "Create a new ruleset at the repository, organization, or enterprise level",
68
"inputSchema": {
79
"properties": {
810
"bypass_actors": {
@@ -50,16 +52,33 @@
5052
],
5153
"type": "string"
5254
},
55+
"enterprise": {
56+
"description": "Enterprise slug. Required when level is 'enterprise'.",
57+
"type": "string"
58+
},
59+
"level": {
60+
"description": "The level at which the ruleset is configured:\n- 'repository': A ruleset on a single repository (requires 'owner' and 'repo').\n- 'organization': A ruleset covering repositories in an organization (requires 'org').\n- 'enterprise': A ruleset covering repositories across an enterprise (requires 'enterprise').",
61+
"enum": [
62+
"repository",
63+
"organization",
64+
"enterprise"
65+
],
66+
"type": "string"
67+
},
5368
"name": {
5469
"description": "The name of the ruleset",
5570
"type": "string"
5671
},
72+
"org": {
73+
"description": "Organization name. Required when level is 'organization'.",
74+
"type": "string"
75+
},
5776
"owner": {
58-
"description": "Repository owner",
77+
"description": "Repository owner. Required when level is 'repository'.",
5978
"type": "string"
6079
},
6180
"repo": {
62-
"description": "Repository name",
81+
"description": "Repository name. Required when level is 'repository'.",
6382
"type": "string"
6483
},
6584
"rules": {
@@ -83,18 +102,18 @@
83102
"type": "array"
84103
},
85104
"target": {
86-
"description": "The target of the ruleset. Defaults to 'branch'",
105+
"description": "The target of the ruleset. Defaults to 'branch'. 'repository' is only valid for 'organization' and 'enterprise' level rulesets.",
87106
"enum": [
88107
"branch",
89108
"tag",
90-
"push"
109+
"push",
110+
"repository"
91111
],
92112
"type": "string"
93113
}
94114
},
95115
"required": [
96-
"owner",
97-
"repo",
116+
"level",
98117
"name",
99118
"enforcement",
100119
"rules"

0 commit comments

Comments
 (0)