api

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: Apache-2.0 Imports: 39 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// RoleUser is an ordinary submitter: it reaches its own runs and nothing
	// else.
	RoleUser = "user"
	// RoleOperator additionally reaches the dispatcher-wide administration
	// operations listed in docs/API.md. No HTTP route grants this role; it is
	// held by the account the local development mode bootstraps.
	RoleOperator = "operator"
)

Account roles. A role is a property of the account, never of the request.

View Source
const (
	// CodeInvalidRequest is a malformed or incomplete request.
	CodeInvalidRequest = "invalid_request"
	// CodeInvalidPolicy is a request whose debuglet policy cannot be priced or
	// scheduled: a timeout outside 1..maxTimeoutMS milliseconds, a negative
	// floor, a ceiling below the floor, a repeated order_id, or an order or a
	// batch whose price overflows.
	CodeInvalidPolicy = "invalid_policy"
	// CodeUnknownExecutor names an executor that is not registered.
	CodeUnknownExecutor = "unknown_executor"
	// CodeIntentMismatch is a submission whose debuglets differ from the ones
	// the payment intent was created for.
	CodeIntentMismatch = "intent_mismatch"
	// CodePaymentIncomplete is a submission for a transaction that is not paid.
	CodePaymentIncomplete = "payment_incomplete"
	// CodeUnsupportedPaymentMethod is a payment method this API does not admit.
	CodeUnsupportedPaymentMethod = "unsupported_payment_method"
	// CodePaymentsDisabled is a chain payment method while blockchain payments
	// are disabled.
	CodePaymentsDisabled = "payments_disabled"
	// CodeUnsupportedAPIVersion is a required contract version this dispatcher
	// does not serve.
	CodeUnsupportedAPIVersion = "unsupported_api_version"
	// CodeUnauthorized is a missing, malformed, unknown, expired or revoked
	// credential, or an auth key that does not match the transaction. It says
	// that the request was not authenticated, never which of those it was.
	CodeUnauthorized = "unauthorized"
	// CodeForbidden is an authenticated request whose account may not perform
	// the operation: an operator operation asked for by an ordinary account, or
	// a cookie-authenticated state change without its CSRF token. Access to
	// another account's object is not reported with this code; it answers
	// not_found, so the response is no existence oracle.
	CodeForbidden = "forbidden"
	// CodeNotFound is a debuglet, user or executor that does not exist.
	CodeNotFound = "not_found"
	// CodeCapacityExhausted is a batch the scheduler cannot admit within the
	// executor's remaining capacity, or a destination limit below the floors
	// already admitted on that destination.
	CodeCapacityExhausted = "capacity_exhausted"
	// CodeCancelRefused is a cancellation the dispatcher did not accept.
	CodeCancelRefused = "cancel_refused"
	// CodeMethodNotAllowed is a method the route does not serve.
	CodeMethodNotAllowed = "method_not_allowed"
	// CodeUnsupportedMediaType is a body representation the route does not read.
	CodeUnsupportedMediaType = "unsupported_media_type"
	// CodePayloadTooLarge is a body beyond the accepted size.
	CodePayloadTooLarge = "payload_too_large"
	// CodeInternal is a failure inside the dispatcher. Its details are logged,
	// never returned.
	CodeInternal = "internal_error"
	// CodeUnavailable is a temporarily unavailable capability.
	CodeUnavailable = "service_unavailable"
)

Documented failure codes. New codes may appear within a contract major version, so a client must treat an unknown code as a plain failure of the status it arrived with.

View Source
const (
	// SessionLifetime is how long an issued session stays valid. It is not
	// extended by use: a client logs in again, which issues a new session.
	SessionLifetime = 12 * time.Hour
)
View Source
const VersionHeader = apispec.VersionHeader

VersionHeader carries the contract version a client requires on requests and the version this dispatcher implements on responses. It is re-exported so that a server assembling middleware can name it without importing the contract package.

Variables

This section is empty.

Functions

func APIToSpec

func APIToSpec(r DebugletRequest) (models.DebugletSpec, error)

func APIVersionMiddleware

func APIVersionMiddleware() echo.MiddlewareFunc

APIVersionMiddleware announces the implemented contract version on every response and answers a client that requires an incompatible one with an explicit error instead of a best-effort response. A request without the header is served unchanged, which keeps every client written before the contract was versioned working.

