Repository navigation
Commit 1debc22
authored
audit(1to1): adjudicate the routes no action reaches and gate on them (#1642)
Refs #1595
Refs #1604
Refs #1605
Refs #1606
Refs #1607
Refs #1608
Refs #1609
Refs #1610
Refs #1611
Refs #1612
Refs #1613
Refs #1614
Refs #1615
Refs #1616
Refs #1617
Refs #1618
Refs #1209
Refs #1619
Refs #1620
Refs #1621
Refs #1622
Refs #1623
Refs #1624
Refs #1625
Refs #1626
Refs #1627
Refs #1628
Refs #1629
Refs #1630
Refs #1631
Refs #1632
Refs #1633
Refs #1634
This is the seventh layer of the auditor stack. The sixth added R-ROUTE
and gated on stale declarations only, which left 730 routes of the
19.5.0 record that no action sends and nothing answered. This layer
answers every one of them and turns on the full gate.
## What the check detects
`-scope=routes` now fails on a finding of any class (a route nothing
answers, an unknown skip reason, an internal route left in, a
contradicted decision), as it already did on a declaration that no
longer describes the tree. The gate reads those classes from
`findingClasses`, so a class added there is gated without a second list
to keep in step. A re-pin that brings a route, or an action that stops
sending one, fails the gate until the change that causes it decides the
route, and every family row pins how many routes it answers.
One declaration problem is new: a `tracked` row over a route whose
client-go method `acceptedMissingMethods` decides `COVERED_GENERIC` or
`INTENTIONAL_SKIP_*`. The row says an action is still to implement and
the decision that the route needs none, so one of the two no longer
describes the tree.
## How the routes are answered
I applied the decisions of 2026-10-27. `covered-by-graphql` is a REST
route whose operation an action does over GraphQL, the action checked in
the catalog and in the request record: 49 routes. They are the `/-/`
epic routes and the child epic links, the five work item operations and
a child's attachment and detachment behind `work_item_rest_api`, a
group's work item's discussions, notes and children (13 routes the
`group.epic_*` actions cover, since their GraphQL reads the group's work
item by its iid whatever its type), a vulnerability's confirmation,
dismissal, resolution, revert and read, and a pipeline's findings. A
project's and a namespace's work item discussions, notes and children
stay tracked, and so does the resolution of a discussion, which no
action does.
`client-protocol` is the protocol a package manager's or MLflow's own
client speaks, 150 routes, except a download, which is tracked. The line
is what the route serves, not how GitLab words its summary: what a
package or a model version holds (one of its files, its archive, its
source or a file inside it, such as a Go module's `go.mod`) is a
download, while an index or a metadata document a client reads to find
and resolve packages, and the URL or the location of the content, are
the protocol's. So Debian's `Release` and `Packages` files, Helm's
`index.yaml`, RPM's `repodata` and RubyGems' spec indexes and gemspecs
are `client-protocol`. The witness holds every `client-protocol` route
whose summary says download to a list that names what each serves
instead, and every entry of that list and every protocol root to a route
it answers.
`tracked` is everything else, 534 routes, under 32 issues: one for each
of thirty catalog domains and one for each of two domains the catalog
does not hold yet, the virtual registries and GitLab Duo. The fifteen
`public_endpoint` routes and every administrator, GitLab.com and tier
route are among them, and a route's reason says it is public exactly
when its skip reason is `public_endpoint` (`POST /glql` is not; `GET
/glql/schema` is).
Seventeen of the tracked routes were settled by
`acceptedMissingMethods`: six `COVERED_GENERIC` (a group's and a
project's direct members, a group's subgroups, the delete of an LDAP
link by its `cn`, a merge request's changes and the `PUT` of the error
tracking settings) and eleven `INTENTIONAL_SKIP_*` (nine downloads, the
streamed repository archive and the deprecated write of a merge
request's approvals). A route still to implement is no method R-ACTION
may settle, so those entries leave the table and R-ACTION lists the
seventeen methods as its backlog, 18 missing methods with
`TerraformStates.List`, which was there already; `Orbit.GetDsl` was the
nineteenth until the Orbit migration, and is decided
`SUPERSEDED_UPSTREAM` now. The creation of a vulnerability keeps its
`COVERED_GRAPHQL` service decision, which does not carry because no
GraphQL action creates one. The two runner token routes and the
integrations list carry no decision at all: they are tracked rows whose
reason names `runner_token_auth` or the `/services/` twin.
The table moved to `family_table.go`, written with five constructors
(`tracked`, `download`, `publicEndpoint`, `protocol`, `overGraphQL`). It
has 331 rows, more than the design estimated, because no two rows may
answer one route: downloads sit inside the protocol trees, so each
protocol is split around its downloads, and a group's work item routes
are split from a project's and a namespace's.
The Orbit rows are as the Orbit migration (#1585) left Orbit, all under
#1209, the issue that already tracked the Orbit routes no action
reaches. The five routes the `orbit.*` actions sent until GitLab.com
removed them (`GET /orbit/status`, `/orbit/schema`, `/orbit/tools`,
`/orbit/schema/dsl` and `/orbit/graph_status`) inherit
`SUPERSEDED_UPSTREAM` from the layer below, and `POST /orbit/mcp`, which
the actions send in their place, is reached, so the `/orbit/mcp` row
tracks the endpoint's SSE listener alone, `GET /orbit/mcp`. `GET
/orbit/agent/commands`, which `orbit.dsl` read until GitLab.com removed
it too and which no client-go method sends, shares a row with the
invocation of a command; the query templates, the named templates, the
response format guidance and the skills stay tracked, the reasons of the
two GitLab.com removed in favour of GraphQL saying so.
## Witness tests, red then green
On the parent as it stood before the stack was rebased onto #1585
(9a1b315fb), with this layer's tests, a stand-in for the four
identifiers they need (two issue constants, `publicTail` and
`Summary.counters`) and without its table or gate:
```text
$ go test -count=1 -run "TestSummary_Clean|TestJudgeAll_AFamilyRow|TestRun_Repository" ./cmd/audit_1to1/internal/routes/
--- FAIL: TestSummary_Clean_PassesOnlyWithoutAFindingOrAStaleDeclaration (0.00s)
--- FAIL: TestSummary_Clean_PassesOnlyWithoutAFindingOrAStaleDeclaration/an_unanswered_route (0.00s)
analyze_test.go:301: clean({... Unanswered:1 ...}) = true, want false
(and the unknown skip reason, the two internal classes and the contradicted decision)
--- FAIL: TestSummary_Clean_FailsOnEveryFindingClassAndOnNoOther (0.00s)
--- FAIL: TestSummary_Clean_FailsOnEveryFindingClassAndOnNoOther/unanswered (0.00s)
analyze_test.go:318: one route of class unanswered: clean() = true, want false
(and the other four finding classes)
--- FAIL: TestJudgeAll_AFamilyRow_AnswersItsRoutesUntilTheyChange (0.02s)
--- FAIL: TestJudgeAll_AFamilyRow_AnswersItsRoutesUntilTheyChange/a_tracked_row_over_a_route_a_COVERED_GENERIC_decision_settles (0.00s)
analyze_test.go:575: stale = [], want ["family GET /gizmos tracks GET /gizmos, and Gizmos.ListGizmos is decided COVERED_GENERIC, which says the route needs no action of its own: an action still to implement is no method acceptedMissingMethods settles"]
(and the INTENTIONAL_SKIP_BINARY case, and the cases whose gate the parent passes with findings left)
--- FAIL: TestRun_Repository_DeclaresTheRoutesADecisionDoesNotCarryOnto (0.22s)
analyze_test.go:960: GET /groups/:id/members = {Route: Class: ...}, want it tracked by a family row whose reason names "", with the decisions "Groups.ListGroupMembers unadjudicated"
(and the other 21 routes of the witness)
--- FAIL: TestRun_Repository_HoldsTheDuoWorkflowRoutesToTheTokenThatCallsThem (0.16s)
analyze_test.go:1008: composite identity = [...], 0 a user's token calls tracked by the Duo row and [... unanswered ...] otherwise, want [...], 14 and none
--- FAIL: TestRun_Repository_AdjudicatesEveryRouteNoActionReaches (0.16s)
analyze_test.go:1089: declared map[tracked:3] under 2 issues; want map[client-protocol:150 covered-by-graphql:49 tracked:535] under one issue for each of 30 catalog domains and of the virtual registries and GitLab Duo, which it does not hold yet
analyze_test.go:1092: 0 public_endpoint routes tracked, want 15; ...
analyze_test.go:1095: ...; roots and listed downloads no client-protocol route answers: ["/group/:id/-/packages/" "/groups/:id/-/packages/" "/packages/" ...]
--- FAIL: TestRun_Repository_HoldsTheWorkItemRoutesToTheActionsThatDoTheirOperation (0.14s)
analyze_test.go:1174: work item routes by scope and category = map[], want map[groups:map[covered-by-graphql:20 tracked:10] namespaces:map[covered-by-graphql:7 tracked:23] projects:map[covered-by-graphql:7 tracked:23]]; ...
FAIL
```
Since the rebase the witness of the decisions that do not carry holds 21
routes, not 22, and the count it wants is 534 tracked: `GET
/orbit/schema/dsl` is inherited now, with the other four Orbit routes
GitLab.com removed.
With this layer's gate check and its seventeen `acceptedMissingMethods`
entries still in place, `TestRun_Repository_GateIsGreen` names the
contradiction on the real tree, six `is decided COVERED_GENERIC`, nine
`is decided INTENTIONAL_SKIP_BINARY` and two `is decided
INTENTIONAL_SKIP_OTHER`:
```text
analyze_test.go:837: the gate fails: 0 routes no action reaches are left findings, among them [], ...; and the stale declarations ["family * /groups/*/uploads/** tracks GET /groups/:id/uploads/:secret/:filename, and GroupMarkdownUploads.DownloadGroupMarkdownUploadBySecretAndFilename is decided INTENTIONAL_SKIP_BINARY, which says the route needs no action of its own: ..." ...]
```
Here:
```text
--- PASS: TestSummary_Clean_PassesOnlyWithoutAFindingOrAStaleDeclaration (0.00s)
--- PASS: TestSummary_Clean_FailsOnEveryFindingClassAndOnNoOther (0.00s)
--- PASS: TestJudgeAll_AFamilyRow_AnswersItsRoutesUntilTheyChange (0.02s)
--- PASS: TestRun_Repository_GateIsGreen (0.88s)
--- PASS: TestRun_Repository_HoldsTheRoutesClientGoLaterModels (0.20s)
--- PASS: TestRun_Repository_DeclaresTheRoutesADecisionDoesNotCarryOnto (0.22s)
--- PASS: TestRun_Repository_HoldsTheDuoWorkflowRoutesToTheTokenThatCallsThem (0.27s)
--- PASS: TestRun_Repository_AdjudicatesEveryRouteNoActionReaches (0.26s)
--- PASS: TestRun_Repository_HoldsTheWorkItemRoutesToTheActionsThatDoTheirOperation (0.25s)
--- PASS: TestDeclares_ATrackedRowOverARouteADecisionSettles_IsAProblem (0.00s)
```
The witness is sensitive to the version on purpose: the client-go bump
and every re-pin move its counts, and that change is the evidence the
triage was run again.
## On main
2137 routes: 1007 reached, 20 outside the API, 186 skipped, 94 by a
slug, 49 aliases, 48 inherited and 733 declared by 331 rows, with no
finding and no stale declaration. Each tracked route is in the text of
its domain's issue with its row, its summary and the client-go methods
that send it, if any.
## Checks
`go test ./... -count=1` with the snapshot parity deferred, and the
`audit_1to1` suites on the real tree without it. 100% statements and
every condition both ways on `routes` (gobco 242 of 242) and on
`actions` (22 of 22); gremlins Lived 0 and Not covered 0 on `routes`
(181 killed) and on `actions` (16 killed). `golangci-lint` is clean on
`cmd/audit_1to1/...`, and the `make analyze` steps the layer touches
pass: the routes, params and paths gates, the sdk gate, the subtest,
goroutine, unread-constant, closed-server, godoc and test-name gates,
the documented tool names and `golangci-lint fmt`, as do markdownlint,
the table formatter, the doc link check and the em dash check.
`gen_testing_docs --check` is regenerated at the top of the stack, as
below this layer. The two pieces of work this layer kept clear of have
merged since, the keyset half of the live record (#1574) and merge
request diff pagination (#1584), and so has the Orbit migration (#1585),
which stopped sending five Orbit routes this layer counted reached (`GET
/orbit/agent/commands`, `/orbit/graph_status`, `/orbit/schema`,
`/orbit/status` and `/orbit/tools`) and started sending `POST
/orbit/mcp`, which the `* /orbit/mcp` row tracked. The stack is rebased
onto main after all three, the Orbit rows are redone as above, and every
figure in this description is measured there except the red run, which
is quoted from the parent before that rebase.
---------
Signed-off-by: José M. Requena Plens <mail@jmrp.io>1 parent 44fd2b9 commit 1debc22
15 files changed
Lines changed: 1380 additions & 159 deletions
File tree
- .github/workflows
- cmd/audit_1to1
- internal
- actions
- routes
- docs/development
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
253 | 253 | | |
254 | 254 | | |
255 | 255 | | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
261 | 260 | | |
262 | 261 | | |
263 | 262 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2011 | 2011 | | |
2012 | 2012 | | |
2013 | 2013 | | |
2014 | | - | |
2015 | | - | |
2016 | | - | |
2017 | | - | |
2018 | | - | |
| 2014 | + | |
| 2015 | + | |
| 2016 | + | |
| 2017 | + | |
| 2018 | + | |
| 2019 | + | |
2019 | 2020 | | |
2020 | 2021 | | |
2021 | 2022 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | 21 | | |
23 | 22 | | |
24 | 23 | | |
| |||
111 | 110 | | |
112 | 111 | | |
113 | 112 | | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
120 | 123 | | |
121 | 124 | | |
122 | 125 | | |
| |||
164 | 167 | | |
165 | 168 | | |
166 | 169 | | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | 170 | | |
173 | 171 | | |
174 | 172 | | |
| |||
177 | 175 | | |
178 | 176 | | |
179 | 177 | | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | 178 | | |
193 | 179 | | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
| 180 | + | |
202 | 181 | | |
203 | 182 | | |
204 | 183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
164 | 175 | | |
165 | 176 | | |
166 | 177 | | |
167 | | - | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
168 | 184 | | |
169 | 185 | | |
170 | 186 | | |
| |||
178 | 194 | | |
179 | 195 | | |
180 | 196 | | |
181 | | - | |
182 | 197 | | |
183 | 198 | | |
184 | 199 | | |
| |||
0 commit comments