scripttoken

package
v1.148.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package scripttoken is the signed token a managed script mints and verifies (#2175): platform.token.mint and platform.token.verify. A token is an HMAC-SHA256 over a JSON body carrying the script's claims, the endpoints or the script it is bound to, its expiry, an id, and whether it may be used once. The key is derived from a stored secret the script names, and the script never sees the secret's value.

It is the same form the bot check's proof-of-work challenge is signed in (internal/botcheck), kept in-house rather than a JWT: the platform both mints and verifies, so nothing outside it has to read one.

Index

Constants

View Source
const (
	CapabilityMint   = "platform.mint_token"
	CapabilityVerify = "platform.verify_token"
)

The platform members a script mints and verifies with.

View Source
const (
	// MaxTokenLen bounds a token before anything is decoded from it.
	MaxTokenLen = 8192
	// MaxClaimsBytes bounds the claims a script puts in one token.
	MaxClaimsBytes = 4096
	// MaxTTL is the longest a token may live.
	MaxTTL = 30 * 24 * time.Hour
	// MaxEndpoints is the most endpoints one token may be bound to.
	MaxEndpoints = 16
)

Limits on what a token carries and how long it lives.

View Source
const (
	ReasonMalformed     = "malformed"
	ReasonTampered      = "tampered"
	ReasonExpired       = "expired"
	ReasonOtherEndpoint = "other_endpoint"
	ReasonUsed          = "used"
)

Reasons a token is refused, as verify returns them to the script.

View Source
const SecretUse = "script_token"

SecretUse is the name a token key's allow_connections lists: a token key is never sent through a connection, so the reserved name is what scopes a stored secret to this use, as botcheck.SecretUse does for a provider key.

Variables

View Source
var ErrRefused = errors.New("token refused")

ErrRefused is the error every refusal wraps; Reason reads which it was.

Functions

func Key

func Key(secret string) []byte

Key derives the signing key from a stored secret's value.

func Reason

func Reason(err error) string

Reason is the reason a Verify error carries, or "" for any other error.

func Sign

func Sign(key []byte, at Binding, m Mint, now time.Time) (string, error)

Sign mints a token under key at binding, valid for m.TTL from now.

Types

type Authority

type Authority func(roles []string) (persona string, admin bool)

Authority resolves the persona roles act as and whether it is the administrator's, the resolution a run's own session gets from the persona layer.

type Binding

type Binding struct {
	Endpoint string
	ScriptID string
}

Binding is where a token is minted or verified: inside an endpoint request, the endpoint's name; anywhere else, the script.

type Caller

type Caller interface {
	CallTool(ctx context.Context, name string, args map[string]any) (map[string]any, error)
}

Caller answers one mint or verify, named by its capability, with the arguments the script passed: an Issuer in a run, the recording in a test.

type Host

type Host struct {
	// Ctx is the run's context.
	Ctx context.Context //nolint:containedctx // the run's lifetime, which both members read
	// Testing is a test or a replay: calls go to Replay.
	Testing bool
	// Replay answers a test's calls, from the recording or a declared answer.
	Replay Caller
	// Live answers a run's calls; nil where this deployment issues no tokens.
	Live Caller
	// Record records a run's call and its answer, nil when nothing records.
	Record func(tool string, args, out map[string]any, err error)
}

Host is the two members as a run binds them, the way scriptpace.Clock binds remaining_ms: in a run each call goes to Live and is recorded, and in a test it is answered from the recording, so a test of a handler that mints or verifies needs neither the key nor the database.

func (Host) Mint

func (h Host) Mint(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error)

Mint is platform.mint_token(claims, ttl, secret, endpoints=None, single_use=False): the token, as a string.

func (Host) Verify

func (h Host) Verify(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error)

Verify is platform.verify_token(token, secret): a dict whose "ok" says whether the token holds, with its "claims" when it does and the "reason" it was refused for when it does not, so a script answers a refusal itself.

type Issuer

type Issuer struct {
	Keys KeyReader
	Uses Uses
	// Authority resolves a run's roles to its persona; nil resolves none, so
	// only a key naming no personas can be used.
	Authority Authority
	// Now is the clock; nil is time.Now.
	Now func() time.Time
}

Issuer answers a run's mints and verifies: the deployment's secrets and single-use record, and Bind's per-run identity.

func (*Issuer) Bind

func (i *Issuer) Bind(at Binding, roles []string) Caller

Bind is the Caller for one run: where it mints and verifies, and the roles the run presents, whose persona a key's allow_personas is checked against. A nil Issuer binds nothing, so a deployment without one leaves the members saying so.

type KeyReader

type KeyReader func(ctx context.Context, name, persona string, admin bool) (string, error)

KeyReader reads a stored secret's value for this use, refusing a secret whose allow_connections does not list SecretUse or whose allow_personas does not name persona (the administrator's is unrestricted).

type Mint

type Mint struct {
	Claims map[string]any
	TTL    time.Duration
	// Endpoints names the endpoints the token verifies at; empty binds it to
	// where it was minted.
	Endpoints []string
	SingleUse bool
}

Mint is one token's request.

type PostgresUses

type PostgresUses struct {
	// contains filtered or unexported fields
}

PostgresUses is Uses over the script_token_uses table.

func NewUses

func NewUses(db *sql.DB) *PostgresUses

NewUses is the use store over db.

func (*PostgresUses) Sweep

func (p *PostgresUses) Sweep(ctx context.Context, now time.Time) (int64, error)

Sweep deletes the uses of tokens that can no longer verify.

func (*PostgresUses) Use

func (p *PostgresUses) Use(ctx context.Context, id string, expires time.Time) (bool, error)

Use inserts the id, and the primary key decides whether it was the first: two replicas verifying the same token at once both insert, and one insert finds the row the other wrote.

type Token

type Token struct {
	Claims    map[string]any
	Expires   time.Time
	ID        string
	SingleUse bool
}

Token is a verified token.

func Verify

func Verify(key []byte, at Binding, token string, now time.Time) (Token, error)

Verify reads a token key signed, refusing one that is malformed, whose signature is not key's, that has expired, or that is not bound to at. A single-use token's use is the caller's to record.

type Uses

type Uses interface {
	// Use records the token's id until it expires and reports whether this
	// was its first use.
	Use(ctx context.Context, id string, expires time.Time) (bool, error)
	// Sweep deletes the records of tokens that have expired.
	Sweep(ctx context.Context, now time.Time) (int64, error)
}

Uses records the single-use tokens that have been verified, so a second use is refused on every replica.

Jump to

Keyboard shortcuts

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