func AuthMiddleware

func AuthMiddleware(db *sql.DB, localDevelopment bool) echo.MiddlewareFunc

AuthMiddleware verifies the credential a request presents and records the caller it establishes. Unlike the identity cookie it replaces, it never accepts a user identifier as a credential and never lets a rejected credential continue as an anonymous request on a protected route.

localDevelopment admits a request that presents no credential at all as the local operator, which is the documented development bypass. It is off unless the deployment explicitly asked for it.

Types

type AccountResponse

type AccountResponse struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Role         string `json:"role"`
	AccountKey   string `json:"account_key"`
	RecoveryCode string `json:"recovery_code"`
}

AccountResponse is an account together with the credentials just issued for it. The two credentials are returned exactly once, by the operation that minted them; the dispatcher keeps only their digests and cannot show them again.

type BalanceResponse

type BalanceResponse struct {
	Balance int64 `json:"balance"`
}

type CreateUserRequest

type CreateUserRequest struct {
	Name string `json:"name"`
}

type DebugletDeleteRequest

type DebugletDeleteRequest struct {
	DebugletID uuid.UUID `json:"debuglet_id"`
	ExecutorID string    `json:"executor_id"`
}

type DebugletLogEntry

type DebugletLogEntry struct {
	ID        int64  `json:"id"`
	Timestamp string `json:"timestamp"`
	Output    string `json:"output"` // base64-encoded
}

type DebugletLogsResponse

type DebugletLogsResponse struct {
	State   string             `json:"state"`
	Error   string             `json:"error,omitempty"`
	After   int64              `json:"after"`
	Logs    []DebugletLogEntry `json:"logs"`
	HasMore bool               `json:"has_more"`
}

type DebugletPolicyRequest

type DebugletPolicyRequest struct {
	FloorBW     int64    `json:"floor_bw"`
	CeilBW      int64    `json:"ceil_bw"`
	TimeoutMS   int64    `json:"timeout_ms"`
	Addresses   []string `json:"addresses"`
	RequireICMP bool     `json:"require_icmp"`
	ListenUDP   bool     `json:"listen_udp"`
	ListenTCP   bool     `json:"listen_tcp"`
	ListenSCION bool     `json:"listen_scion"`
}

type DebugletRequest

type DebugletRequest struct {
	// Must be unique accross a single request
	OrderID int64 `json:"order_id"`
	// Optional start time as unix epoch time
	StartTimestamp *int64                `json:"start_time,omitempty"`
	ExecutorID     string                `json:"executor_id"`
	Args           []string              `json:"args,omitempty"`
	Wasm           string                `json:"wasm"`
	Policy         DebugletPolicyRequest `json:"policy"`
}

type DebugletResponse

type DebugletResponse struct {
	ID         uuid.UUID `json:"id"`
	StartTime  int64     `json:"start_time"`
	EndTime    int64     `json:"end_time"`
	Usage      int64     `json:"usage"`
	ExecutorID string    `json:"executor_id"`
	Addresses  []string  `json:"addresses"`
	State      string    `json:"state"`
}

type DebugletStateResponse

type DebugletStateResponse struct {
	State      string `json:"state"`
	Error      string `json:"error"`
	ExecutorID string `json:"executor_id"`
}

type DestinationLimitRequest

type DestinationLimitRequest struct {
	Destination string `json:"destination"`
	Limit       int64  `json:"limit"`
}

type DummyIntent

type DummyIntent struct {
	TransactionID string `json:"transaction_id"`
	AuthKey       string `json:"auth_key"`
}

type ErrorResponse

type ErrorResponse struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorResponse is the documented error envelope of the HTTP API. Every failure answers with this object: Code is a stable identifier a client branches on, Message is a bounded human-readable diagnostic it must not parse. Internal diagnostics are never part of it; they stay in the dispatcher's log. api/openapi.yaml lists the codes.

type ExecutorByIPResponse

type ExecutorByIPResponse struct {
	ExecutorID  string      `json:"executor_id"`
	DebugletIDs []uuid.UUID `json:"debuglet_ids"` // newest first, up to ?n= (default 10)
}

ExecutorByIPResponse is returned by GET /executors/by-ip?ip=<ip>. It identifies which executor corresponds to a given source IP and lists the most recent debuglet IDs that were dispatched to it.

type ExecutorCounts

type ExecutorCounts struct {
	// Eligible counts executors whose control session lease is valid now.
	Eligible int `json:"eligible"`
	// Registered counts the entries of the executor registry.
	Registered int `json:"registered"`
}

ExecutorCounts reports the executor registry and its eligible subset.

type ExecutorResponse

type ExecutorResponse struct {
	ID       string `json:"id"`
	Ready    bool   `json:"ready"`
	LastSeen int64  `json:"last_seen"`
	Version  string `json:"version"`

	TeslaDelaySec          int64  `json:"tesla_delay_sec"`
	TeslaAnchorTimestampNs int64  `json:"tesla_anchor_timestamp_ns"`
	TeslaAnchorKey         []byte `json:"tesla_anchor_key"` // k_0, the public chain anchor
	PricePerBw             int64  `json:"price_per_bw"`
	Currency               string `json:"currency"`
}

type ExecutorTeslaResponse

type ExecutorTeslaResponse struct {
	ExecutorID        string `json:"executor_id"`
	AnchorKey         string `json:"anchor_key"`          // base64-encoded k_0
	AnchorTimestampNs int64  `json:"anchor_timestamp_ns"` // Unix nanoseconds of epoch 0
	DelaySec          int64  `json:"delay_sec"`           // epoch duration in seconds
	DisclosedEpoch    int64  `json:"disclosed_epoch"`     // index of latest disclosed key
	DisclosedKey      string `json:"disclosed_key"`       // base64-encoded k_τ, empty if none yet
}

ExecutorTeslaResponse is returned by GET /executors/:id/tesla. It provides all parameters needed by an external verifier to reconstruct chain keys and validate packet authentication tags.

type GitHubOAuthConfig

type GitHubOAuthConfig struct {
	Enabled                 bool
	ClientID, ClientSecret  string
	CallbackURL, SuccessURL string
}

type Handler

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

func NewHandler

func NewHandler(d *dispatcher.Dispatcher, db *sql.DB, l *zap.Logger, options ...Option) *Handler

func (*Handler) CreateUser

func (h *Handler) CreateUser(c echo.Context) error

PUT /user CreateUser registers an account and issues its first credentials. The account key and the recovery code are returned exactly once; only their digests are stored. The role of a self-registered account is always the ordinary one.

func (*Handler) DeleteDebuglet

func (h *Handler) DeleteDebuglet(c echo.Context) error

DELETE /debuglet

func (*Handler) GetDebugletLogs

func (h *Handler) GetDebugletLogs(c echo.Context) error

GET /debuglet/:id/logs

func (*Handler) GetDebugletState

func (h *Handler) GetDebugletState(c echo.Context) error

GET /debuglet/:id/state

func (*Handler) GetExecutorByIP

func (h *Handler) GetExecutorByIP(c echo.Context) error

GET /executors/by-ip?ip=<ip>[&n=<count>]

Returns the executor ID of the executor whose source IP matches the query parameter, and the recent runs of the requesting account that were dispatched to it. Which executor serves an address is attribution data a measurement peer may need; which runs it carried is private, so the returned identifiers are the caller's own, never the run identifiers of another account. n defaults to 10 and can be raised by the caller up to maxRecentDebugletIDs, though the executor's ring retains at most 20 recent identifiers, so that is the real bound on the answer.

func (*Handler) GetExecutorTesla

func (h *Handler) GetExecutorTesla(c echo.Context) error

GET /executors/:id/tesla

Returns the TESLA key schedule parameters for the given executor, including the public anchor key k_0 and the latest disclosed key k_τ. External verifiers use these to reconstruct chain keys and validate packet tags.

func (*Handler) GetExecutors

func (h *Handler) GetExecutors(c echo.Context) error

GET /executors

func (*Handler) GetGitHubCallback

func (h *Handler) GetGitHubCallback(c echo.Context) error

func (*Handler) GetGitHubLogin

func (h *Handler) GetGitHubLogin(c echo.Context) error

GetGitHubLogin starts the OAuth authorization-code flow. The state is an unpredictable, short-lived, HttpOnly cookie; no return URL comes from the request, so the callback cannot become an open redirect.

func (*Handler) GetHealth

func (h *Handler) GetHealth(c echo.Context) error

GetHealth answers GET /health. It always answers 200: the report is the answer, and a probe that could not read it would learn nothing.

func (*Handler) GetLiveness

