projectadmin

package
v0.9.77 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2026 License: GPL-3.0 Imports: 27 Imported by: 0

Documentation

Overview

Package projectadmin holds the project settings writes that the dashboard and MCP tokens share. A function does no authorization: the caller checks permissions first. Each write does the change, its revision row, and its audit row in one tenant-scoped transaction.

Index

Constants

View Source
const (
	KindRemoteConfig = "remote_config"
	KindLeaderboard  = "leaderboard"
)

Resource kinds in settings_revisions.

View Source
const (
	RemoteConfigMaxBytes = 65536
	// LeaderboardMetadataMaxBytes is smaller than remote config: every
	// /v1/leaderboards reply carries the metadata of every board.
	LeaderboardMetadataMaxBytes = 16384
	LeaderboardNameMax          = 120
)

Size limits for the JSON objects that the dashboard and the MCP tools write. The database allows more; these are the editor limits.

View Source
const OriginCacheTTL = 30 * time.Second

OriginCacheTTL is how long a saved origin list takes to reach each app host: each host caches the origins of all projects for this long.

Variables

View Source
var (
	// ErrAPIKeyLimit means the project is at its active key limit.
	ErrAPIKeyLimit = errors.New("projectadmin: the Game Project is at its API key limit")
	// ErrScopeNotGrantable means a requested key scope is not enabled for the
	// tenant or project, or its server switch is off. MCP clients see this
	// text, so it has no package prefix.
	ErrScopeNotGrantable = errors.New("scope cannot be granted")
	// ErrProjectNotInTenant means the key's project is not in the tenant.
	ErrProjectNotInTenant = errors.New("projectadmin: Game Project is not in the Account Tenant")
)
View Source
var (
	// ErrDuplicateLeaderboard means a live board in the project has the name.
	ErrDuplicateLeaderboard = errors.New("projectadmin: leaderboard with that name already exists")
	// ErrSortOrderLocked rejects a sort-order change on a board that already
	// has entries: collapsed bests are frozen under the order they were
	// written with.
	ErrSortOrderLocked = errors.New("projectadmin: sort order is fixed once scores exist")
)
View Source
var (
	// ErrRevisionConflict means the caller's expected revision is not the
	// newest revision of the resource.
	ErrRevisionConflict = errors.New("projectadmin: expected revision is not the newest revision")
	// ErrRevisionNotFound means the revision is not kept for the resource.
	ErrRevisionNotFound = errors.New("projectadmin: revision not found")
)
View Source
var ErrInvalidLeaderboard = errors.New("invalid leaderboard settings")

ErrInvalidLeaderboard wraps every leaderboard settings failure. The wrapped message is safe to show the person or the agent.

View Source
var ErrInvalidOrigins = errors.New("invalid allowed origins")

ErrInvalidOrigins wraps every origin validation failure. The wrapped message is safe to show the person or the agent.

Functions

func AllProjectOrigins

func AllProjectOrigins(ctx context.Context, pool *db.Pool) ([]string, error)

AllProjectOrigins returns the distinct origins of all live projects, for the process-wide CORS and WebSocket origin check. It runs with no tenant set through a SECURITY DEFINER function that returns origins only.

func AllowedOrigins

func AllowedOrigins(ctx context.Context, pool *db.Pool, tenantID, projectID int64) ([]string, error)

AllowedOrigins returns the project's origin list.

func CreateAPIKey

func CreateAPIKey(ctx context.Context, pool *db.Pool, authz *rbac.Authorizer, tenantID int64, in NewAPIKey, actor Actor) (int64, string, error)

CreateAPIKey makes a key, its Casbin role, its scopes, and its audit row in one transaction, then reloads the policy. It does no authorization: the caller checks that the actor may manage this key type. The key value is returned once and is never stored.

func CreateLeaderboard

func CreateLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID int64, s LeaderboardSettings, actor Actor) (int64, error)

CreateLeaderboard creates a board and records revision 1.

func DeleteLeaderboard

func DeleteLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, actor Actor) error

DeleteLeaderboard soft-deletes a board. Scores stay; RestoreLeaderboard undoes it. It returns pgx.ErrNoRows when nothing matched.

func NewAPIKeyValue

func NewAPIKeyValue(keyType tenant.KeyType) (string, error)

NewAPIKeyValue mints a plaintext API key with a type prefix: ggp_ for publishable, ggs_ for secret, then 32 random bytes in base64url. The prefix is part of the stored hash, so it helps log searches and leak detection without changing server policy.

func NormalizeJSONObject

func NormalizeJSONObject(raw string, maxBytes int) ([]byte, error)

NormalizeJSONObject checks a single top-level JSON object (no trailing data), encodes it again in canonical form, and applies maxBytes to that form. Numbers keep their exact text.

func NormalizeOrigin

func NormalizeOrigin(raw string) (string, error)

NormalizeOrigin checks one browser origin and returns it in the form a browser sends: lower-case scheme://host[:port], with no default port. It refuses a path, query, fragment, user info, and wildcards.

func NormalizeOrigins

func NormalizeOrigins(raw []string, limit int) ([]string, error)

NormalizeOrigins checks a list, drops blank lines and duplicates, and refuses more than limit origins.

