teams

package
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package teams is a thin client for the Truestamp Teams + Memberships JSON:API surfaces (GET /api/json/teams, /api/json/memberships). It exposes the small subset of operations the CLI needs to discover a user's team memberships and validate that a configured team is accessible.

The membership read policy on the server side filters to the actor's own memberships, so `ListMyMemberships` returns "the teams I'm a member of" with no extra filtering. See truestamp-v2/lib/truestamp/teams/membership.ex policy block.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUnauthorized = errors.New("not authenticated")
	ErrForbidden    = errors.New("forbidden")
	ErrNotFound     = errors.New("not found")
	ErrBadRequest   = errors.New("bad request")
	ErrRateLimited  = errors.New("rate limited")
	ErrServer       = errors.New("server error")
)

Errors surfaced by the client. CLI layers may errors.Is these to pick an exit code and user-facing message.

ErrUnauthorized covers 401 (the API key itself is invalid or expired). ErrForbidden covers 403 — auth was accepted but the actor isn't allowed to read this resource (typically: the tenant header points to a team the actor isn't a member of). Distinguishing the two matters because the user-facing remediation is completely different: 401 → run `auth login`; 403 → check the team id, ask for membership.

Functions

func FormatRole

func FormatRole(role string) string

FormatRole returns a human-friendly title-cased role label suitable for table cells: "team_owner" -> "Owner", "team_admin" -> "Admin", "team_member" -> "Member", "team_viewer" -> "Viewer". Unknown inputs pass through unchanged so a future server-side role addition shows up verbatim instead of being silently dropped.

func GetMyRoleOnTeam

func GetMyRoleOnTeam(ctx context.Context, cfg Config, teamID string) (string, error)

GetMyRoleOnTeam returns the role string for the API key's user on the given team, or the empty string if the user has no membership (without distinguishing the "no membership" case from "lookup failed"). Callers that need the failure distinction should call ListMyMemberships and search the slice.

func PrivilegeRank

func PrivilegeRank(role string) int

PrivilegeRank returns a sort key for the given role. Lower values rank higher (Owner = 0, Viewer = 3). Unknown roles sort last so a future server-side addition isn't silently grouped with viewers.

Types

type APIError

type APIError struct {
	Status     int
	Detail     string // preferred; falls back to Title
	RetryAfter string // verbatim Retry-After header on 429
	// contains filtered or unexported fields
}

APIError carries HTTP status + preserved `errors[].detail` from the JSON:API envelope for display to the user. Wraps one of the sentinel errors above so callers can errors.Is() the class while still showing the detail text.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

type Config

type Config struct {
	APIURL string // e.g. https://www.truestamp.com/api/json
	APIKey string // Bearer token (never logged)
	Team   string // optional tenant id; sent verbatim as the `tenant` header
}

Config carries the subset of runtime configuration needed for a request. Kept small to avoid importing the top-level config package.

type Membership

type Membership struct {
	ID     string `json:"id"`
	TeamID string `json:"team_id"`
	Role   string `json:"role"` // "team_owner" | "team_admin" | "team_member" | "team_viewer"
	Team   *Team  `json:"team,omitempty"`
}

Membership pairs a user's role with the team it applies to. Team is populated from a parallel `GET /teams` call, joined client-side (see ListMyMemberships). JSON tags are snake_case to match the shape of every other --json surface in the CLI; without explicit tags the Go field names ("ID", "TeamID") would leak.

func ListMyMemberships

func ListMyMemberships(ctx context.Context, cfg Config) ([]Membership, error)

ListMyMemberships returns one Membership row per team the API key's user has access to, with the user's role on that team.

The implementation anchors on `GET /teams` (source of truth for "teams I can read", per the server-side `relates_to_actor_via(:members)` READ policy) rather than `/memberships` because:

  1. `/memberships` can return rows whose team_id no longer exists (orphaned dev seed data, mid-cascade-delete races).
  2. Under admin bypass policies, `/memberships` may return memberships from other users that the actor doesn't actually hold. Anchoring on the team list ensures every returned row represents a team the actor can actually read.
  3. `?include=team` on the memberships endpoint is unreliable — the included array is sparse for reasons we haven't fully diagnosed (possibly Ash's per-response include limits or relationship-load authorization filtering).

Roles are joined from a parallel `/memberships` request and deduplicated by team_id (when multiple memberships exist for the same team — e.g. different users on the same team under admin bypass — we take the first match deterministically).

Both endpoints walk `links.next` so users with many memberships or teams aren't silently truncated by the server's default page size.

type Team

type Team struct {
	ID             string `json:"id"`
	Name           string `json:"name"`
	Personal       bool   `json:"personal"`
	OwnershipModel string `json:"ownership_model"`
	CreatedAt      string `json:"inserted_at"`
}

Team is the subset of a JSON:API team resource the CLI consumes.

func GetTeam

func GetTeam(ctx context.Context, cfg Config, id string) (*Team, error)

GetTeam fetches a single team by id. Useful for `truestamp team set <id>` validation: a 2xx confirms the user can read it (which by policy means they have a membership), 4xx surfaces the JSON:API detail string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL