httpapi

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: AGPL-3.0 Imports: 40 Imported by: 0

Documentation

Overview

Package httpapi is part of the Redoubt control plane. See CLAUDE.md for its role.

Index

Constants

View Source
const (
	EnvRateLimitAuth    = "REDOUBT_RATELIMIT_AUTH"
	EnvRateLimitWebhook = "REDOUBT_RATELIMIT_WEBHOOK"
	EnvRateLimitAPI     = "REDOUBT_RATELIMIT_API"
)

Environment variables that override the defaults, each of the form "<per-minute>/<burst>".

View Source
const ActionRateLimitHit = "ratelimit.hit"

ActionRateLimitHit is the audit action recorded (at most once per address per minute) when a request is refused.

Variables

This section is empty.

Functions

func New

func New(d Deps) http.Handler

New builds the HTTP handler.

func RoutesMarkdown

func RoutesMarkdown() string

RoutesMarkdown renders the route table as docs/API.md.

Types

type APIError

type APIError struct {
	Status int
	Msg    string
}

APIError is a non-2xx response.

func (*APIError) Error

func (e *APIError) Error() string

type Client

type Client struct {
	BaseURL string
	Token   string
	HTTP    *http.Client
}

Client is the typed API client used by the redoubt CLI.

func NewClient

func NewClient(baseURL, token string) *Client

NewClient creates a client for the platformd API.

func (*Client) AuditExport

func (c *Client) AuditExport(ctx context.Context, format string, w io.Writer) error

AuditExport streams the export in the given format into w.

func (*Client) AuditList

func (c *Client) AuditList(ctx context.Context, after, limit int64) ([]audit.Row, error)

AuditList returns audit rows after seq.

func (*Client) AuditVerify

func (c *Client) AuditVerify(ctx context.Context) (audit.Report, error)

AuditVerify runs verify-chain on the server.

func (*Client) BackupAddon

func (c *Client) BackupAddon(ctx context.Context, app, name string) (addons.BackupView, error)

BackupAddon enqueues a backup and returns its record.

func (*Client) Bootstrap

func (c *Client) Bootstrap(ctx context.Context, email, password string) (UserView, error)

Bootstrap creates the first Owner with the bootstrap token (Client.Token).

func (*Client) CompleteTOTP

func (c *Client) CompleteTOTP(ctx context.Context, code string) error

CompleteTOTP presents the second factor for the current session.

func (*Client) ConfirmTOTP

func (c *Client) ConfirmTOTP(ctx context.Context, code string) ([]string, error)

ConfirmTOTP finishes enrollment and returns the recovery codes (shown once).

func (*Client) CreateAddon

func (c *Client) CreateAddon(ctx context.Context, app, kind, name string) (addons.View, error)

CreateAddon provisions a Postgres or Redis addon for app.

func (*Client) CreateApp

func (c *Client) CreateApp(ctx context.Context, req deploy.CreateAppRequest) (deploy.AppView, error)

CreateApp registers an app.

func (*Client) CreateToken

func (c *Client) CreateToken(ctx context.Context, name string) (string, error)

CreateToken mints an API token for the logged-in user (returned once).

func (*Client) CreateUser

func (c *Client) CreateUser(ctx context.Context, email, password, role string) (UserView, error)

CreateUser adds a user (requires users.manage).

func (*Client) DeleteAddon

func (c *Client) DeleteAddon(ctx context.Context, app, name string, removeData bool) error

DeleteAddon removes an addon; removeData also deletes its volume (destructive permission).

func (*Client) DeleteSecret

func (c *Client) DeleteSecret(ctx context.Context, app, name string) error

DeleteSecret removes a secret.

func (*Client) DeleteUser

func (c *Client) DeleteUser(ctx context.Context, id string) error

DeleteUser removes a user (Owner only).

func (*Client) Deploy

Deploy triggers a deployment.

func (*Client) DeployStatic

func (c *Client) DeployStatic(ctx context.Context, req deploy.StaticRequest) (deploy.StaticResult, error)

DeployStatic deploys a pre-built image.