func RestoreLeaderboard

func RestoreLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, actor Actor) error

RestoreLeaderboard undoes a soft delete. It returns ErrDuplicateLeaderboard when a live board in the project has the same name, and pgx.ErrNoRows when no deleted board matched.

func RollbackLeaderboard

func RollbackLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id, revision int64, expected *int64, actor Actor) (int64, error)

RollbackLeaderboard applies the settings of a kept revision as a new revision. Scores are not restored.

func RollbackRemoteConfig

func RollbackRemoteConfig(ctx context.Context, pool *db.Pool, tenantID, projectID, revision int64, expected *int64, actor Actor) (int64, error)

RollbackRemoteConfig applies a kept revision as a new revision.

func ScopeGrantable

func ScopeGrantable(ctx context.Context, authz *rbac.Authorizer, sw KeySwitches, tenantID int64, projectID *int64, scope string) bool

ScopeGrantable reports whether a key scope can be granted: the server switch must be on (matchmaker has none) and a feature grant must enable the feature for the key's tenant and project. A key with no project uses the tenant-level grant.

func SetAllowedOrigins

func SetAllowedOrigins(ctx context.Context, pool *db.Pool, tenantID, projectID int64, raw []string, limit int, actor Actor) ([]string, error)

SetAllowedOrigins replaces the project's origin list and returns the old list, so a wrong value can be put back. There is no revision history for origins. It returns pgx.ErrNoRows when the project does not exist.

func SetRemoteConfig

func SetRemoteConfig(ctx context.Context, pool *db.Pool, tenantID, projectID int64, config []byte, expected *int64, actor Actor) (int64, error)

SetRemoteConfig replaces the project's remote config. config must already be a validated JSON object. expected, when set, must be the newest revision number. It returns pgx.ErrNoRows when the project does not exist.

func UpdateLeaderboard

func UpdateLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, s LeaderboardSettings, expected *int64, actor Actor) (int64, error)

UpdateLeaderboard saves settings onto a live board and records a revision. It returns pgx.ErrNoRows when the board does not exist or is deleted.

func ValidLeaderboardName

func ValidLeaderboardName(name string) bool

ValidLeaderboardName rejects names PostgreSQL cannot store or that are too long. A NUL byte raises SQLSTATE 22021, which would show as a 500 instead of a field error. Invalid UTF-8 is checked first because the rune loop below would see it as U+FFFD.

func ValidateLeaderboard

func ValidateLeaderboard(s LeaderboardSettings, create bool) error

ValidateLeaderboard checks settings that did not come from the dashboard form. The form parser gives field-level messages for the same rules. ScoreOperator is checked only on create; it is fixed after that.

Types

type Actor

type Actor struct {
	UserID         int64
	TokenID        int64
	TokenCreatorID int64
}

Actor is who made a change. Set UserID for a dashboard user, or TokenID and TokenCreatorID for an MCP token.

type DeletedLeaderboard

type DeletedLeaderboard struct {
	ID        int64
	Name      string
	DeletedAt time.Time
}

DeletedLeaderboard is a soft-deleted board that can be restored.

func ListDeletedLeaderboards

func ListDeletedLeaderboards(ctx context.Context, pool *db.Pool, tenantID, projectID int64) ([]DeletedLeaderboard, error)

ListDeletedLeaderboards returns the newest 50 deleted boards of a project.

type KeySwitches

type KeySwitches struct {
	FleetEnabled bool
	RelayEnabled bool
}

KeySwitches are the server feature switches that gate key scopes.

type LeaderboardSettings

type LeaderboardSettings struct {
	Name              string          `json:"name"`
	SortOrder         string          `json:"sort_order"`
	ScoreOperator     string          `json:"score_operator"`
	ClientSubmissions bool            `json:"client_submissions"`
	ScoreMin          *int64          `json:"score_min,omitempty"`
	ScoreMax          *int64          `json:"score_max,omitempty"`
	ResetSchedule     string          `json:"reset_schedule"`
	AttemptCap        *int32          `json:"attempt_cap,omitempty"`
	Metadata          json.RawMessage `json:"metadata,omitempty"`
}

LeaderboardSettings are the editable leaderboard settings. They are also the revision snapshot. ScoreOperator is fixed at creation; an update ignores it.

type NewAPIKey

type NewAPIKey struct {
	ProjectID *int64
	Label     string
	Type      tenant.KeyType
	// Scopes are extra feature scopes. The matchmaker scope is always added.
	Scopes []string
	// MaxActive, when > 0, refuses the create when the project already has
	// this many active keys. It needs a ProjectID.
	MaxActive int64
	Switches  KeySwitches
}

NewAPIKey is the input of CreateAPIKey.

type Revision

type Revision struct {
	Revision    int64
	Snapshot    json.RawMessage
	ActorUserID *int64
	TokenID     *int64
	Source      string
	CreatedAt   time.Time
}

Revision is one kept settings revision.

func ListRevisions

func ListRevisions(ctx context.Context, pool *db.Pool, tenantID, projectID int64, kind string, resourceID int64) ([]Revision, error)

ListRevisions returns the kept revisions of one resource, newest first.

Jump to

Keyboard shortcuts

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