fix: smarter fallback team selection for scope inference#120
fix: smarter fallback team selection for scope inference#120
Conversation
… is part of as a fallback
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Instead of always falling back to the username, prefer the user's configured default team (defaultTeamId). Falls back to username when defaultTeamId is not set. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
marc-vercel
left a comment
There was a problem hiding this comment.
Overall LGTM, left 3 comments (two of them are optional).
I see that the tests mock the API response, but given that we are changing API requests/responses, have we manually tested all the flows? If possible I would love to have some integration tests, but because we are dealing with auth I do not think it will be easy.
|
|
||
| throw new NotOk({ | ||
| statusCode: 403, | ||
| responseText: `Authenticated as "${username}" but none of the available teams allow sandbox creation. Specify a team explicitly with --scope <team-id-or-slug>.`, |
There was a problem hiding this comment.
Not a blocker: it would be nice to know which teams have we tried.
| ): Promise<{ candidateTeamIds: string[]; username: string }> { | ||
| const [userData, teamsData] = await Promise.all([ | ||
| fetchApi({ token, endpoint: "/v2/user" }).then(UserSchema.parse), | ||
| fetchApi({ token, endpoint: "/v2/teams?limit=100" }).then( |
There was a problem hiding this comment.
What happens if the user has more than 100 teams? I understand we are just covering the first 100 teams.
This is unlikely, but we should iterate on that. Not a blocker.
| token: opts.token, | ||
| endpoint: `/v11/projects?slug=${encodeURIComponent(teamId)}`, | ||
| token, | ||
| endpoint: `/v11/projects?${teamParam}`, |
There was a problem hiding this comment.
Does this API endpoint ensures that the user can read sandboxes? Afaik it just checks that the user can read the project no?
For example, we require the Resource.VercelSandbox scope at the API level to read a sandbox.
There was a problem hiding this comment.
best we can do right now is to filter by OWNER roles
sandbox/packages/vercel-sandbox/src/auth/project.ts
Lines 151 to 153 in e3e173a
I don't think there is a way to retrieve a list of teams filtered by a specific permission yet
There was a problem hiding this comment.
So, this means we can login as a team that does not have permissions. I understand that this is already happening no? If so we can iterate on that later.
| ): Promise<{ candidateTeamIds: string[]; username: string }> { | ||
| const [userData, teamsData] = await Promise.all([ | ||
| fetchApi({ token, endpoint: "/v2/user" }).then(UserSchema.parse), | ||
| fetchApi({ token, endpoint: "/v2/teams?limit=100" }).then( |
There was a problem hiding this comment.
Fetching all the teams (up to 100) will be quite slow right? In which case would a user not have a defaultTeamId?
There was a problem hiding this comment.
defaultTeamId is not always set. But we can request them sequentially
Ideally the /v2/teams endpoint would have a access/permission based filter and sort argument, then we'd only need to get one.
Summary
/v2/userand/v2/teamsin parallel to build an ordered list of candidate teams for scope inferenceuser.defaultTeamIdfirst, then falls back to the best hobby-plan OWNER team (personal team matching username, or most recently updated)billing.plan === 'hobby'andmembership.role === 'OWNER'to avoid selecting pro/enterprise teams