@sentry/junior-google 0.267.0 → 0.269.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
@@ -1,207 +1,29 @@
1
1
  # @sentry/junior-google
2
2
 
3
- Proof of concept. Junior acts as its own Google Workspace account, for example
4
- `junior@sentry.io`. Junior does not use the Google credentials of the people it
5
- helps. Tracking issue: getsentry/junior#2063.
6
-
7
- This version supports Calendar, Meet transcripts, and reading Google Docs,
8
- Sheets, and Slides.
9
- Gmail and Drive writes are out of scope.
10
-
11
- ## Surfaces
12
-
13
- - `findMeetingTimes` finds times when every required attendee is free and
14
- inside working hours (09:00 to 17:00 by default) in the time zone of their
15
- own calendar. It reads free/busy data and calendar time zones only. It never
16
- reads event titles or details. Optional attendees do not block a slot.
17
- Slots where they are free come first, and each slot names the optional
18
- attendees who are busy or off hours. A search can be limited to some
19
- weekdays, such as Wednesdays and Fridays for a weekly meeting. A search
20
- covers at most 14 days, counted on the local clock, so a daylight-saving
21
- change does not shorten it. Slots are spread across days and across each
22
- day, so the requester gets a real choice.
23
- - Every Calendar tool takes an optional `timeZone` for the times it reads and
24
- shows. Without it, the tool uses the requester's timezone from
25
- `ctx.users.resolveTimezone()`, so Junior does not have to ask for one.
26
- - `createCalendarEvent` creates an event on Junior's own calendar. It sends
27
- invites and always adds a Google Meet link. It can add a location, optional
28
- attendees, and a simple repeat rule (weekdays, weekly, or monthly). A retry of the same
29
- tool call returns the same event. It does not create a second invite.
30
- - `listCalendarEvents` reads the events on one colleague's calendar, or on
31
- Junior's own calendar when no calendar is given. It shows only what the
32
- calendar's Google sharing settings let Junior's account see. A calendar
33
- shared as free/busy only shows busy blocks without titles. It never returns
34
- event descriptions. Each event says whether Junior organizes it, and gives
35
- attendee responses and the series id of a repeating event.
36
- - `updateCalendarEvent` and `cancelCalendarEvent` accept an event id or a
37
- Google Calendar event link.
38
- - `updateCalendarEvent` changes the title, description, time, location, video
39
- call, or attendees of an event that Junior organizes. Google emails the
40
- attendees about the change. Only people invited to the event can ask for a
41
- change.
42
- - `cancelCalendarEvent` deletes an event that Junior organizes. Google removes
43
- it from every attendee's calendar and emails them a cancellation. Only
44
- people invited to the event can ask to cancel it.
45
- - `createCalendarEvent` and `updateCalendarEvent` save a Calendar event
46
- annotation on the Conversation. Junior shows its card with the next reply.
47
- The card shows the title, time, and attendees, and links to the event. A
48
- change to an event replaces its card.
49
- - `searchGoogleFiles` finds Google Docs, Sheets, and Slides that are shared
50
- with Junior's account, by words in the title or text. A search can ask for only
51
- some of these types. Files that are only shared by public link are not found,
52
- because Drive search only covers files the account has.
53
- - The read tools take a link or a file id. They work for files shared with
54
- Junior's account and for files shared with anyone who has the link. A link's
55
- `resourcekey` value is sent to Google, because older files shared by link
56
- need it. Each result stops at 100,000 characters.
57
- - `readGoogleDoc` reads one Doc as Markdown. Drive exports the Doc, so the
58
- Docs API is not used.
59
- - `readGoogleSheet` reads the cells of one Sheet as CSV, with values formatted
60
- as the Sheet shows them. It reads every tab, or one A1 range such as
61
- `Budget!A1:F50`. The result names every tab, so Junior can ask for a smaller
62
- range when a Sheet is too large. A Drive CSV export has only the first tab,
63
- so this tool uses the Sheets API.
64
- - `readGoogleSlides` reads the text and speaker notes of each slide, with
65
- tables as `|` rows. It uses the Slides API to keep slide numbers and notes.
66
- - `listGoogleFileComments` reads the comments and replies on one Doc, Sheet,
67
- or Slides file, 100 per call. Each comment gives its author name, text, the
68
- file text it is attached to, and whether it is resolved.
69
- - `readMeetingTranscript` reads the Meet transcript and Gemini notes of one
70
- meeting on Junior's calendar. Junior and the requester must both be invited
71
- to the meeting. Junior does not have to join the call. When someone turns on
72
- transcription or Gemini notes, Google saves them as Docs in the organizer's
73
- Drive, attaches them to the Calendar event, and shares them with every
74
- invitee in the organizer's domain. The tool reads these Docs from the event
75
- attachments, so it needs no Meet scope. It reads an attached Doc only when
76
- the organizer owns it and it was made after the meeting started. Thus a Doc
77
- that someone else attaches to the event, or an agenda made before the
78
- meeting, is not read. It does not require a title format, because Meet can
79
- change the titles and they differ by language. The title only sets `kind`.
80
- Google can take from some minutes to a few hours after the call to attach
81
- the records, so an automation must allow for this delay. The result marks
82
- the text as untrusted. The tool only reads. Junior acts on what was said
83
- only when the requester or an automation asks for it.
84
- - A transcript of a long meeting can be megabytes. The result returns at
85
- most 100,000 characters inline. The tool saves the full text of each cut
86
- record to a Markdown file in the Conversation sandbox, under `meetings/`,
87
- and returns its `path`. Junior then reads or searches the full file in
88
- parts. Drive cannot export a Doc larger than 10 MB.
89
- - The **Google account** page on the dashboard Admin page shows whether the
90
- account is connected. Its Connect button starts Google sign-in.
91
- - `junior google connect` and `junior google status` are the operator CLI.
92
-
93
- ## Authentication
94
-
95
- A Junior admin connects the account one time, out of band. Slack never shows
96
- the sign-in link, the authorization code, or any token. Junior admins are
97
- managed with `junior admin grant <email>`. This plugin has no admin list of its
98
- own.
99
-
100
- 1. An admin opens **Admin → Google account** in the dashboard and selects
101
- **Connect**, or runs `junior google connect`.
102
- 2. Google sign-in opens with PKCE and a single-use state value.
103
- 3. The admin signs in as the configured account, not as themselves.
104
- 4. Junior checks that the identity token names the configured account. It also
105
- checks that Google granted every Calendar and Drive scope. If a check
106
- fails, Junior revokes the grant and stores nothing.
107
- 5. Junior stores the refresh token in the `junior_google_accounts` table.
108
-
109
- At runtime, the `issueCredential` hook exchanges the refresh token for a
110
- one-hour access token. Junior applies that token only to `www.googleapis.com`
111
- requests from this plugin's tools. The `grantForEgress` hook denies sandbox
112
- commands and any request that does not match a declared operation. Thus the
113
- model cannot use `curl` to read Junior's calendar or Drive and skip the tool
114
- rules.
115
-
116
- If Google rejects the refresh token (`invalid_grant`), Junior deletes it. The
117
- tools then report that an admin must connect the account again. If the stored
118
- grant does not have every scope the current tools need, Google rejects the
119
- request and the tool asks an admin to reconnect.
120
-
121
- ## Rules in code
122
-
123
- - Junior checks and invites only people in the allowed domains. By default,
124
- the allowed domain is the domain of the account email.
125
- - Junior adds the requester to the attendees when it knows their email.
126
- - Junior changes or cancels only events that it organizes, and only for a
127
- requester who is invited to the event. The `calendar.events.owned` scope
128
- also keeps events that other people organize out of reach.
129
- - Calendar scopes are `calendar.events.freebusy`, `calendar.events.readonly`,
130
- and `calendar.events.owned`.
131
- - The Drive scope is `drive.readonly`. The Drive comments API accepts no
132
- narrower read scope, and the Sheets and Slides APIs also accept it. Junior
133
- permits only these requests: Drive file search, file metadata, export, and
134
- comment reads; Sheets metadata and cell reads; and Slides reads. Each
135
- request must go to the host of its own API.
136
- - Junior also requests `openid email` to verify the account during sign-in.
137
- - Drive sharing decides which files Junior can read. The file tools read
138
- any Doc, Sheet, or Slides file shared with Junior's account. This includes
139
- Meet transcripts and Gemini notes, which Google shares with Junior when it
140
- is invited. `readMeetingTranscript` finds the records from the Calendar
141
- event and adds the invite checks. It is not the only way to read them.
3
+ Proof of concept. Junior uses its own Google Workspace account, such as
4
+ `junior@example.com`, to schedule meetings, read Meet transcripts, and read
5
+ Google Docs, Sheets, and Slides that are shared with that account. Junior does
6
+ not use the Google credentials of the people it helps.
142
7
 
