bugpipe 3.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bugpipe/__init__.py +42 -0
- bugpipe/api/AUDIT.md +331 -0
- bugpipe/api/README.md +728 -0
- bugpipe/api/__init__.py +3 -0
- bugpipe/api/client.py +328 -0
- bugpipe/api/models.py +742 -0
- bugpipe/api/parser.py +720 -0
- bugpipe/cli/__init__.py +69 -0
- bugpipe/cli/cmd.py +304 -0
- bugpipe/cli/term.py +234 -0
- bugpipe/cli/update_checker.py +207 -0
- bugpipe-3.0.1.dist-info/METADATA +52 -0
- bugpipe-3.0.1.dist-info/RECORD +15 -0
- bugpipe-3.0.1.dist-info/WHEEL +4 -0
- bugpipe-3.0.1.dist-info/entry_points.txt +3 -0
bugpipe/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from .api.client import TRACKERS, Bugpipe
|
|
2
|
+
from .api.models import (
|
|
3
|
+
CUSTOM_FIELD_IDS,
|
|
4
|
+
Attachment,
|
|
5
|
+
AttachmentRestriction,
|
|
6
|
+
Comment,
|
|
7
|
+
CommentsResult,
|
|
8
|
+
CustomFieldValue,
|
|
9
|
+
Exportable,
|
|
10
|
+
FieldChange,
|
|
11
|
+
Issue,
|
|
12
|
+
IssueType,
|
|
13
|
+
IssueUpdate,
|
|
14
|
+
IssueUpdatesResult,
|
|
15
|
+
Priority,
|
|
16
|
+
Results,
|
|
17
|
+
SearchResult,
|
|
18
|
+
Severity,
|
|
19
|
+
Status,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"CUSTOM_FIELD_IDS",
|
|
24
|
+
"TRACKERS",
|
|
25
|
+
"Attachment",
|
|
26
|
+
"AttachmentRestriction",
|
|
27
|
+
"Bugpipe",
|
|
28
|
+
"Comment",
|
|
29
|
+
"CommentsResult",
|
|
30
|
+
"CustomFieldValue",
|
|
31
|
+
"Exportable",
|
|
32
|
+
"FieldChange",
|
|
33
|
+
"Issue",
|
|
34
|
+
"IssueType",
|
|
35
|
+
"IssueUpdate",
|
|
36
|
+
"IssueUpdatesResult",
|
|
37
|
+
"Priority",
|
|
38
|
+
"Results",
|
|
39
|
+
"SearchResult",
|
|
40
|
+
"Severity",
|
|
41
|
+
"Status",
|
|
42
|
+
]
|
bugpipe/api/AUDIT.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# Authenticated API audit
|
|
2
|
+
|
|
3
|
+
These audits come from browser traffic captured with mitmproxy while signed in to `issuetracker.google.com`. Some endpoints also work without authentication.
|
|
4
|
+
|
|
5
|
+
“Tested” records the status of the original checks. “Untested” means the
|
|
6
|
+
behavior was captured or noted but not verified by those checks.
|
|
7
|
+
|
|
8
|
+
## Endpoints
|
|
9
|
+
|
|
10
|
+
| # | Endpoint | Tested | Result or recorded note |
|
|
11
|
+
|---|-----------------------------------------------------------|--------|-----------------------------------------------|
|
|
12
|
+
| 1 | [List comments](#1-list-comments) | Yes | Returns text comments without authentication |
|
|
13
|
+
| 2 | [User preferences](#2-user-preferences) | No | Captured response: `[["f.mt"]]`; meaning unknown |
|
|
14
|
+
| 3 | [Read timestamp](#3-read-timestamp) | No | Captured request and timestamp response |
|
|
15
|
+
| 4 | [Component access policies](#4-component-access-policies) | Yes | Users and groups listed by role |
|
|
16
|
+
| 5 | [User access](#5-user-access) | Yes | Returns the roles held by the requesting user |
|
|
17
|
+
| 6 | [Similar issues](#6-similar-issues) | No | Recorded note: HTTP 401 without Google authentication cookies |
|
|
18
|
+
| 7 | [Health check](#7-health-check) | Yes | HTTP 200 with `yes` on 13 tested domains |
|
|
19
|
+
| 8 | [Update request](#8-update-request) | Yes | Accepts sort order, page size, and page token |
|
|
20
|
+
| 9 | [Field changes](#9-field-changes) | Yes | Initial update includes archive, deletion, and access fields |
|
|
21
|
+
| 10 | [Protobuf types](#10-protobuf-types) | No | Captured `IssueAccessLimit` and `User` type names |
|
|
22
|
+
| 11 | [Issue timestamps](#11-issue-timestamps) | Yes | `[34]` tracks substantive activity; `[35]` tracks the last write |
|
|
23
|
+
| 12 | [Private hotlists](#12-private-hotlists) | No | Recorded note: batch requests omit private hotlists; single requests return HTTP 403 |
|
|
24
|
+
|
|
25
|
+
## 1. List comments
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
POST /action/issues/{issue_id}/listComments
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Tested without cookies or authentication tokens.
|
|
32
|
+
|
|
33
|
+
Request shape:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
[ISSUE_ID, SORT_ORDER, PAGE_SIZE, PAGE_TOKEN]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Position | Field | Type | Value |
|
|
40
|
+
|----------|-------|------|-------|
|
|
41
|
+
| `[0]` | issue_id | `int` | Issue ID |
|
|
42
|
+
| `[1]` | sort_order | `str \| null` | `"ASC"` for oldest first; `"DESC"` or `null` for newest first |
|
|
43
|
+
| `[2]` | page_size | `int` | Comments per page |
|
|
44
|
+
| `[3]` | page_token | `str`, omitted on the first page | Token from the previous response |
|
|
45
|
+
|
|
46
|
+
Both sort orders passed the recorded checks. The response has this shape:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
data[0] = ["b.ListIssueCommentsResponse", [COMMENTS, PAGE_TOKEN, TOTAL_COUNT]]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Path | Type | Value |
|
|
53
|
+
|------|------|-------|
|
|
54
|
+
| `[0][1][0]` | `list[list]` | Comment arrays |
|
|
55
|
+
| `[0][1][1]` | `str \| null` | Next page token, such as `"start_index:2"`, or `null` on the last page |
|
|
56
|
+
| `[0][1][2]` | `int` | Total text comments; excludes updates that only change fields |
|
|
57
|
+
|
|
58
|
+
### Comment fields
|
|
59
|
+
|
|
60
|
+
Comment fields run through index `[18]`. The shortened example below stops at
|
|
61
|
+
`[17]`. The parser accepts missing trailing fields.
|
|
62
|
+
|
|
63
|
+
| Index | Field | Type | Meaning |
|
|
64
|
+
|-------|-------|------|---------|
|
|
65
|
+
| `[0]` | body | `str` | Comment text |
|
|
66
|
+
| `[2]` | author | user array | Comment author |
|
|
67
|
+
| `[3]` | modified_at | timestamp | Last edit time |
|
|
68
|
+
| `[4]` | unknown | `list` | Recorded value: `[]` |
|
|
69
|
+
| `[5]` | issue_id | `int` | Parent issue |
|
|
70
|
+
| `[6]` | sequence_number | `int` | Starts at 1 here and at 0 in `/updates` |
|
|
71
|
+
| `[8]` | unknown | `int` | Recorded values: 1 and 2; meaning unverified |
|
|
72
|
+
| `[9]` | unknown | `list` | Recorded value: `[[1]]`; meaning unknown |
|
|
73
|
+
| `[14]` | comment_token | `str` | Recorded as a stable token per comment; decodes twice from base64 to a 128-bit value in hex |
|
|
74
|
+
| `[17]` | last_editor | user array | Last person to edit the comment |
|
|
75
|
+
| `[18]` | created_at | timestamp | Original post time |
|
|
76
|
+
|
|
77
|
+
The recorded check of 491 live comments found that `[18] <= [3]` in every
|
|
78
|
+
case. Edited comments had `[18] < [3]`. This also held for self-edits, where
|
|
79
|
+
the author remained the last editor.
|
|
80
|
+
|
|
81
|
+
### Example
|
|
82
|
+
|
|
83
|
+
Request the first three comments for issue `496840714`, oldest first:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
[496840714, "ASC", 3]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Shortened response:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
[
|
|
93
|
+
[
|
|
94
|
+
"b.ListIssueCommentsResponse",
|
|
95
|
+
[
|
|
96
|
+
[
|
|
97
|
+
[
|
|
98
|
+
"This is an **M147** merge request from crbug/495542144...",
|
|
99
|
+
null,
|
|
100
|
+
[null, "chromium-merge@google.com", 1, ["google_domain"]],
|
|
101
|
+
[1774605025, 724000000],
|
|
102
|
+
[],
|
|
103
|
+
496840714,
|
|
104
|
+
1,
|
|
105
|
+
null,
|
|
106
|
+
2,
|
|
107
|
+
[[1]],
|
|
108
|
+
null,
|
|
109
|
+
null,
|
|
110
|
+
null,
|
|
111
|
+
null,
|
|
112
|
+
"WVRReVltSTBNVEl5...",
|
|
113
|
+
null,
|
|
114
|
+
null,
|
|
115
|
+
[null, "chromium-merge@google.com", 1, ["google_domain"]]
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
"Fixes a major user reported regression...",
|
|
119
|
+
null,
|
|
120
|
+
[null, "user@google.com", 1, ["googlers_unrestricted", "google_domain"]],
|
|
121
|
+
[1774605229, 679000000],
|
|
122
|
+
[],
|
|
123
|
+
496840714,
|
|
124
|
+
2,
|
|
125
|
+
null,
|
|
126
|
+
2,
|
|
127
|
+
[[1]],
|
|
128
|
+
null,
|
|
129
|
+
null,
|
|
130
|
+
null,
|
|
131
|
+
null,
|
|
132
|
+
"WVRReVltSTBNVEl5...",
|
|
133
|
+
null,
|
|
134
|
+
null,
|
|
135
|
+
[null, "user@google.com", 1, ["googlers_unrestricted", "google_domain"]]
|
|
136
|
+
]
|
|
137
|
+
],
|
|
138
|
+
"start_index:2",
|
|
139
|
+
7
|
|
140
|
+
]
|
|
141
|
+
]
|
|
142
|
+
]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The sample contains comments 1 and 2. The next page token is
|
|
146
|
+
`"start_index:2"`. Its total is 7 text comments; the recorded
|
|
147
|
+
`issue.comment_count` was 22 because it included field-only updates.
|
|
148
|
+
|
|
149
|
+
## 2. User preferences
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
POST /action/current_user/preferences
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Untested. The request body was not captured. The captured response was:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
[["f.mt"]]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Its meaning is unknown.
|
|
162
|
+
|
|
163
|
+
## 3. Read timestamp
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
POST /action/issues/read_timestamp
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Untested. The endpoint name suggests that it marks issues as read. This is an
|
|
170
|
+
inference from the name and the captured timestamp response.
|
|
171
|
+
|
|
172
|
+
Captured request shape, where `ISSUE_IDS` stands for the issue ID values:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
[null, null, null, [[ISSUE_IDS], 1, 1]]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Captured response shape:
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
[["b.UpdateIssueReadTimestampResponse", null, [null, null, [SECS, NANOS]]]]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 4. Component access policies
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
GET /action/access_policies/components%2F{component_id}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Tested. The response type is `b.AccessPolicy`. It contains nested user arrays
|
|
191
|
+
grouped by role: admin, writer, appender, and reader. Entries include users
|
|
192
|
+
and groups such as `"googlers_unrestricted"` and `"public_non_google"`.
|
|
193
|
+
|
|
194
|
+
## 5. User access
|
|
195
|
+
|
|
196
|
+
```text
|
|
197
|
+
GET /action/user_access?relations=admin,writer,appender,reader&resourceNames=issues/{id}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Tested. The response type is `b.UserAccessBatchResponse`.
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
[
|
|
204
|
+
[
|
|
205
|
+
"b.UserAccessBatchResponse",
|
|
206
|
+
[
|
|
207
|
+
["b.ResourceRelation", "issues/497175171", 3],
|
|
208
|
+
["b.ResourceRelation", "issues/497175171", 4]
|
|
209
|
+
]
|
|
210
|
+
]
|
|
211
|
+
]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
For the query above, the recorded role values are:
|
|
215
|
+
|
|
216
|
+
| Value | Role |
|
|
217
|
+
|-------|------|
|
|
218
|
+
| 1 | Admin |
|
|
219
|
+
| 2 | Writer |
|
|
220
|
+
| 3 | Appender |
|
|
221
|
+
| 4 | Reader |
|
|
222
|
+
|
|
223
|
+
The response contains only roles held by the requesting user. The example
|
|
224
|
+
contains appender and reader roles. A separate check with a public read-only
|
|
225
|
+
user returned only `4`, the reader role.
|
|
226
|
+
|
|
227
|
+
## 6. Similar issues
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
POST /action/retrieve_similar_issues
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Untested. Captured request shape:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
["b.RetrieveSimilarIssuesRequest", [ISSUE_ID, null, null, 7, null, null, 2]]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The recorded note reports HTTP 401 without Google authentication cookies.
|
|
240
|
+
The required cookies were not verified.
|
|
241
|
+
|
|
242
|
+
## 7. Health check
|
|
243
|
+
|
|
244
|
+
```text
|
|
245
|
+
GET /action/yes
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Tested without authentication. The endpoint returns `yes` as `text/plain`,
|
|
249
|
+
with no JSON or anti-XSSI prefix. The client exposes it as `echo()`.
|
|
250
|
+
|
|
251
|
+
These 13 domains returned HTTP 200 with `yes` in the recorded checks:
|
|
252
|
+
|
|
253
|
+
| Domain | Result |
|
|
254
|
+
|--------|--------|
|
|
255
|
+
| `issuetracker.google.com` | 200 `yes` |
|
|
256
|
+
| `issues.chromium.org` | 200 `yes` |
|
|
257
|
+
| `issues.pigweed.dev` | 200 `yes` |
|
|
258
|
+
| `issues.gerritcodereview.com` | 200 `yes` |
|
|
259
|
+
| `issues.skia.org` | 200 `yes` |
|
|
260
|
+
| `issues.webrtc.org` | 200 `yes` |
|
|
261
|
+
| `issues.fuchsia.dev` | 200 `yes` |
|
|
262
|
+
| `issues.angleproject.org` | 200 `yes` |
|
|
263
|
+
| `issues.webmproject.org` | 200 `yes` |
|
|
264
|
+
| `issues.oss-fuzz.com` | 200 `yes` |
|
|
265
|
+
| `project-zero.issues.chromium.org` | 200 `yes` |
|
|
266
|
+
| `gn.issues.chromium.org` | 200 `yes` |
|
|
267
|
+
| `git.issues.gerritcodereview.com` | 200 `yes` |
|
|
268
|
+
|
|
269
|
+
## 8. Update request
|
|
270
|
+
|
|
271
|
+
```text
|
|
272
|
+
POST /action/issues/{issue_id}/updates
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Tested. The captured browser request used this form:
|
|
276
|
+
|
|
277
|
+
```text
|
|
278
|
+
[ISSUE_ID, "ASC", 1100, null, 2]
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
| Position | Field | Type | Value |
|
|
282
|
+
|----------|-------|------|-------|
|
|
283
|
+
| `[0]` | issue_id | `int` | Issue ID |
|
|
284
|
+
| `[1]` | sort_order | `str` | `"ASC"` for oldest first or `"DESC"` for newest first |
|
|
285
|
+
| `[2]` | page_size | `int` | 1100 in the tested request |
|
|
286
|
+
| `[3]` | page_token | `str \| null` | Next page token, or `null` for the first page |
|
|
287
|
+
| `[4]` | unknown | `int` | `2` in captured requests; purpose unknown |
|
|
288
|
+
|
|
289
|
+
## 9. Field changes
|
|
290
|
+
|
|
291
|
+
Tested. These fields appeared in `update[5]` of the initial update
|
|
292
|
+
(sequence 1):
|
|
293
|
+
|
|
294
|
+
| Field | Wrapper type | Recorded value |
|
|
295
|
+
|-------|--------------|----------------|
|
|
296
|
+
| `is_archived` | `BoolValue` | Not recorded here |
|
|
297
|
+
| `is_deleted` | `BoolValue` | Not recorded here |
|
|
298
|
+
| `access_limit` | `IssueAccessLimit` | `[1]`; meaning unverified |
|
|
299
|
+
|
|
300
|
+
## 10. Protobuf types
|
|
301
|
+
|
|
302
|
+
Untested. Captured type names include:
|
|
303
|
+
|
|
304
|
+
- `google.devtools.issuetracker.v1.IssueAccessLimit`
|
|
305
|
+
- `google.devtools.issuetracker.v1.User`
|
|
306
|
+
|
|
307
|
+
## 11. Issue timestamps
|
|
308
|
+
|
|
309
|
+
Tested. `TOP` means one issue array. Both `TOP[34]` and `TOP[35]` contained
|
|
310
|
+
`[seconds, nanoseconds]` timestamps in the recorded checks.
|
|
311
|
+
|
|
312
|
+
`TOP[35]` tracked the last write. It matched `modified_at` at `TOP[5]` or
|
|
313
|
+
differed by a few seconds. It changed with automated hotlist and custom
|
|
314
|
+
field updates as well as other writes.
|
|
315
|
+
|
|
316
|
+
`TOP[34]` tracked the last comment or substantive field change, such as a
|
|
317
|
+
status, assignee, or component change. Later automated metadata changes did
|
|
318
|
+
not move it. On issues with those automated changes, `TOP[34] <= TOP[35]`.
|
|
319
|
+
Issues with no comments still had `TOP[34]`, tied to the last substantive
|
|
320
|
+
field change.
|
|
321
|
+
|
|
322
|
+
## 12. Private hotlists
|
|
323
|
+
|
|
324
|
+
```text
|
|
325
|
+
GET /action/hotlists?id=X&id=Y
|
|
326
|
+
GET /action/hotlists/{id}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Untested. The recorded note says batch requests return only accessible
|
|
330
|
+
hotlists and omit private ones. Single requests for private hotlists return
|
|
331
|
+
HTTP 403 according to the same note.
|