Documentation
¶
Index ¶
- Constants
- func APIToSpec(r DebugletRequest) (models.DebugletSpec, error)
- func APIVersionMiddleware() echo.MiddlewareFunc
- func AuthMiddleware(db *sql.DB, localDevelopment bool) echo.MiddlewareFunc
- type AccountResponse
- type BalanceResponse
- type CreateUserRequest
- type DebugletDeleteRequest
- type DebugletLogEntry
- type DebugletLogsResponse
- type DebugletPolicyRequest
- type DebugletRequest
- type DebugletResponse
- type DebugletStateResponse
- type DestinationLimitRequest
- type DummyIntent
- type ErrorResponse
- type ExecutorByIPResponse
- type ExecutorCounts
- type ExecutorResponse
- type ExecutorTeslaResponse
- type GitHubOAuthConfig
- type Handler
- func (h *Handler) CreateUser(c echo.Context) error
- func (h *Handler) DeleteDebuglet(c echo.Context) error
- func (h *Handler) GetDebugletLogs(c echo.Context) error
- func (h *Handler) GetDebugletState(c echo.Context) error
- func (h *Handler) GetExecutorByIP(c echo.Context) error
- func (h *Handler) GetExecutorTesla(c echo.Context) error
- func (h *Handler) GetExecutors(c echo.Context) error
- func (h *Handler) GetGitHubCallback(c echo.Context) error
- func (h *Handler) GetGitHubLogin(c echo.Context) error
- func (h *Handler) GetHealth(c echo.Context) error
- func (h *Handler) GetLiveness(c echo.Context) error
- func (h *Handler) GetMe(c echo.Context) error
- func (h *Handler) GetOpenAPI(c echo.Context) error
- func (h *Handler) GetPaymentStatus(c echo.Context) error
- func (h *Handler) GetReadiness(c echo.Context) error
- func (h *Handler) GetVersion(c echo.Context) error
- func (h *Handler) ListUserDebuglets(c echo.Context) error
- func (h *Handler) ListUserIDs(c echo.Context) error
- func (h *Handler) LockPrice(request PaymentIntentRequest, transactionId string, refundAddress string, ...) (int64, error)
- func (h *Handler) PatchDestinationLimit(c echo.Context) error
- func (h *Handler) PostLogin(c echo.Context) error
- func (h *Handler) PostLogout(c echo.Context) error
- func (h *Handler) PostRecover(c echo.Context) error
- func (h *Handler) PutDebuglets(c echo.Context) error
- func (h *Handler) PutPaymentIntent(c echo.Context) error
- func (h *Handler) RegisterRoutes(e *echo.Echo)
- func (h *Handler) VersionIdentities() VersionResponse
- type HealthResponse
- type IntentResponse
- type LoginRequest
- type Option
- type PaymentIntentRequest
- type ProbeResponse
- type RecoverRequest
- type SessionResponse
- type SubmitDebugletsRequest
- type SuiIntent
- type UserResponse
- type VersionResponse
Constants ¶
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.
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" // 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 = "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.
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 )
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 DebugletLogEntry ¶
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 DebugletStateResponse ¶
type DestinationLimitRequest ¶
type DummyIntent ¶
type ErrorResponse ¶
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 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 ¶
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 ¶
DELETE /debuglet
func (*Handler) GetDebugletLogs ¶
GET /debuglet/:id/logs
func (*Handler) GetDebugletState ¶
GET /debuglet/:id/state
func (*Handler) GetExecutorByIP ¶
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 ¶
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) GetGitHubLogin ¶
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 ¶
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 ¶
GetLiveness answers GET /healthz. Reaching it is the whole check.
func (*Handler) GetMe ¶
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 ¶
GetOpenAPI answers GET /openapi.yaml with the contract this build implements.
func (*Handler) GetPaymentStatus ¶
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 ¶
GetReadiness answers GET /readyz: 200 while this dispatcher would admit new work, 503 naming the failed checks otherwise.
func (*Handler) GetVersion ¶
VersionResponse identities. GetVersion answers GET /version.
func (*Handler) ListUserDebuglets ¶
GET /list-debuglets
func (*Handler) ListUserIDs ¶
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 ¶
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 ¶
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 ¶
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 ¶
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) PutPaymentIntent ¶
PUT /payment/intent
func (*Handler) RegisterRoutes ¶
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 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 ¶
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 ¶
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 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.