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
- Variables
- func AllProjectOrigins(ctx context.Context, pool *db.Pool) ([]string, error)
- func AllowedOrigins(ctx context.Context, pool *db.Pool, tenantID, projectID int64) ([]string, error)
- func CreateAPIKey(ctx context.Context, pool *db.Pool, authz *rbac.Authorizer, tenantID int64, ...) (int64, string, error)
- func CreateLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID int64, ...) (int64, error)
- func DeleteLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, actor Actor) error
- func NewAPIKeyValue(keyType tenant.KeyType) (string, error)
- func NormalizeJSONObject(raw string, maxBytes int) ([]byte, error)
- func NormalizeOrigin(raw string) (string, error)
- func NormalizeOrigins(raw []string, limit int) ([]string, error)
- func RestoreLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, actor Actor) error
- func RollbackLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id, revision int64, ...) (int64, error)
- func RollbackRemoteConfig(ctx context.Context, pool *db.Pool, tenantID, projectID, revision int64, ...) (int64, error)
- func ScopeGrantable(ctx context.Context, authz *rbac.Authorizer, sw KeySwitches, tenantID int64, ...) bool
- func SetAllowedOrigins(ctx context.Context, pool *db.Pool, tenantID, projectID int64, raw []string, ...) ([]string, error)
- func SetRemoteConfig(ctx context.Context, pool *db.Pool, tenantID, projectID int64, config []byte, ...) (int64, error)
- func UpdateLeaderboard(ctx context.Context, pool *db.Pool, tenantID, projectID, id int64, ...) (int64, error)
- func ValidLeaderboardName(name string) bool
- func ValidateLeaderboard(s LeaderboardSettings, create bool) error
- type Actor
- type DeletedLeaderboard
- type KeySwitches
- type LeaderboardSettings
- type NewAPIKey
- type Revision
Constants ¶
const ( KindRemoteConfig = "remote_config" KindLeaderboard = "leaderboard" )
Resource kinds in settings_revisions.
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.
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 ¶
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") )
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") )
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") )
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.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
Actor is who made a change. Set UserID for a dashboard user, or TokenID and TokenCreatorID for an MCP token.
type DeletedLeaderboard ¶
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 ¶
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.