func (*Client) DeploymentLogs

func (c *Client) DeploymentLogs(ctx context.Context, id string, after int64) ([]deploy.LogLine, error)

DeploymentLogs returns persisted log lines after seq.

func (*Client) DownloadSBOM

func (c *Client) DownloadSBOM(ctx context.Context, releaseID, format string, w io.Writer) error

DownloadSBOM streams a release's SBOM (spdx | cyclonedx) into w.

func (*Client) EnrollTOTP

func (c *Client) EnrollTOTP(ctx context.Context) (secret, otpauthURL string, err error)

EnrollTOTP starts TOTP enrollment (secret shown once).

func (*Client) FollowLogs

func (c *Client) FollowLogs(ctx context.Context, id string, after int64, fn func(deploy.LogLine)) (string, error)

FollowLogs streams SSE log events, calling fn per line until the deployment ends or ctx is cancelled. It returns the final state reported by the server ("" if the stream ended early).

func (*Client) GetAddon

func (c *Client) GetAddon(ctx context.Context, app, name string) (addons.View, error)

GetAddon returns one addon.

func (*Client) GetApp

func (c *Client) GetApp(ctx context.Context, app string) (deploy.AppView, error)

GetApp returns one app.

func (*Client) GetDeployment

func (c *Client) GetDeployment(ctx context.Context, id string) (deploy.DeploymentView, error)

GetDeployment returns a deployment.

func (*Client) Health

func (c *Client) Health(ctx context.Context) (map[string]string, error)

Health checks /healthz (unauthenticated).

func (*Client) ListAddons

func (c *Client) ListAddons(ctx context.Context, app string) ([]addons.View, error)

ListAddons lists an app's addons.

func (*Client) ListAppViews

func (c *Client) ListAppViews(ctx context.Context) ([]deploy.AppView, error)

ListAppViews lists apps (Phase 1 shape).

func (*Client) ListApps

func (c *Client) ListApps(ctx context.Context) ([]deploy.AppStatus, error)

ListApps lists managed apps.

func (*Client) ListBackups

func (c *Client) ListBackups(ctx context.Context, app, name string, limit int) ([]addons.BackupView, error)

ListBackups lists an addon's backups, newest first.

func (*Client) ListDeployments

func (c *Client) ListDeployments(ctx context.Context, app string, limit int) ([]deploy.DeploymentView, error)

ListDeployments lists deployments for an app.

func (*Client) ListReleases

func (c *Client) ListReleases(ctx context.Context, app string, limit int) ([]deploy.ReleaseView, error)

ListReleases lists an app's releases, newest first.

func (*Client) ListSecrets

func (c *Client) ListSecrets(ctx context.Context, app string) ([]deploy.SecretMeta, error)

ListSecrets returns names + metadata only.

func (*Client) ListSessions

func (c *Client) ListSessions(ctx context.Context) ([]SessionView, error)

ListSessions returns the caller's own live sessions.

func (*Client) ListUsers

func (c *Client) ListUsers(ctx context.Context) ([]UserDetail, error)

ListUsers returns every user (users.manage).

func (*Client) Login

func (c *Client) Login(ctx context.Context, email, password string) (LoginResponse, error)

Login authenticates with email/password; the session cookie is kept in c.HTTP's jar.

func (*Client) Me

func (c *Client) Me(ctx context.Context) (UserView, error)

Me returns the current principal.

func (*Client) RecordUpdate

func (c *Client) RecordUpdate(ctx context.Context, ev update.Event) error

RecordUpdate reports an update event to the control plane (client side).

func (*Client) ReleaseScan

func (c *Client) ReleaseScan(ctx context.Context, releaseID string) (scan.Result, error)

ReleaseScan returns a release's scan summary.

func (*Client) RemoveApp

func (c *Client) RemoveApp(ctx context.Context, app string) error

RemoveApp removes an app.

func (*Client) ResetUserPassword

func (c *Client) ResetUserPassword(ctx context.Context, id, password string) error

ResetUserPassword sets a new password for another user and revokes their sessions.

func (*Client) RestoreAddon

