@sentry/junior-github 0.107.1 → 0.109.0

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.
package/README.md CHANGED
@@ -24,6 +24,6 @@ export const plugins = defineJuniorPlugins([
24
24
 
25
25
  Full setup guide: https://junior.sentry.dev/extend/github-plugin/
26
26
 
27
- The plugin owns its signed webhook route, normalized pull request outcome
28
- projection, and dashboard operational report. Core only owns delivery from
29
- plugin-published resource events into matching conversation subscriptions.
27
+ The plugin owns its signed webhook route, normalized pull request and issue
28
+ outcome projections, and dashboard operational report. Core only owns delivery
29
+ from plugin-published resource events into matching conversation subscriptions.
package/SETUP.md CHANGED
@@ -68,14 +68,14 @@ vercel env update GITHUB_APP_PRIVATE_KEY production --sensitive < ./github-app-p
68
68
 
69
69
  Repeat for `preview` and `development` as needed. After env changes, redeploy so the new deployment picks up updated values.
70
70
 
71
- ### Optional pull request webhooks and outcome reporting
71
+ ### Optional GitHub webhooks and outcome reporting
72
72
 
73
- To report Junior-created PR outcomes, use the standard GitHub noreply format
74
- `<bot-user-id>+<app-slug>[bot]@users.noreply.github.com` for
73
+ To report Junior-created pull request and issue outcomes, use the standard
74
+ GitHub noreply format `<bot-user-id>+<app-slug>[bot]@users.noreply.github.com` for
75
75
  `GITHUB_APP_BOT_EMAIL` and configure `GITHUB_WEBHOOK_SECRET`. Junior derives
76
76
  the App bot login from that email. Set the GitHub App webhook URL to
77
77
  `https://<junior-host>/api/webhooks/github` and subscribe to Pull request
78
- events. The secret in GitHub must match the deployment environment.
78
+ and Issues events. The secret in GitHub must match the deployment environment.
79
79
 
80
80
  Conversation watches additionally use Check suite, Issue comment, Pull request
81
81
  review, and Pull request review comment events.
@@ -91,8 +91,13 @@ deployed app environment:
91
91
  pnpm exec junior upgrade
92
92
  ```
93
93
 
94
- The migration creates `junior_github_pull_requests`, which backs webhook
95
- ingestion and the `/system` outcome report.
94
+ The migrations create `junior_github_pull_requests` and
95
+ `junior_github_issues`, which back webhook ingestion and the `/system` outcome
96
+ report. When a tracked pull request merges, Junior also reads its commit list
97
+ and records whether every Git author was Junior's configured bot or whether the
98
+ pull request contained non-Junior-authored commits.
99
+ The pull request projection also stores associated native Junior conversation
100
+ ids as an opaque, deduplicated `text[]` without a foreign key.
96
101
 
97
102
  ### Optional permission declaration
98
103
 
@@ -128,8 +133,8 @@ Use `additionalUserScopes` only when a human-identity integration flow requires
128
133
  ## 3) Runtime behavior
129
134
 
130
135
  - When either GitHub skill is active, authenticated `gh` and `git` commands cause the runtime to inject GitHub credentials automatically for the current turn.
131
- - The plugin classifies GitHub traffic from the forwarded HTTP request. Reads use `installation-read`, while `GET /user` uses `user-read`. Allowlisted App-owned mutations, Git smart-HTTP pushes, and user-attachment uploads to `uploads.github.com/user-attachments/assets` use repository-scoped `installation-write`. Unknown REST writes and GraphQL mutations are denied.
132
- - `user-read` and explicitly human `user-write` operations require the actor, or an explicitly delegated user subject, to authorize the GitHub App through the private OAuth flow. Junior-owned issue, pull request, branch, and asset-upload operations do not fall back to user OAuth.
136
+ - The plugin classifies GitHub traffic from the forwarded HTTP request. Reads use `installation-read`, while `GET /user` uses `user-read`. Allowlisted App-owned mutations and Git smart-HTTP pushes use repository-scoped `installation-write`. User-attachment uploads to `uploads.github.com/user-attachments/assets` use `user-write`. Unknown REST writes and GraphQL mutations are denied.
137
+ - `user-read` and explicitly human `user-write` operations require the actor, or an explicitly delegated user subject, to authorize the GitHub App through the private OAuth flow. Junior-owned issue, pull request, and branch operations do not fall back to user OAuth.
133
138
  - Headless resource-event turns use the `resource-event` system actor and may receive the same repository-scoped installation grants. This lets Junior respond to subscribed pull request events by committing and pushing fixes without inheriting a subscriber's OAuth credential.
134
139
  - Git commits use Junior as author and committer. Resolvable human run actors are credited once with `Co-Authored-By` trailers.
135
140
  - Issued credentials are reused only within the current turn, credential leases are cached by plugin grant and repository lease scope, and upstream 403 permission denials clear the cached lease before the next retry.
@@ -0,0 +1,5 @@
1
+ import type { PgDatabase } from "drizzle-orm/pg-core";
2
+ import type { PgQueryResultHKT } from "drizzle-orm/pg-core/session";
3
+ import { githubSqlSchema } from "./schema.js";
4
+ /** Database contract for GitHub-owned projections and reports. */
5
+ export type GitHubDb = PgDatabase<PgQueryResultHKT, typeof githubSqlSchema>;
@@ -5,6 +5,188 @@ export declare const githubPullRequestStateSchema: z.ZodEnum<{
5
5
  closed_unmerged: "closed_unmerged";
6
6
  }>;
7
7
  export type GitHubPullRequestState = z.output<typeof githubPullRequestStateSchema>;
8
+ export declare const githubPullRequestCommitCompositionSchema: z.ZodEnum<{
9
+ junior_only: "junior_only";
10
+ mixed: "mixed";
11
+ }>;
12
+ export type GitHubPullRequestCommitComposition = z.output<typeof githubPullRequestCommitCompositionSchema>;
13
+ export declare const githubIssueStateSchema: z.ZodEnum<{
14
+ open: "open";
15
+ closed: "closed";
16
+ }>;
17
+ export type GitHubIssueState = z.output<typeof githubIssueStateSchema>;
18
+ export declare const githubIssueStateReasonSchema: z.ZodEnum<{
19
+ completed: "completed";
20
+ duplicate: "duplicate";
21
+ not_planned: "not_planned";
22
+ reopened: "reopened";
23
+ }>;
24
+ export type GitHubIssueStateReason = z.output<typeof githubIssueStateReasonSchema>;
25
+ /** Current provider projection for issues classified as Junior-owned. */
26
+ export declare const juniorGitHubIssues: import("drizzle-orm/pg-core").PgTableWithColumns<{
27
+ name: "junior_github_issues";
28
+ schema: undefined;
29
+ columns: {
30
+ issueId: import("drizzle-orm/pg-core").PgColumn<{
31
+ name: "issue_id";
32
+ tableName: "junior_github_issues";
33
+ dataType: "string";
34
+ columnType: "PgText";
35
+ data: string;
36
+ driverParam: string;
37
+ notNull: true;
38
+ hasDefault: false;
39
+ isPrimaryKey: true;
40
+ isAutoincrement: false;
41
+ hasRuntimeDefault: false;
42
+ enumValues: [string, ...string[]];
43
+ baseColumn: never;
44
+ identity: undefined;
45
+ generated: undefined;
46
+ }, {}, {}>;
47
+ repositoryId: import("drizzle-orm/pg-core").PgColumn<{
48
+ name: "repository_id";
49
+ tableName: "junior_github_issues";
50
+ dataType: "string";
51
+ columnType: "PgText";
52
+ data: string;
53
+ driverParam: string;
54
+ notNull: true;
55
+ hasDefault: false;
56
+ isPrimaryKey: false;
57
+ isAutoincrement: false;
58
+ hasRuntimeDefault: false;
59
+ enumValues: [string, ...string[]];
60
+ baseColumn: never;
61
+ identity: undefined;
62
+ generated: undefined;
63
+ }, {}, {}>;
64
+ repositoryFullName: import("drizzle-orm/pg-core").PgColumn<{
65
+ name: "repository_full_name";
66
+ tableName: "junior_github_issues";
67
+ dataType: "string";
68
+ columnType: "PgText";
69
+ data: string;
70
+ driverParam: string;
71
+ notNull: true;
72
+ hasDefault: false;
73
+ isPrimaryKey: false;
74
+ isAutoincrement: false;
75
+ hasRuntimeDefault: false;
76
+ enumValues: [string, ...string[]];
77
+ baseColumn: never;
78
+ identity: undefined;
79
+ generated: undefined;
80
+ }, {}, {}>;
81
+ number: import("drizzle-orm/pg-core").PgColumn<{
82
+ name: "number";
83
+ tableName: "junior_github_issues";
84
+ dataType: "number";
85
+ columnType: "PgInteger";
86
+ data: number;
87
+ driverParam: string | number;
88
+ notNull: true;
89
+ hasDefault: false;
90
+ isPrimaryKey: false;
91
+ isAutoincrement: false;
92
+ hasRuntimeDefault: false;
93
+ enumValues: undefined;
94
+ baseColumn: never;
95
+ identity: undefined;
96
+ generated: undefined;
97
+ }, {}, {}>;
98
+ state: import("drizzle-orm/pg-core").PgColumn<{
99
+ name: "state";
100
+ tableName: "junior_github_issues";
101
+ dataType: "string";
102
+ columnType: "PgText";
103
+ data: "open" | "closed";
104
+ driverParam: string;
105
+ notNull: true;
106
+ hasDefault: false;
107
+ isPrimaryKey: false;
108
+ isAutoincrement: false;
109
+ hasRuntimeDefault: false;
110
+ enumValues: [string, ...string[]];
111
+ baseColumn: never;
112
+ identity: undefined;
113
+ generated: undefined;
114
+ }, {}, {
115
+ $type: "open" | "closed";
116
+ }>;
117
+ stateReason: import("drizzle-orm/pg-core").PgColumn<{
118
+ name: "state_reason";
119
+ tableName: "junior_github_issues";
120
+ dataType: "string";
121
+ columnType: "PgText";
122
+ data: "completed" | "duplicate" | "not_planned" | "reopened";
123
+ driverParam: string;
124
+ notNull: false;
125
+ hasDefault: false;
126
+ isPrimaryKey: false;
127
+ isAutoincrement: false;
128
+ hasRuntimeDefault: false;
129
+ enumValues: [string, ...string[]];
130
+ baseColumn: never;
131
+ identity: undefined;
132
+ generated: undefined;
133
+ }, {}, {
134
+ $type: "completed" | "duplicate" | "not_planned" | "reopened";
135
+ }>;
136
+ openedAt: import("drizzle-orm/pg-core").PgColumn<{
137
+ name: "opened_at";
138
+ tableName: "junior_github_issues";
139
+ dataType: "date";
140
+ columnType: "PgTimestamp";
141
+ data: Date;
142
+ driverParam: string;
143
+ notNull: true;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: undefined;
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {}>;
153
+ closedAt: import("drizzle-orm/pg-core").PgColumn<{
154
+ name: "closed_at";
155
+ tableName: "junior_github_issues";
156
+ dataType: "date";
157
+ columnType: "PgTimestamp";
158
+ data: Date;
159
+ driverParam: string;
160
+ notNull: false;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: undefined;
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, {}, {}>;
170
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
171
+ name: "updated_at";
172
+ tableName: "junior_github_issues";
173
+ dataType: "date";
174
+ columnType: "PgTimestamp";
175
+ data: Date;
176
+ driverParam: string;
177
+ notNull: true;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: undefined;
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, {}, {}>;
187
+ };
188
+ dialect: "pg";
189
+ }>;
8
190
  /** Current provider projection for pull requests classified as Junior-owned. */
9
191
  export declare const juniorGitHubPullRequests: import("drizzle-orm/pg-core").PgTableWithColumns<{
10
192
  name: "junior_github_pull_requests";
@@ -97,6 +279,68 @@ export declare const juniorGitHubPullRequests: import("drizzle-orm/pg-core").PgT
97
279
  }, {}, {
98
280
  $type: "merged" | "open" | "closed_unmerged";
99
281
  }>;
282
+ commitComposition: import("drizzle-orm/pg-core").PgColumn<{
283
+ name: "commit_composition";
284
+ tableName: "junior_github_pull_requests";
285
+ dataType: "string";
286
+ columnType: "PgText";
287
+ data: "junior_only" | "mixed";
288
+ driverParam: string;
289
+ notNull: false;
290
+ hasDefault: false;
291
+ isPrimaryKey: false;
292
+ isAutoincrement: false;
293
+ hasRuntimeDefault: false;
294
+ enumValues: [string, ...string[]];
295
+ baseColumn: never;
296
+ identity: undefined;
297
+ generated: undefined;
298
+ }, {}, {
299
+ $type: "junior_only" | "mixed";
300
+ }>;
301
+ conversationIds: import("drizzle-orm/pg-core").PgColumn<{
302
+ name: "conversation_ids";
303
+ tableName: "junior_github_pull_requests";
304
+ dataType: "array";
305
+ columnType: "PgArray";
306
+ data: string[];
307
+ driverParam: string | string[];
308
+ notNull: true;
309
+ hasDefault: true;
310
+ isPrimaryKey: false;
311
+ isAutoincrement: false;
312
+ hasRuntimeDefault: false;
313
+ enumValues: [string, ...string[]];
314
+ baseColumn: import("drizzle-orm").Column<{
315
+ name: "conversation_ids";
316
+ tableName: "junior_github_pull_requests";
317
+ dataType: "string";
318
+ columnType: "PgText";
319
+ data: string;
320
+ driverParam: string;
321
+ notNull: false;
322
+ hasDefault: false;
323
+ isPrimaryKey: false;
324
+ isAutoincrement: false;
325
+ hasRuntimeDefault: false;
326
+ enumValues: [string, ...string[]];
327
+ baseColumn: never;
328
+ identity: undefined;
329
+ generated: undefined;
330
+ }, {}, {}>;
331
+ identity: undefined;
332
+ generated: undefined;
333
+ }, {}, {
334
+ baseBuilder: import("drizzle-orm/pg-core").PgColumnBuilder<{
335
+ name: "conversation_ids";
336
+ dataType: "string";
337
+ columnType: "PgText";
338
+ data: string;
339
+ enumValues: [string, ...string[]];
340
+ driverParam: string;
341
+ }, {}, {}, import("drizzle-orm").ColumnBuilderExtraConfig>;
342
+ size: undefined;
343
+ }>;
100
344
  openedAt: import("drizzle-orm/pg-core").PgColumn<{
101
345
  name: "opened_at";
102
346
  tableName: "junior_github_pull_requests";
@@ -169,6 +413,170 @@ export declare const juniorGitHubPullRequests: import("drizzle-orm/pg-core").PgT
169
413
  dialect: "pg";
170
414
  }>;
171
415
  export declare const githubSqlSchema: {
416
+ juniorGitHubIssues: import("drizzle-orm/pg-core").PgTableWithColumns<{
417
+ name: "junior_github_issues";
418
+ schema: undefined;
419
+ columns: {
420
+ issueId: import("drizzle-orm/pg-core").PgColumn<{
421
+ name: "issue_id";
422
+ tableName: "junior_github_issues";
423
+ dataType: "string";
424
+ columnType: "PgText";
425
+ data: string;
426
+ driverParam: string;
427
+ notNull: true;
428
+ hasDefault: false;
429
+ isPrimaryKey: true;
430
+ isAutoincrement: false;
431
+ hasRuntimeDefault: false;
432
+ enumValues: [string, ...string[]];
433
+ baseColumn: never;
434
+ identity: undefined;
435
+ generated: undefined;
436
+ }, {}, {}>;
437
+ repositoryId: import("drizzle-orm/pg-core").PgColumn<{
438
+ name: "repository_id";
439
+ tableName: "junior_github_issues";
440
+ dataType: "string";
441
+ columnType: "PgText";
442
+ data: string;
443
+ driverParam: string;
444
+ notNull: true;
445
+ hasDefault: false;
446
+ isPrimaryKey: false;
447
+ isAutoincrement: false;
448
+ hasRuntimeDefault: false;
449
+ enumValues: [string, ...string[]];
450
+ baseColumn: never;
451
+ identity: undefined;
452
+ generated: undefined;
453
+ }, {}, {}>;
454
+ repositoryFullName: import("drizzle-orm/pg-core").PgColumn<{
455
+ name: "repository_full_name";
456
+ tableName: "junior_github_issues";
457
+ dataType: "string";
458
+ columnType: "PgText";
459
+ data: string;
460
+ driverParam: string;
461
+ notNull: true;
462
+ hasDefault: false;
463
+ isPrimaryKey: false;
464
+ isAutoincrement: false;
465
+ hasRuntimeDefault: false;
466
+ enumValues: [string, ...string[]];
467
+ baseColumn: never;
468
+ identity: undefined;
469
+ generated: undefined;
470
+ }, {}, {}>;
471
+ number: import("drizzle-orm/pg-core").PgColumn<{
472
+ name: "number";
473
+ tableName: "junior_github_issues";
474
+ dataType: "number";
475
+ columnType: "PgInteger";
476
+ data: number;
477
+ driverParam: string | number;
478
+ notNull: true;
479
+ hasDefault: false;
480
+ isPrimaryKey: false;
481
+ isAutoincrement: false;
482
+ hasRuntimeDefault: false;
483
+ enumValues: undefined;
484
+ baseColumn: never;
485
+ identity: undefined;
486
+ generated: undefined;
487
+ }, {}, {}>;
488
+ state: import("drizzle-orm/pg-core").PgColumn<{
489
+ name: "state";
490
+ tableName: "junior_github_issues";
491
+ dataType: "string";
492
+ columnType: "PgText";
493
+ data: "open" | "closed";
494
+ driverParam: string;
495
+ notNull: true;
496
+ hasDefault: false;
497
+ isPrimaryKey: false;
498
+ isAutoincrement: false;
499
+ hasRuntimeDefault: false;
500
+ enumValues: [string, ...string[]];
501
+ baseColumn: never;
502
+ identity: undefined;
503
+ generated: undefined;
504
+ }, {}, {
505
+ $type: "open" | "closed";
506
+ }>;
507
+ stateReason: import("drizzle-orm/pg-core").PgColumn<{
508
+ name: "state_reason";
509
+ tableName: "junior_github_issues";
510
+ dataType: "string";
511
+ columnType: "PgText";
512
+ data: "completed" | "duplicate" | "not_planned" | "reopened";
513
+ driverParam: string;
514
+ notNull: false;
515
+ hasDefault: false;
516
+ isPrimaryKey: false;
517
+ isAutoincrement: false;
518
+ hasRuntimeDefault: false;
519
+ enumValues: [string, ...string[]];
520
+ baseColumn: never;
521
+ identity: undefined;
522
+ generated: undefined;
523
+ }, {}, {
524
+ $type: "completed" | "duplicate" | "not_planned" | "reopened";
525
+ }>;
526
+ openedAt: import("drizzle-orm/pg-core").PgColumn<{
527
+ name: "opened_at";
528
+ tableName: "junior_github_issues";
529
+ dataType: "date";
530
+ columnType: "PgTimestamp";
531
+ data: Date;
532
+ driverParam: string;
533
+ notNull: true;
534
+ hasDefault: false;
535
+ isPrimaryKey: false;
536
+ isAutoincrement: false;
537
+ hasRuntimeDefault: false;
538
+ enumValues: undefined;
539
+ baseColumn: never;
540
+ identity: undefined;
541
+ generated: undefined;
542
+ }, {}, {}>;
543
+ closedAt: import("drizzle-orm/pg-core").PgColumn<{
544
+ name: "closed_at";
545
+ tableName: "junior_github_issues";
546
+ dataType: "date";
547
+ columnType: "PgTimestamp";
548
+ data: Date;
549
+ driverParam: string;
550
+ notNull: false;
551
+ hasDefault: false;
552
+ isPrimaryKey: false;
553
+ isAutoincrement: false;
554
+ hasRuntimeDefault: false;
555
+ enumValues: undefined;
556
+ baseColumn: never;
557
+ identity: undefined;
558
+ generated: undefined;
559
+ }, {}, {}>;
560
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
561
+ name: "updated_at";
562
+ tableName: "junior_github_issues";
563
+ dataType: "date";
564
+ columnType: "PgTimestamp";
565
+ data: Date;
566
+ driverParam: string;
567
+ notNull: true;
568
+ hasDefault: false;
569
+ isPrimaryKey: false;
570
+ isAutoincrement: false;
571
+ hasRuntimeDefault: false;
572
+ enumValues: undefined;
573
+ baseColumn: never;
574
+ identity: undefined;
575
+ generated: undefined;
576
+ }, {}, {}>;
577
+ };
578
+ dialect: "pg";
579
+ }>;
172
580
  juniorGitHubPullRequests: import("drizzle-orm/pg-core").PgTableWithColumns<{
173
581
  name: "junior_github_pull_requests";
174
582
  schema: undefined;
@@ -260,6 +668,68 @@ export declare const githubSqlSchema: {
260
668
  }, {}, {
261
669
  $type: "merged" | "open" | "closed_unmerged";
262
670
  }>;
671
+ commitComposition: import("drizzle-orm/pg-core").PgColumn<{
672
+ name: "commit_composition";
673
+ tableName: "junior_github_pull_requests";
674
+ dataType: "string";
675
+ columnType: "PgText";
676
+ data: "junior_only" | "mixed";
677
+ driverParam: string;
678
+ notNull: false;
679
+ hasDefault: false;
680
+ isPrimaryKey: false;
681
+ isAutoincrement: false;
682
+ hasRuntimeDefault: false;
683
+ enumValues: [string, ...string[]];
684
+ baseColumn: never;
685
+ identity: undefined;
686
+ generated: undefined;
687
+ }, {}, {
688
+ $type: "junior_only" | "mixed";
689
+ }>;
690
+ conversationIds: import("drizzle-orm/pg-core").PgColumn<{
691
+ name: "conversation_ids";
692
+ tableName: "junior_github_pull_requests";
693
+ dataType: "array";
694
+ columnType: "PgArray";
695
+ data: string[];
696
+ driverParam: string | string[];
697
+ notNull: true;
698
+ hasDefault: true;
699
+ isPrimaryKey: false;
700
+ isAutoincrement: false;
701
+ hasRuntimeDefault: false;
702
+ enumValues: [string, ...string[]];
703
+ baseColumn: import("drizzle-orm").Column<{
704
+ name: "conversation_ids";
705
+ tableName: "junior_github_pull_requests";
706
+ dataType: "string";
707
+ columnType: "PgText";
708
+ data: string;
709
+ driverParam: string;
710
+ notNull: false;
711
+ hasDefault: false;
712
+ isPrimaryKey: false;
713
+ isAutoincrement: false;
714
+ hasRuntimeDefault: false;
715
+ enumValues: [string, ...string[]];
716
+ baseColumn: never;
717
+ identity: undefined;
718
+ generated: undefined;
719
+ }, {}, {}>;
720
+ identity: undefined;
721
+ generated: undefined;
722
+ }, {}, {
723
+ baseBuilder: import("drizzle-orm/pg-core").PgColumnBuilder<{
724
+ name: "conversation_ids";
725
+ dataType: "string";
726
+ columnType: "PgText";
727
+ data: string;
728
+ enumValues: [string, ...string[]];
729
+ driverParam: string;
730
+ }, {}, {}, import("drizzle-orm").ColumnBuilderExtraConfig>;
731
+ size: undefined;
732
+ }>;
263
733
  openedAt: import("drizzle-orm/pg-core").PgColumn<{
264
734
  name: "opened_at";
265
735
  tableName: "junior_github_pull_requests";