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 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.