func (c *Client) RestoreAddon(ctx context.Context, app, name, backupID string) error

RestoreAddon loads backupID into the addon (same kind), replacing its contents.

func (*Client) RevokeSession

func (c *Client) RevokeSession(ctx context.Context, id string) error

RevokeSession ends one of the caller's own sessions.

func (*Client) Rollback

func (c *Client) Rollback(ctx context.Context, app, releaseID string) (deploy.DeploymentView, error)

Rollback re-deploys a previous release (empty id = the one before the active release).

func (*Client) SelfAudit

func (c *Client) SelfAudit(ctx context.Context) (selfaudit.Report, error)

SelfAudit fetches the posture report (CLI).

func (*Client) SetGitSource

SetGitSource connects a repository (webhook secret returned once).

func (*Client) SetScanPolicy

func (c *Client) SetScanPolicy(ctx context.Context, app, policy string) (deploy.AppView, error)

SetScanPolicy updates an app's scan policy (off | warn | block).

func (*Client) SetSecret

func (c *Client) SetSecret(ctx context.Context, app, name, value string) (deploy.SecretMeta, error)

SetSecret writes a secret (never readable afterwards).

func (*Client) System

func (c *Client) System(ctx context.Context) (SystemInfo, error)

System returns daemon information.

func (*Client) UpdateUser

func (c *Client) UpdateUser(ctx context.Context, id string, patch UserPatch) (UserDetail, error)

UpdateUser changes a user's role and/or disabled flag.

type CreateAddonRequest

type CreateAddonRequest struct {
	Kind string `json:"kind"`
	Name string `json:"name"`
}

CreateAddonRequest is the body of POST /apps/{app}/addons.

type Deps

type Deps struct {
	// Phase 0
	Static  *deploy.Static
	Docker  *docker.Client
	Token   string // bootstrap token (D-011): full access only while no user exists
	Logger  *slog.Logger
	Version string

	// Phase 1
	Service  *deploy.Service
	Auth     *auth.Service
	Sessions *auth.Sessions
	Store    *store.Store
	Keeper   *secrets.Keeper
	Webhooks *webhooks.Handler
	Broker   *deploy.Broker
	Logs     *deploy.Logs
	// Chain is the hash-chained audit log (nil until Phase 2 wiring; endpoints then 501).
	Chain *audit.Chain
	// CacheUsage reports the BuildKit cache size (nil when no builder is configured).
	CacheUsage func(context.Context) (int64, error)

	// Phase 2
	// Audit receives events raised by the HTTP layer itself (ratelimit.hit); services own theirs.
	Audit audit.Sink
	// RateLimits overrides DefaultRateLimits (nil = defaults; see ratelimit.go).
	RateLimits *RateLimits
	// SelfAudit serves /api/v1/self-audit and the dashboard's /self-audit page (E2.7).
	SelfAudit *selfaudit.Service
	// Addons serves /api/v1/apps/{app}/addons… (E2.3: Postgres/Redis addons and backups).
	Addons *addons.Service
	// Updates records `redoubt update` / auto-update events on the audit chain (E3.3).
	Updates *update.Recorder
}

Deps are the services the API exposes. Handlers contain no business logic: every operation is a call into the service layer, which is also what the CLI and the HTMX UI use.

type ErrorResponse

type ErrorResponse struct {
	Error string `json:"error"`
}

ErrorResponse is the JSON error envelope.

type LoginResponse

type LoginResponse struct {
	NeedsTOTP bool     `json:"needs_totp"`
	User      UserView `json:"user"`
}

LoginResponse is returned by Login.

type Principal

type Principal struct {
	User      db.User
	SessionID string
	// Bootstrap is true for the file-based bootstrap token, honoured only while no user exists
	// (D-011): it carries every permission so the first Owner can be created and the Phase 0
	// demo path keeps working on a fresh install.
	Bootstrap bool
	// TOTPPending is true for a cookie session whose second factor has not been presented.
	TOTPPending bool
}

Principal is the authenticated caller of a request.

func PrincipalFrom