func (h *Handler) GetLiveness(c echo.Context) error

GetLiveness answers GET /healthz. Reaching it is the whole check.

func (*Handler) GetMe

func (h *Handler) GetMe(c echo.Context) error

GET /me GetMe returns the authenticated account. It requires a credential even in local development, because the local development bypass names no account.

func (*Handler) GetOpenAPI

func (h *Handler) GetOpenAPI(c echo.Context) error

GetOpenAPI answers GET /openapi.yaml with the contract this build implements.

func (*Handler) GetPaymentStatus

func (h *Handler) GetPaymentStatus(c echo.Context) error

GET /payment/:transaction_id/status

GetPaymentStatus reports whether one payment order is paid. The order is private to the account that created it: another account's order and an unknown one answer alike.

func (*Handler) GetReadiness

func (h *Handler) GetReadiness(c echo.Context) error

GetReadiness answers GET /readyz: 200 while this dispatcher would admit new work, 503 naming the failed checks otherwise.

func (*Handler) GetVersion

func (h *Handler) GetVersion(c echo.Context) error

VersionResponse identities. GetVersion answers GET /version.

func (*Handler) ListUserDebuglets

func (h *Handler) ListUserDebuglets(c echo.Context) error

GET /list-debuglets

func (*Handler) ListUserIDs

func (h *Handler) ListUserIDs(c echo.Context) error

GET /user-ids ListUserIDs enumerates the accounts of this dispatcher. Enumeration is an operator operation: an ordinary account has no reason to learn which other accounts exist, and an identifier it learned was once enough to impersonate one.

func (*Handler) LockPrice

func (h *Handler) LockPrice(request PaymentIntentRequest, transactionId string, refundAddress string, ctx context.Context) (int64, error)

LockPrice prices an intent and creates its Outstanding debuglet_order rows, returning the total price. The rows reference the intent's transaction, so that transaction must already exist; PutPaymentIntent therefore prices, creates the transaction and only then stores the orders. Every failure it reports is already a documented API error, so a caller can return it unchanged.

func (*Handler) PatchDestinationLimit

func (h *Handler) PatchDestinationLimit(c echo.Context) error

PATCH /destination

PatchDestinationLimit changes a dispatcher-wide bandwidth limit, which affects every account's admission decisions. It is therefore an operator operation rather than something a submitter may do to its own runs.

func (*Handler) PostLogin

func (h *Handler) PostLogin(c echo.Context) error

POST /auth/login

PostLogin verifies an account key and issues a session for the account it names. It is the only route that turns a long-lived credential into one, and it never accepts a user identifier, a run identifier or a payment auth key.

func (*Handler) PostLogout

func (h *Handler) PostLogout(c echo.Context) error

POST /auth/logout

PostLogout revokes the session the request authenticated with and clears the browser cookies. The revoked token is refused from then on, before its expiry.

func (*Handler) PostRecover

func (h *Handler) PostRecover(c echo.Context) error

POST /auth/recover

PostRecover consumes a recovery code and returns a new account key and a new recovery code for the one account that code belongs to. Every session of that account is revoked first, so a recovered account is not still reachable with a credential the previous holder kept. A recovery code names its own account and nothing else: it can never be redirected at another one.

func (*Handler) PutDebuglets

func (h *Handler) PutDebuglets(c echo.Context) error

PUT /debuglet

func (*Handler) PutPaymentIntent

func (h *Handler) PutPaymentIntent(c echo.Context) error

PUT /payment/intent

func (*Handler) RegisterRoutes

func (h *Handler) RegisterRoutes(e *echo.Echo)

func (*Handler) VersionIdentities

func (h *Handler) VersionIdentities() VersionResponse

VersionIdentities reports the three independent identities of a running dispatcher: the HTTP API contract it serves, the binary it was built from and the executor control protocol it speaks. They are versioned separately and only the API contract is a promise to HTTP clients.

type HealthResponse

type HealthResponse struct {
	Live      bool           `json:"live"`
	Ready     bool           `json:"ready"`
	Reasons   []string       `json:"reasons"`
	Storage   string         `json:"storage"`
	Control   string         `json:"control"`
	Executors ExecutorCounts `json:"executors"`
}

HealthResponse is the aggregate report. It is a fixed set of small fields: no operator note, no identifier, no path, because the route is public.

type IntentResponse

