Roles and permissions

A person's authority comes from their role in a workspace. A workspace token's authority comes from its scopes. Teams have no roles of their own: a workspace's members may work in every team of that workspace. Reading how a team's work turned out is narrower; see Team outcomes.

Roles

RoleRankPermissions
owner2read, plan, configure, manage-secrets, manage-runners, manage-token-trusts, administer
admin1read, plan, configure, manage-secrets, manage-runners, manage-token-trusts, administer
member0read, plan

The web app shows the roles as Owner, Admin and Member. The person who creates a workspace is its owner. A person who accepts an invite joins with the role the invite gives, admin or member. A workspace always has at least one owner.

A closed workspace grants nothing to anyone.

Permissions

PermissionAllowsGranted to
readSee a workspace and its resources, and export it as Terraform.Every role. Every token.
planCheck expressions, at POST /api/expressions/check. Open, change and delete replay sets, mark the set that guards a station's changes, start and stop replays, propose and withdraw replay candidates, start and stop searches, pick a search's candidate, and start replay checks, on a team whose outcomes the caller may read.Every person. Tokens with plan or configure.
configureCreate, change and delete teams, lines, integrations, hooks, skills and harness profiles; change the workspace.Owners, admins. Tokens with configure.
manage-secretsCreate, change and delete secrets.Owners, admins. Tokens with secrets.
manage-runnersCreate, change and delete runner pools, runner trusts and workspace runners.Owners, admins. Tokens with runners.
manage-token-trustsCreate, change and delete workspace token trusts.Owners, admins. Tokens with trusts.
administerIssue, change and revoke workspace tokens; read configuration changes; close the workspace; invite people, list, resend and revoke invites, and add members to teams; connect GitHub; connect the team to an integration over OAuth.Owners, admins. Never a token.
open-workspacesCreate a workspace.Every signed-in person. Never a token.

A request for something the caller cannot see returns 404. A request to change something the caller can see but may not change returns 403:

Permission missingTitle
configure, manage-secrets, manage-runners, manage-token-trustsNot allowed to change the <kind>
administerNot allowed to administer the <kind>
open-workspacesNot allowed to open a workspace
planNot allowed to plan

See Resource API for the error format.

Token scopes

A workspace token carries one or more scopes. Each scope grants itself and the scopes listed beside it.

ScopeAlso grantsPermissions
readread
planreadread, plan
configureplan, readread, plan, configure
secretsreadread, manage-secrets
runnersreadread, manage-runners
trustsreadread, manage-token-trusts

A token's scopes must include read, plan or configure, and name each scope once; see Scopes for the messages. A token acts only in its own workspace. See spotlight_workspace_token_trust for tokens a trust mints.

Team outcomes

How a team's work turned out can be read only by:

  • people on the team;
  • the workspace's owners and admins;
  • workspace tokens of the workspace with the read scope.

Anyone else is answered 404, as for something that does not exist.

OutcomeWhere
Station outcomes"Latest runs on this config", "Recent runs" and "Version" on a work station's "Overview" tab, and "Runs by config" on the station's view on Insights. See Station outcomes.
JudgeThe judge's agreement with people under "Judge" on a work station's "Overview" tab and under "How far to trust the judge" on the station's view on Insights, a run's judge score and people's grades, and grading a run. See Judge and alerts, Agreement and Grades.
Grade itemsInbox items asking to grade a run. They reach no one else.
Station alert itemsInbox items saying a station crossed one of its alert thresholds. They reach no one else.
InsightsEvery tab of a team's Insights page, the Insights API, and the Replayed candidates API.
ReplaysA work station's "Replays" section, its replay sets, replays and replay runs, the Replays API, and the team's replay candidates. Changing them also needs plan. A replay run, with its config and event stream, is readable only through the team it replayed for, even after its station is removed. See Replays.
Searches and replay checksA work station's "Searches" section, its searches, the pull requests picked candidates open, and its replay checks: the Searches API and the Replay checks API. Estimating a search needs only read. Starting and stopping a search, picking a candidate, marking a guarding set and starting a check also need plan. See Searches.

Members

GET /api/workspaces/{slug}/members lists everyone in the workspace, with their role, their teams and the roles the caller may give them. Every member of the workspace may read it. The web app's Members page (see Web app) is shown only to owners and admins; a member who opens it is sent to the workspace's own route.

Changing roles

Roles are changed on the Members page, in the "Members" list of any team's "General" settings page, or with PATCH /api/workspaces/{slug}/members/{userId}. The role changed is the person's role in the workspace, and holds in every team.

  • Only an owner or an admin may set roles.
  • An owner may change anyone's role, including their own.
  • An admin may change only members, and may not give the owner role.
  • The last owner may not be given another role.

For an owner or admin, setting a person's role to the one they already hold changes nothing and is not refused. A refused change returns one of these:

StatusMessageCause
403This person is not a member of this workspace.The person is not a member of the workspace.
403Only an owner or an admin can set roles.The caller is not an owner or admin.
403You can only set roles for people below you.An admin changing an owner or another admin.
403You cannot change your own role.An admin changing their own role.
403You cannot give a role above your own.An admin giving the owner role.
409The workspace needs at least one owner. Please make someone else an owner first.The last owner given another role.