func PrincipalFrom(ctx context.Context) (Principal, bool)

PrincipalFrom returns the request principal (zero value + false when unauthenticated).

func (Principal) Actor

func (p Principal) Actor() deploy.Actor

Actor converts the principal into the service layer's actor.

func (Principal) Can

func (p Principal) Can(perm auth.Permission) bool

Can reports whether the principal holds a permission.

type RateLimit

type RateLimit struct {
	PerMinute int `json:"per_minute"`
	Burst     int `json:"burst"`
}

RateLimit is one token bucket: PerMinute tokens are refilled continuously and the bucket holds at most Burst. A zero PerMinute disables the limit for its class.

func ParseRateLimit

func ParseRateLimit(s string) (RateLimit, error)

ParseRateLimit parses "<per-minute>/<burst>" (e.g. "60/30"). "0/0" disables the class.

func (RateLimit) String

func (l RateLimit) String() string

String renders the limit for audit details and logs.

type RateLimits

type RateLimits struct {
	// Auth covers credential-bearing requests: POST /api/v1/auth/{login,bootstrap,totp} and the
	// dashboard's /login, /setup and /login/totp forms.
	Auth RateLimit `json:"auth"`
	// Webhook covers deliveries to /api/v1/webhooks/*.
	Webhook RateLimit `json:"webhook"`
	// API covers everything else (JSON API and dashboard pages).
	API RateLimit `json:"api"`
}

RateLimits configures the three request classes the middleware distinguishes.

func DefaultRateLimits

func DefaultRateLimits() RateLimits

DefaultRateLimits are the shipped limits (plan §3: brute-force protection + rate limiting).

func RateLimitsFromEnv

func RateLimitsFromEnv(getenv func(string) string) (RateLimits, error)

RateLimitsFromEnv returns the defaults overridden by any REDOUBT_RATELIMIT_* variables.

type RestoreRequest

type RestoreRequest struct {
	BackupID string `json:"backup_id"`
}

RestoreRequest is the body of POST /apps/{app}/addons/{name}/restore.

type Route

type Route struct {
	Method  string `json:"method"`
	Pattern string `json:"pattern"`
}

Route is one registered method + pattern.

func Routes

func Routes() []Route

Routes lists every route the server registers when all services are configured. It mounts the router with placeholder (never-called) services, so it reflects the real route table (docs/API.md is generated from it and TestAPIReferenceMatchesRoutes keeps them in sync).

type SessionView

type SessionView struct {
	ID         string `json:"id"`
	IP         string `json:"ip"`
	UserAgent  string `json:"user_agent"`
	CreatedAt  string `json:"created_at"`
	LastSeenAt string `json:"last_seen_at"`
	ExpiresAt  string `json:"expires_at"`
	// Current marks the session the request itself was made with.
	Current bool `json:"current"`
}

SessionView is what a user sees about their own sessions (never the token hash).

type SystemInfo

type SystemInfo struct {
	ServerVersion   string   `json:"server_version"`
	SecurityOptions []string `json:"security_options"`
	OperatingSystem string   `json:"operating_system"`
	Containers      int      `json:"containers"`
	Images          int      `json:"images"`
	BuildCacheBytes int64    `json:"build_cache_bytes"`
}

SystemInfo is the subset of docker info the API exposes.

type UserDetail

type UserDetail struct {
	UserView
	Disabled  bool   `json:"disabled"`
	UpdatedAt string `json:"updated_at"`
}

UserDetail is the administrative view of a user: UserView plus the account state.

type UserPatch

type UserPatch struct {
	Role     *string `json:"role,omitempty"`
	Disabled *bool   `json:"disabled,omitempty"`
}

UserPatch is the body of PATCH /users/{id}; absent fields are left unchanged.

type UserView

type UserView struct {
	ID          string `json:"id"`
	Email       string `json:"email"`
	Role        string `json:"role"`
	TOTPEnabled bool   `json:"totp_enabled"`
	CreatedAt   string `json:"created_at"`
}

UserView is the API representation of a user (no hashes, no secrets).

Jump to

Keyboard shortcuts

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