143
8
  ## Setup
144
9
 
145
- The plugin uses the same Google OAuth client as dashboard sign-in. Each
146
- sign-in requests only its own scopes, so dashboard sign-in still asks only for
147
- identity.
148
-
149
10
  1. In the Google Cloud project of the dashboard OAuth client, enable the
150
- Google Calendar API, Google Drive API, Google Sheets API, and Google Slides
151
- API. If an API is not enabled, its tool tells the requester that an admin
152
- must enable it.
153
- 2. On the OAuth consent screen, use user type **Internal** and add the
154
- Calendar and Drive scopes above. `drive.readonly` is a restricted scope.
155
- An Internal app does not need Google verification for it.
156
- 3. On the OAuth client, add these redirect URIs:
157
- - `https://<junior host>/api/plugins/google/oauth/callback`
158
- - `http://127.0.0.1:8765/oauth/callback`, for the CLI. Use another port with
159
- `junior google connect --port`.
11
+ Calendar, Drive, Sheets, and Slides APIs.
12
+ 2. Use an **Internal** consent screen. Add the scopes
13
+ `calendar.events.freebusy`, `calendar.events.readonly`,
14
+ `calendar.events.owned`, and `drive.readonly`.
15
+ 3. Add the redirect URIs
16
+ `https://<junior host>/api/plugins/google/oauth/callback` and
17
+ `http://127.0.0.1:8765/oauth/callback` (CLI).
160
18
  4. Give the Junior account a Workspace license.