The web app offers a role menu only where more than one role can be given.

Invites

An invite asks one email address to join the workspace with a role, and optionally names teams of the workspace to join.

ActionEndpointWho may
InvitePOST /api/workspaces/{slug}/invitesOwners and admins.
List pending invitesGET /api/workspaces/{slug}/invitesOwners and admins.
Send an invite againPOST /api/workspaces/{slug}/invites/{inviteId}/resendOwners and admins.
Revoke an inviteDELETE /api/workspaces/{slug}/invites/{inviteId}Owners and admins.
Read what an invite link offersGET /api/invites/{token}Anyone with the link, signed in or not.
Accept an invitePOST /api/invites/{token}/acceptThe person signed in with the invited address.
Add a member to a teamPOST /api/teams/{teamId}/membersOwners and admins.

Every action but reading an invite link needs a person signed in; a workspace token is answered 401. A caller who is not an owner or admin of the workspace is answered 404 by the actions only they may take, as for a workspace that does not exist.

  • An invite gives the admin or member role. Nobody is invited as an owner; owners and admins may both invite as admin.
  • One request invites 1 to 50 addresses, all with the same role and teams. Addresses are compared without regard to case, and a repeated address is invited once.
  • An address that belongs to a member of the workspace is sent nothing.
  • An address with an open or expired invite is sent it again, with a new link, the role and teams of this request, and a fresh 14 days. An address whose invite was revoked or accepted gets a new invite.
  • Sending an invite again replaces its link; the old link stops working. Only an open or expired invite can be sent again.
  • Revoking an invite stops its link working. Revoking a revoked invite changes nothing. An accepted invite cannot be revoked.
  • An invite lasts 14 days from when it was last sent.
  • Accepting needs the person to be signed in with the invited address, compared without regard to case, and the invite to be open.
  • Accepting adds the person to the workspace with the invite's role, and to each team it names that still belongs to the workspace. A person already in the workspace keeps their role and is added to the teams.
  • The pending invites list holds only open invites, newest first.
  • Adding a member to a team needs the person to be in the workspace already.

Each address in an invite request gets one outcome:

OutcomeWeb appMeaning
invited"Invited"A new invite was emailed.
sent-again"Sent again"An open or expired invite was emailed again.
already-a-member"Already a member"The address belongs to a member. Nothing was sent.
not-sent"Not sent. Please resend it from Pending invites."The invite was written but the email could not be sent.

The email's subject reads <inviter> invited you to join <workspace> on Spotlight, names the teams the invite joins, and links to /invites/<token> at the Spotlight address. When the control plane has no mail server set (SMTP_URL), the message is written to its log instead of sent.

StateMeaning
openSent, not yet accepted, revoked or expired.
acceptedAccepted.
revokedTaken back.
expiredNot accepted within 14 days of being last sent.

Errors and messages lists the refusals. See Invite people and change their roles and Join a workspace from an invitation.

Actions only people can take

These need a person signed in to Spotlight. A workspace token is refused:

ActionNeeds
Anything under administerAn owner or admin.
Creating a workspaceAny signed-in person.
Approving, editing or dismissing a tool call or harness permissionThe assignee of the task that asks. A call that asks because of a person's own tool rule is put to that person, and only they can approve it.

Answering the inbox, saying something to a run and stopping a run are also reserved to the task's assignee.

GitHub connection

Connecting a GitHub App installation to a workspace needs both:

ConditionChecked by
The person is an owner or admin of the workspace.Their workspace role.
The person administers the installation.GitHub, with the person's GitHub sign-in. For an organisation's installation, they are an active admin of the organisation. For a user's installation, they are that user.
StatusMessageCause
403Only a workspace owner or admin can connect GitHub.Not an owner or admin.
403You are not an admin of this GitHub installation.Not the installation's administrator.
403GitHub could not confirm this installation is yours. Please sign in again.GitHub would not say.
409GitHub installation <id> is connected to another workspace. Please disconnect it there first.Connected to another workspace.

One installation connects one workspace. See Installation callback and Connect GitHub to a workspace.

Integration connections

An integration that links over OAuth holds a team connection, and, when its connection.holder is requester, a connection for each person who makes one. See Holder.

ActionWho may
Connect or reconnect the teamAn owner or admin of the workspace.
Connect, reconnect or disconnect their own accountAny person on the team, for an integration whose holder is requester.
See who on the team has connected, with the account the host namedAn owner or admin of the workspace. Nobody sees another person's token.
Disconnect another personNobody.
Set what to ask of each tool's calls made with their own connectionAny person on the team, for themselves only, for an integration whose holder is requester.
Approve a call that asks because of a person's own ruleOnly that person. The task is put to them. Whoever may answer the task can dismiss the call.

A tool of a requester integration acts only with the connection of the person who started the task, and only while they are on the team. Of the team's rule for a tool and that person's, the stricter wins. See Person rules and Connect an integration that signs in with OAuth.

On this page