type IntentResponse struct {
	Method string `json:"method"`
	Intent any    `json:"intent"`
}

type LoginRequest

type LoginRequest struct {
	AccountKey string `json:"account_key"`
}

LoginRequest exchanges an account key for a session. An empty account key is the local development bootstrap and is refused by every other deployment.

type Option

type Option func(*Handler)

Option configures a Handler. Every option is explicit: the zero configuration is the profile a deployment gets, and nothing about it is inferred from the request.

func CookieSecure

func CookieSecure(secure bool) Option

CookieSecure marks the session and CSRF cookies Secure, so a browser sends them over TLS only. It is an explicit statement by the deployment because a request cannot describe its own scheme: X-Forwarded-Proto, X-Url-Scheme and X-Forwarded-Ssl are set by whoever sent the request, and trusting them would let a plaintext caller decide that its own cookies need no TLS. cmd/dispatcher sets it when the daemon terminates TLS itself or when the configuration says a TLS terminator stands in front of it.

func GitHubOAuth

func GitHubOAuth(cfg GitHubOAuthConfig) Option

func LocalDevelopment

func LocalDevelopment(enabled bool) Option

LocalDevelopment enables the local development profile of this API. In it, a request that presents no credential at all is served as the dispatcher's own local operator, and its runs are recorded without an owner, which is what keeps the explicit wallet-free local flow usable without a browser. A request that does present a credential is authenticated and authorized normally even here.

It is off by default and must never be enabled for a deployment that is reachable by anyone but its operator. cmd/dispatcher enables it exactly where it already recognises a local environment: blockchain payments disabled, the TLS listener disabled and both listeners on loopback, which is the configuration the local role commands generate and the deployment examples do not.

type PaymentIntentRequest

type PaymentIntentRequest struct {
	Debuglets     []DebugletRequest `json:"debuglets"`
	PaymentMethod string            `json:"payment_method"`
	RefundAddress string            `json:"refund_address"`
}

type ProbeResponse

type ProbeResponse struct {
	Status  string   `json:"status"`
	Reasons []string `json:"reasons,omitempty"`
}

ProbeResponse is the body of the liveness and readiness probes. Reasons is present only on a refusal.

type RecoverRequest

type RecoverRequest struct {
	RecoveryCode string `json:"recovery_code"`
}

RecoverRequest exchanges a recovery code for fresh account credentials.

type SessionResponse

type SessionResponse struct {
	Token     string `json:"token"`
	CSRFToken string `json:"csrf_token"`
	ExpiresAt int64  `json:"expires_at"`
	ID        string `json:"id"`
	Name      string `json:"name"`
	Role      string `json:"role"`
}

SessionResponse is an issued session. token is the bearer credential a native client repeats on every request; csrf_token is the value a browser client, which received the session in a cookie, repeats in the X-Debuglet-CSRF header of every state-changing request.

type SubmitDebugletsRequest

type SubmitDebugletsRequest struct {
	Debuglets     []DebugletRequest `json:"debuglets"`
	TransactionId string            `json:"transaction_id"`
	AuthKey       string            `json:"auth_key"`
}

type SuiIntent

type SuiIntent struct {
	TransactionId   string `json:"transaction_id"`
	AuthKey         string `json:"auth_key"`
	Price           int64  `json:"price"`
	CoinType        string `json:"coin_type"`
	ExpiresAtS      int64  `json:"expires_at_s"`
	RegistryAddress string `json:"registry_address"`
	ReceiverAddress string `json:"receiver_address"`
}

type UserResponse

type UserResponse struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	// Role is the account's role, "user" or "operator". It reports what the
	// account may do; it is not a credential and grants nothing by itself.
	Role string `json:"role"`
}

type VersionResponse

type VersionResponse struct {
	Version         string   `json:"version"`
	APIVersion      string   `json:"api_version"`
	APIVersions     []string `json:"api_versions"`
	BinaryVersion   string   `json:"binary_version"`
	BinaryRevision  string   `json:"binary_revision,omitempty"`
	ProtocolVersion string   `json:"protocol_version"`
}

VersionResponse reports the version identities of a dispatcher. They are independent: api_version is the HTTP contract this dispatcher serves, binary_version identifies the build and protocol_version is the executor control protocol, which no HTTP client speaks. Version is the dispatcher's configured string, retained for clients written before the contract was versioned.

Jump to

Keyboard shortcuts

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