Class SystemTeamScopes
- Namespace
- Tharga.Team
- Assembly
- Tharga.Team.dll
System-level (cross-team) scope constants for team operations. Unlike the in-team TeamScopes
(which authorize only the caller's own team), these authorize across any team and are granted to system
API keys or privileged roles. The toolkit defines them; the consumer applies them as they see fit
(e.g. o.ConfigureSystemRoles mapping a role to the scope, or a system API key's scope list).
public static class SystemTeamScopes
- Inheritance
-
SystemTeamScopes
- Inherited Members
Fields
Delete
Authorizes deleting any team, regardless of membership and regardless of the
AllowTeamCreation self-service option. The unconditional, cross-team delete path.
public const string Delete = "teams:delete"
Field Value
Manage
Authorizes renaming any team and setting or clearing its icon, regardless of membership.
The oversight equivalent of the in-team team:manage, for the two operations that are
presentational.
public const string Manage = "teams:manage"
Field Value
Remarks
Deliberately narrower than in-team team:manage, which also covers consent and custom
roles. Those are authorization: consent is a team's own statement about what it exposes
inbound, and an operator overriding it is a far larger claim than fixing a typo in a name. Rename
and icon change how a team looks; consent changes who can reach it.
Extending this scope to consent would need a deliberate decision and its own name. An architecture-level rule cannot express "these two members of that scope but not those two", so a test asserts the boundary instead.
Purge
Authorizes permanently removing a soft-deleted team, including dropping its storage.
public const string Purge = "teams:purge"
Field Value
Remarks
Separate from Delete because it is the only irreversible one, and because it is
the only one needing whatever privilege the storage adapter requires to destroy a team's data — for
the MongoDB adapter in a per-team-database deployment, dropDatabase. That privilege is one
most managed deployments will not grant permanently: Atlas's readWriteAnyDatabase does not
include it.
Splitting it means a deployment can withhold both this scope and the database grant and still delete teams normally, which is what Eplicta FortDocs asked for in Tharga/Team#224.
Restoring needs no scope of its own. It is strictly less destructive than the delete it undoes, so Delete covers it — anyone trusted to remove a team is trusted to change their mind. A third scope would be a grant nobody has asked for and one more thing to map.
Read
Authorizes enumerating any team via ITeamService.GetAllTeamsAsync, regardless of
membership — the discovery path for oversight roles (support, administration).
public const string Read = "teams:read"
Field Value
Remarks
Discovery only. Holding this grants no access inside a team: selecting a team the caller is not a member of still yields only the scopes that team has consented to, and none if it has consented to nothing. Contrast with the in-team Read, which authorizes reading the caller's own team.
Granting it needs a store that can list every team. It switches the consuming UI —
TeamComponent, TeamSelector, the Users view — into cross-team oversight mode, which lists
teams from GetAllTeamsAsync instead of from the caller's memberships. The built-in store
(TeamServiceRepositoryBase) implements it. A team service deriving TeamServiceBase
directly must override GetAllTeamsInternalAsync; without it the call throws
NotSupportedException, and a startup check reports the gap as soon as anything can grant
this scope. The default used to return nothing instead, and the symptom was every holder, Owners
included, being told they are not a member of a team.
SetOwner
Authorizes making an existing member the sole owner of any team, whatever its current owner count — none, one, or several.
public const string SetOwner = "teams:set-owner"
Field Value
Remarks
Why this is its own scope. The rule this codebase already applies is that a new scope is
warranted when an operation is irreversible or crosses a tenant boundary. This does the second: the
caller is by definition not a member of the team they are acting on. It is also privilege escalation
by construction — it hands someone Owner and takes it from whoever held it — so it earns its
own grant and its own audit entry rather than riding on a scope granted for something else.
Deliberately not Delete: authorizing repair with the right to destroy would
mean the only way to fix a team is to hold the right to delete it. Deliberately not the in-team
team:manage either, which is TeamKey-bound and so cannot fit a non-member.
This grant can depose a sitting owner, and is meant to. The two cases it exists for are a team
synced from a legacy system carrying several owners, which must be reduced to one, and a handover the
sitting owner cannot perform themselves — they have left, or the account is gone.
ITeamService.TransferOwnershipAsync remains the in-team path and still requires the caller to
be the owner; this is the operator path, and the two are not alternatives.
Renamed from teams:assign-owner (3.9.0–3.13.0), which authorized only the ownerless-repair
case. The name changed with the capability rather than being widened in place, so a host that
granted the old string does not silently acquire the ability to depose owners. The old name authorizes
nothing.