161
- 5. Set these environment variables on the deployment:
162
-
163
- | Variable | Purpose |
164
- | ---------------------------------- | ----------------------------------------------- |
165
- | `GOOGLE_CLIENT_ID` | OAuth client id, shared with dashboard sign-in |
166
- | `GOOGLE_CLIENT_SECRET` | OAuth client secret |
167
- | `GOOGLE_WORKSPACE_ACCOUNT_EMAIL` | The account Junior acts as |
168
- | `GOOGLE_WORKSPACE_ALLOWED_DOMAINS` | Optional comma-separated domains to schedule in |
169
-
170
- The plugin registers no tools and no sign-in routes until the first three
171
- variables are set. The Admin page shows **Not configured** until then.
172
-
173
- 6. Run `junior upgrade` to create the table.
174
- 7. Run `junior admin grant <email>` for each person who may connect the account.
175
- 8. Connect the account on **Admin → Google account**, or run
176
- `junior google connect` with the deployment database configured.
19
+ 5. Set `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`,
20
+ `GOOGLE_WORKSPACE_ACCOUNT_EMAIL`, and optionally
21
+ `GOOGLE_WORKSPACE_ALLOWED_DOMAINS`.
22
+ 6. Run `junior upgrade`, then `junior admin grant <email>` for each admin.
23
+ 7. Connect the account on **Admin → Google account** in the dashboard, or run
24
+ `junior google connect`.
177
25
 
178
- ## Known gaps
26
+ Anyone who can talk to Junior can read what the Junior account can see. Share
27
+ calendars and files with that account only when that is acceptable.
179
28
 
180
- - The refresh token is stored in plain text in Postgres. Encryption at rest is
181
- tracked in getsentry/junior#2065.
182
- - Free/busy and event details show only what the company's calendar sharing
183
- default allows. Calendars that Junior cannot see appear in `unavailable`
184
- for `findMeetingTimes`, and as `visible: false` for `listCalendarEvents`.
185
- - Anyone who can talk to Junior can ask it to read a colleague's calendar.
186
- Junior returns what its own account can see, so set the sharing default
187
- with that in mind.
188
- - Anyone who can talk to Junior can also ask it to read any file shared with
189
- Junior's account. Share a file with that account only when everyone who can
190
- talk to Junior may read it.
191
- - `drive.readonly` lets the account read every Drive file it can open. The
192
- tools read only Google Docs, Sheets, and Slides.
193
- - `readGoogleSheet` does not return formulas, notes on cells, or charts.
194
- `readGoogleSlides` does not describe images or charts.
195
- - Google does not expose the working hours that people set in Calendar.
196
- Junior uses each calendar's time zone and one shared workday instead.
197
- - Junior cannot find or book meeting rooms. Room discovery needs the Admin
198
- SDK `admin.directory.resource.calendar.readonly` scope and a Workspace
199
- admin role on Junior's account. Room emails are also outside the allowed
200
- domains. It cannot accept or decline invites for other people.
201
- - Google does not share Meet records with invitees when more than 200 people
202
- in the organizer's domain are invited.
203
- - Junior reads a transcript only when someone asks. No event tells
204
- automations that a transcript is ready yet. Tracking issue:
205
- getsentry/junior#2100.
206
- - No disconnect command. To revoke access, remove the app grant from the
207
- Junior account in Google.
29
+ Plugin setup: https://junior.sentry.dev/extend/
@@ -5,7 +5,7 @@ import { type GoogleToolContext } from "./shared";
5
5
  *
6
6
  * Anyone who can edit an event can attach any Doc, so the tool reads only
7
7
  * attached Docs that the organizer owns and that were made for this meeting.
8
- * The package README explains how Google shares the records.
8
+ * The package AGENTS.md has the transcript rules.
9
9
  */
10
10
  export declare function createReadMeetingTranscriptTool(ctx: GoogleToolContext): import("@sentry/junior-plugin-api").PluginToolDefinition<{
11
11
  eventId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-google",
3
- "version": "0.267.0",
3
+ "version": "0.269.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,7 +25,7 @@
25
25
  "commander": "^14.0.3",
26
26
  "drizzle-orm": "^0.45.2",
27
27
  "zod": "^4.5.4",
28
- "@sentry/junior-plugin-api": "0.267.0"
28
+ "@sentry/junior-plugin-api": "0.269.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@oxlint/plugins": "1.79.0",