tenseleyflow/shithub / 7464170

Browse files

docs/api: rulesets REST reference + SUMMARY entry

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
746417029ec542dbf1929967516bf9ee5100a66f
Parents
5558fed
Tree
ea5937c

2 changed files

StatusFile+-
M docs/public/SUMMARY.md 1 0
A docs/public/api/rulesets.md 120 0
docs/public/SUMMARY.mdmodified
@@ -31,6 +31,7 @@
3131
 - [Repositories](./api/repos.md)
3232
 - [Repository follow-ups (README/topics/merge-upstream)](./api/repos-followups.md)
3333
 - [Branches and tags](./api/branches.md)
34
+- [Rulesets](./api/rulesets.md)
3435
 - [Repo collaborators](./api/collaborators.md)
3536
 - [Commits](./api/commits.md)
3637
 - [Contents](./api/contents.md)
docs/public/api/rulesets.mdadded
@@ -0,0 +1,120 @@
1
+# Rulesets
2
+
3
+Read-only rulesets surface. Mirrors GitHub's
4
+[`/repos/{owner}/{repo}/rulesets`](https://docs.github.com/en/rest/repos/rules)
5
+response shape. shithub synthesizes ruleset rows from the
6
+`branch_protection_rules` table — one branch-protection row
7
+becomes one ruleset, named after its pattern, with each
8
+configured field projected as a typed rule object.
9
+
10
+All endpoints require `Authorization: Bearer <pat>` with
11
+`repo:read` and gate on `ActionRepoRead`. The
12
+[common API conventions](overview.md) apply.
13
+
14
+## Ruleset shape
15
+
16
+```json
17
+{
18
+  "id": 17,
19
+  "name": "Pattern: main",
20
+  "target": "branch",
21
+  "source_type": "Repository",
22
+  "source": "alice/demo",
23
+  "enforcement": "active",
24
+  "conditions": {
25
+    "ref_name": {
26
+      "include": ["refs/heads/main"],
27
+      "exclude": []
28
+    }
29
+  },
30
+  "rules": [
31
+    {
32
+      "type": "pull_request",
33
+      "parameters": {
34
+        "required_approving_review_count": 1,
35
+        "dismiss_stale_reviews_on_push": false,
36
+        "require_code_owner_review": true
37
+      }
38
+    },
39
+    {"type": "non_fast_forward"},
40
+    {"type": "deletion"},
41
+    {"type": "required_signatures"},
42
+    {
43
+      "type": "required_status_checks",
44
+      "parameters": {
45
+        "required_status_checks": [{"context": "ci/build"}],
46
+        "strict_required_status_checks_policy": false
47
+      }
48
+    }
49
+  ],
50
+  "created_at": "2026-05-12T04:00:00Z",
51
+  "updated_at": "2026-05-13T04:00:00Z"
52
+}
53
+```
54
+
55
+### Rule types
56
+
57
+Each `rules[].type` maps to one or more columns on the underlying
58
+protection row:
59
+
60
+| `type` | Columns | Notes |
61
+|--------|---------|-------|
62
+| `pull_request` | `require_pr_for_push`, `required_review_count`, `require_code_owner_review`, `dismiss_stale_reviews_on_push` | Emitted when any of these is non-default. `parameters.required_approving_review_count` is the headline value. |
63
+| `non_fast_forward` | `prevent_force_push` | Force-push gate. No parameters. |
64
+| `deletion` | `prevent_deletion` | Branch-delete gate. No parameters. |
65
+| `required_signatures` | `require_signed_commits` | Verified-signature gate. No parameters. |
66
+| `required_status_checks` | `status_checks_required`, `dismiss_stale_status_checks_on_push` | `parameters.required_status_checks` is an array of `{context}` objects. `integration_id` is omitted (we don't track per-app integrations). |
67
+
68
+Rules an admin hasn't configured are absent from the array — clients should treat missing as "rule not configured" rather than assuming defaults.
69
+
70
+### Field notes
71
+
72
+- `target` — always `"branch"`. Tag rulesets ship in a future sprint when tag protection lands.
73
+- `source_type` / `source` — always `"Repository"` / `"<owner>/<repo>"`. Org-scoped and enterprise-scoped rulesets are out of scope until shithub grows enterprise-tier accounts.
74
+- `enforcement` — always `"active"`. We don't model `"disabled"` or `"evaluate"` modes; every row in the table is enforced by the pre-receive hook.
75
+- `conditions.ref_name.include` — single-entry array with the pattern prefixed by `refs/heads/`. shithub's patterns use `filepath.Match` semantics (`*` doesn't cross `/`), not gh's fnmatch.
76
+- `bypass_actors` — not emitted. Bypass / multi-actor exemptions ship in a future sprint.
77
+
78
+## List rulesets
79
+
80
+```
81
+GET /api/v1/repos/{owner}/{repo}/rulesets
82
+```
83
+
84
+Required scope: `repo:read`.
85
+
86
+Returns every ruleset on the repo, ordered by id. Empty repos and repos with no configured protection rules return `[]`.
87
+
88
+## Get a single ruleset
89
+
90
+```
91
+GET /api/v1/repos/{owner}/{repo}/rulesets/{id}
92
+```
93
+
94
+Required scope: `repo:read`.
95
+
96
+Returns the single ruleset whose id matches. 404 when the id doesn't belong to this repo — same status as "doesn't exist" so the response doesn't leak existence across repo boundaries.
97
+
98
+## Rules applying to a branch
99
+
100
+```
101
+GET /api/v1/repos/{owner}/{repo}/rules/branches/{branch}
102
+```
103
+
104
+Required scope: `repo:read`.
105
+
106
+Returns every ruleset whose pattern matches the given branch name. **All** matching patterns are returned, not just the longest-match — the longest-match heuristic shithub's pre-receive enforcer uses is an internal precedence detail, not a contract surface.
107
+
108
+Branch names that contain `/` (`feature/x`, `release/v1.0`) are matched against patterns using `filepath.Match`: `*` does not cross path separators, so `release/*` matches `release/v1.0` but not `release/v1.0/sub`.
109
+
110
+## Errors
111
+
112
+| Status | When                                            |
113
+|-------:|-------------------------------------------------|
114
+|    401 | PAT missing/invalid/expired/revoked.            |
115
+|    403 | PAT lacks `repo:read` scope.                    |
116
+|    404 | Repo not found, ruleset id not found, or cross-repo lookup. |
117
+
118
+## Mutating rulesets
119
+
120
+Creating, updating, and deleting rulesets via REST is not yet shipped. Use the web UI at `Settings → Branches → Add rule` for now. The shape of the future POST/PATCH/DELETE endpoints will mirror gh's documented surface and will require `repo:write` + `ActionRepoAdmin`.