forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexpected-protections.yml
More file actions
228 lines (207 loc) · 11.5 KB
/
Copy pathexpected-protections.yml
File metadata and controls
228 lines (207 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# The repository protections RELEASING.md §8's gate table depends on, and
# which of them are actually configured.
#
# The companion to expected-settings.yml, for the same reason and with the same
# split. That file covers Settings -> Secrets and variables; this one covers
# Settings -> Rules, Settings -> Environments and the labels. Neither is
# visible from a checkout, and both are the kind of thing that gets set once,
# by hand, and then silently removed.
#
# WHY THIS FILE EXISTS AT ALL. #375's complaint is that §8's gate is "a
# document rather than a mechanism": three of its rows say `procedure` or name
# a repository setting nobody has made. Making those settings is a human
# action - no API this repository can reach will do it. What can be automated
# is noticing, so the settings stop being something remembered and start being
# something checked. A gate that nothing verifies is the state #375 objects to,
# and a gate verified only on the day it was set up is the same state with a
# delay.
#
# WHAT A PULL REQUEST CAN CHECK, AND WHAT ONLY A LIVE RUN CAN. The tests in
# .github/tests/test_repository_protections.py split the same way
# test_repository_settings.py does:
#
# from the checkout whether this file still agrees with the workflows -
# above all, that every check named below can actually
# report on a merge queue entry.
# from a live run whether GitHub is really configured this way.
#
# The first half is the one with teeth day to day, because drift in the
# workflows is what actually happens.
# The branch these protections are asserted about. Everything below is scoped
# to it; nothing here says anything about any other branch.
branch: main
# ---------------------------------------------------------------------------
# Required status checks
# ---------------------------------------------------------------------------
#
# THE MENU IS CLOSED, AND THE REASON IS A HANG RATHER THAN A FAILURE.
# BRANCHING.md: merge queue raises its checks on the `merge_group` event, and a
# workflow that does not trigger on that event never reports against a queue
# entry. That does not fail the entry, it hangs it until the queue times out
# and ejects the pull request. So a check may only be required here if its
# workflow carries `merge_group:` - which is a fact about the workflow file,
# and therefore something a test can insist on rather than a rule someone
# remembers. That test is the point of this section.
#
# The check name is a job's `name:` where it has one and its job id otherwise,
# because that is what GitHub reports and therefore what the setting must
# name. `workflow` is here so the test knows where to look, not as
# documentation.
#
# One wrinkle that sentence used to gloss (#654): a MATRIX job never reports
# its bare name - GitHub reports one check per leg, `id (value, ...)` - so
# requiring one means naming a leg. The checkout test expands default-named
# plain-list matrices and refuses to guess at anything fancier; a required
# check it cannot resolve is a failing test at the pull request that adds
# the matrix, not a queue of pull requests blocked behind a status nothing
# will ever report.
required_status_checks:
test:
workflow: client-tests.yml
why: >-
The client suite - 2190 tests across 144 files, plus typecheck, lint,
format and the build. TESTING.md item 19 records what it cannot see
(jsdom has no WebGL, so every map test mocks maplibre-gl), which is an
argument for UA rather than against requiring this.
pytest:
workflow: pipeline-tests.yml
why: >-
The pipeline suite. The half of the system that decides where the trail
is drawn and how far along it a hiker is, so a red run here is the
safety-critical set in RELEASING.md §8b rather than an inconvenience.
pytest-postgres:
workflow: backend-tests.yml
why: >-
The backend suite against a real Postgres service container, which is
what makes gate 4 - migrations up, down and `alembic check` - a check
rather than a claim. It is also the job that catches a migration chain
with two heads, which has happened.
PR has a linked issue:
workflow: pr-issue-link.yml
why: >-
CONTRIBUTING.md's tracker rule, and the only one of the five that is
about process rather than correctness. Required because the exemption it
polices is a label - a pull request with no issue and no `no-issue` label
is the case it exists for, and a check nobody has to satisfy does not
police anything.
Manifest agrees with the workflows:
workflow: settings-manifest.yml
why: >-
That every `secrets.X`/`vars.X` a workflow reads is declared, that
nothing declared has outlived its last reader, and that nothing is read
from the context it was not declared for - which GitHub resolves to an
empty string rather than an error, so the failure surfaces as missing
configuration somewhere far away. Needs only the checkout, so it reports
on a fork's pull request too.
NEWLY REQUIRABLE, AND THE HISTORY IS THE REASON THE ENTRY IS LONG. This
sat in never_required until #679, not on principle but on measured
evidence: while both halves of the settings suite shared one workflow,
BRANCHING.md records five attempts in which any proposed change to
settings-check.yml at all - a comment was enough - produced
`action_required` with zero jobs rather than a status. That file was the
only one here that both ran on `pull_request` and resolved the `secrets`
context. The recorded fix was to split it so the half reading secrets and
the half reading the checkout stop sharing an `on:` block, and #679 is
that split. settings-manifest.yml touches no secrets context anywhere,
which is the property that was actually bought.
The check NAME is unchanged across the split, deliberately: branch
protection matches a check name, not a workflow file, so keeping it
verbatim is what lets this move without a window in which the required
check reports nothing.
# Checks that exist, look like they belong above, and must stay out.
#
# Declared rather than merely omitted so that leaving one out is a recorded
# decision instead of an oversight - and so a test can fail if the reason ever
# stops being true.
never_required:
Settings are configured:
workflow: settings-configured.yml
why: >-
Deliberately does not run on `pull_request` at all - GitHub passes no
secrets to a fork's run, so the job would fail for every outside
contributor for a reason none of them could fix. A required check that
cannot report on a pull request blocks every pull request.
This is about what the check can SEE, not about a missing trigger, which
is what distinguishes it from its former co-tenant above. Adding
`merge_group:` here would not make it requirable; it would only give a
queue entry a second way to be blocked by a job that cannot answer.
# ---------------------------------------------------------------------------
# Branch protection settings that are not about which checks run
# ---------------------------------------------------------------------------
settings:
# ONE MAINTAINER, and the two settings that would lock them out.
#
# This repository has a single maintainer, and two of GitHub's protections
# behave differently for one person than for a team - in opposite
# directions. Both are recorded here because both are a click away from
# making the repository unusable by the only person who can use it, and
# neither failure explains itself.
required_approving_review_count:
expected: 0
why: >-
Must stay 0. GitHub does not let an author approve their own pull
request - a platform rule with no toggle, unlike everything else in this
file. With one maintainer, requiring even one approval means no pull
request is ever mergeable: there is nobody who can give it. The escapes
are worse than the rule - an admin bypass hollows it out, and a second
account to approve one's own work is a fiction the audit trail records
as review. Note this applies to the agent-authored pull requests too:
the token authenticates as the maintainer, so GitHub considers them
their own. Revisit when there is a second person, not before.
require_branches_up_to_date:
expected: false
why: >-
Must stay OFF. BRANCHING.md §1: with it on, GitHub disables the merge
button until the branch is current, and the whole branching strategy -
which explicitly tells contributors not to merge `main` in to stay
current - becomes something nobody can follow. It is also the setting
that specifically punishes concurrent work by serialising it, and five
branches open at once is the normal state here. The merge queue is what
makes it unnecessary rather than merely tolerable: the queue builds each
entry against `main` plus everything ahead of it, which is the guarantee
this setting was reaching for, without serialising anybody.
# ---------------------------------------------------------------------------
# Environments
# ---------------------------------------------------------------------------
environments:
production:
required_reviewers_at_least: 1
prevent_self_review: false
why: >-
What makes RELEASING.md §12 - only the maintainer ships - checked by
GitHub rather than by discipline. Two workflows already run under this
environment and neither is gated by anything today:
publish-vector-data.yml, which overwrites the map data hikers download,
and migrate.yml's production job, which applies schema changes to the
database a club's moderation queue lives in. Both are dispatch-only, so
the environment is the only thing that could ask a second time.
`prevent_self_review` must stay FALSE, and this is where an environment
differs from a pull request rather than matching it. GitHub allows a
required reviewer to approve their own deployment by default; "Prevent
self-review" is an opt-in toggle added in October 2023. Off, a single
maintainer can be their own reviewer and the gate does real work - a
publish or a migration waits for a deliberate approval instead of firing
the moment a dispatch is submitted. On, with one reviewer, it is the
same lockout as requiring a pull request approval: nobody can ever
approve, and both of these workflows become undispatchable.
So the gate here is not a second pair of eyes and should not be
described as one. It is a speed bump against an accidental dispatch,
which is the failure actually available to a solo maintainer.
# ---------------------------------------------------------------------------
# Labels
# ---------------------------------------------------------------------------
#
# Gate 11 - "no open issue labelled release-blocker" - is checkable by API
# once these exist, and unanswerable until they do: a search for a label that
# does not exist returns no issues, which reads exactly like a clean gate.
labels:
release-blocker:
why: >-
This release does not go out. RELEASING.md §8b: a finding in the
safety-critical set can never become a follow-up issue, and this label is
how that distinction is recorded somewhere a query can see.
release-followup:
why: >-
The next release carries it. The other half of the same decision - the
one that makes `release-blocker` mean something, because a tracker with
only a blocking label grows a habit of not applying it.