server

package
v0.9.9 Latest Latest
Warning

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

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

Documentation

Overview

Package server is the control-plane HTTP service: it records multi-stack Terraform executions, drives one GitHub check run per environment, and projects approval-gate state — all as a pure function of its SQLite store. Terraform itself runs in the user's own CI; this server observes and gates.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

type App struct {

	// Approval is the optional approval-gate backend. nil disables gating
	// (gates recorded AWAITING are never satisfied → action_required). Set after
	// construction (e.g. by the serve command), so New's signature is unchanged.
	Approval approval.Backend
	// Objects is the optional object store for completed-log offload. nil keeps
	// logs in the local buffer only. Set after construction, like Approval.
	Objects ObjectStore
	// PushVerifier verifies a Pub/Sub push OIDC bearer token, returning the
	// token's email claim. Set externally (like Approval/Objects); nil disables
	// the /pubsub/push endpoint (it returns 404).
	PushVerifier func(ctx context.Context, bearer string) (email string, err error)
	// contains filtered or unexported fields
}

App is the HTTP application.

func New

func New(db *sql.DB, gh GitHub, cfg Config) *App

New builds an App.

func (*App) CleanLogBuffers added in v0.9.0

func (a *App) CleanLogBuffers(maxAge time.Duration)

CleanLogBuffers removes execution buffer directories older than maxAge — orphans left by restarts mid-execution. Call at startup.

func (*App) ReconcileLoop

func (a *App) ReconcileLoop(ctx context.Context, interval time.Duration)

ReconcileLoop periodically re-evaluates every not-yet-ACTIVE gate, so a grant that goes ACTIVE after the request (the common case) converges to success even with no provider event. No-op without a backend. Blocks until ctx is cancelled.

func (*App) Routes

func (a *App) Routes() http.Handler

Routes returns the HTTP handler. Uses stdlib method-pattern routing (Go 1.22+). Auth model:

  • /api/* require a short-lived HS256 JWT (aud=api) — generated by CI
  • /live/* /pr/ /{$} require a 30-day HS256 JWT (aud=view) via ?token= or cookie
  • /img/* /assets/* public (GitHub camo + CSS must not require auth)
  • /logs/* public (accessed inline by the live page after view auth)

type CheckRunUpdate

type CheckRunUpdate struct {
	Summary    string // GFM progress task list (renders at the top)
	Text       string // the rendered plan report (renders below the progress)
	DetailsURL string // the live page for the full view
	Conclusion string // "" while running; otherwise success|failure|action_required|neutral
}

CheckRunUpdate carries everything a PATCH to a check run needs.

type Config

type Config struct {
	// WebhookSecret is the bearer token required on /api/* mutations. Empty
	// disables auth (local/dev only).
	WebhookSecret string
	// PublicBaseURL is the public origin used for check-run Details links. Empty
	// derives it from the inbound request (e.g. behind a TLS-terminating proxy).
	PublicBaseURL string
	// UseChecks true → drive a rich GitHub check run (needs checks:write);
	// false → link mode, posting a commit status (needs statuses:write).
	UseChecks bool
	// ReconcilerCore routes server-side gate/execution state transitions through
	// the pure reconcile core (internal/reconcile) instead of the legacy
	// handlers. Off by default; engaged only at quiescence (see Task 19).
	ReconcilerCore bool
	// LogsDir is where per-stack log buffers are written. Empty disables log
	// ingestion (the endpoints become no-ops).
	LogsDir string
	// GroupDepth controls the live DAG's grouping: stacks fold into groups by
	// their first GroupDepth path segments. 0 = unset → handlers default to 2.
	GroupDepth int
	// GroupPattern is a regexp whose first capture group is the group key;
	// overrides GroupDepth. Empty → fall back to GroupDepth grouping.
	GroupPattern string
	// PushServiceAccount is the allowed verified OIDC email for /pubsub/push.
	// Empty accepts any verified token.
	PushServiceAccount string
	// GitHubWebhookSecret is the HMAC-SHA256 secret GitHub sends on every webhook
	// delivery (X-Hub-Signature-256). Empty disables the /github/webhook endpoint.
	GitHubWebhookSecret string
}

Config is the server runtime configuration.

type FSStore

type FSStore struct{ Root string }

FSStore is a filesystem-backed ObjectStore rooted at Root.

func (FSStore) Get

func (s FSStore) Get(_ context.Context, key string) (io.ReadCloser, error)

func (FSStore) Put

func (s FSStore) Put(_ context.Context, key string, r io.Reader) error

type GitHub

type GitHub interface {
	// CreateCheckRun opens an in_progress check run with the given name whose
	// Details link is detailsURL; returns its id.
	CreateCheckRun(ctx context.Context, repo, sha, name, detailsURL string) (int64, error)
	// UpdateCheckRun patches an existing check run.
	UpdateCheckRun(ctx context.Context, repo string, checkRunID int64, u CheckRunUpdate) error
	// PostStatus sets a commit status (link-mode fallback).
	PostStatus(ctx context.Context, repo, sha, context_, state, description, targetURL string) error
	// PRHeadSHA returns the current head commit SHA of a pull request, so a
	// verdict is posted on the live head rather than a stale execution SHA.
	PRHeadSHA(ctx context.Context, repo string, pr int) (string, error)
	// PRClosed reports whether a pull request is in the closed state (merged or
	// abandoned). Returns (false, err) when the PR cannot be read.
	PRClosed(ctx context.Context, repo string, pr int) (bool, error)
}

GitHub is the surface the server needs from GitHub. A rich check run requires a GitHub App with checks:write; the link-mode fallback posts a commit status (statuses:write) whose target URL points at the live page. The real implementation lands in a later sub-plan; tests use MockGitHub.

type MockGitHub

type MockGitHub struct {
	CreateCheckRunFn func(ctx context.Context, repo, sha, name, detailsURL string) (int64, error)
	UpdateCheckRunFn func(ctx context.Context, repo string, checkRunID int64, u CheckRunUpdate) error
	PostStatusFn     func(ctx context.Context, repo, sha, context_, state, description, targetURL string) error
	PRHeadSHAFn      func(ctx context.Context, repo string, pr int) (string, error)
	PRClosedFn       func(ctx context.Context, repo string, pr int) (bool, error)
	// CreateCheckRunCalls counts CreateCheckRun invocations so tests can assert
	// the check run is created exactly once (idempotency).
	CreateCheckRunCalls int
}

MockGitHub is a test double for GitHub. Unset funcs are no-ops.

func (*MockGitHub) CreateCheckRun

func (m *MockGitHub) CreateCheckRun(ctx context.Context, repo, sha, name, detailsURL string) (int64, error)

func (*MockGitHub) PRClosed added in v0.9.5

func (m *MockGitHub) PRClosed(ctx context.Context, repo string, pr int) (bool, error)

func (*MockGitHub) PRHeadSHA

func (m *MockGitHub) PRHeadSHA(ctx context.Context, repo string, pr int) (string, error)

func (*MockGitHub) PostStatus

func (m *MockGitHub) PostStatus(ctx context.Context, repo, sha, context_, state, description, targetURL string) error

func (*MockGitHub) UpdateCheckRun

func (m *MockGitHub) UpdateCheckRun(ctx context.Context, repo string, checkRunID int64, u CheckRunUpdate) error

type ObjectStore

type ObjectStore interface {
	Put(ctx context.Context, key string, r io.Reader) error
	Get(ctx context.Context, key string) (io.ReadCloser, error)
}

ObjectStore persists completed log objects (and, later, plan/verify outputs). FSStore backs tests/local; a cloud impl (e.g. GCS) is wired by the serve command for deployment.

type RealClient

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

RealClient is the production GitHub implementation. It mints a fresh App installation token per request, so the token never goes stale on a long-running service. The App key + ids are supplied by the caller (a deployment concern); RealClient has no cloud-secret-store dependency.

func NewRealClient

func NewRealClient(appID, installationID string, pemKey []byte) (*RealClient, error)

NewRealClient parses the PEM App private key and returns a client for the given App id + installation id.

func (*RealClient) CreateCheckRun

func (c *RealClient) CreateCheckRun(ctx context.Context, repo, sha, name, detailsURL string) (int64, error)

CreateCheckRun opens an in_progress check run with the given name.

func (*RealClient) PRClosed added in v0.9.5

func (c *RealClient) PRClosed(ctx context.Context, repo string, pr int) (bool, error)

PRClosed reports whether the pull request's state is "closed".

func (*RealClient) PRHeadSHA

func (c *RealClient) PRHeadSHA(ctx context.Context, repo string, pr int) (string, error)

PRHeadSHA returns a pull request's current head commit SHA.

func (*RealClient) PostStatus

func (c *RealClient) PostStatus(ctx context.Context, repo, sha, context_, state, description, targetURL string) error

PostStatus sets a commit status (link-mode fallback; needs only statuses:write).

func (*RealClient) UpdateCheckRun

func (c *RealClient) UpdateCheckRun(ctx context.Context, repo string, checkRunID int64, u CheckRunUpdate) error

UpdateCheckRun patches a check run. A non-empty Conclusion completes the run.

type Shell added in v0.9.9

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

Shell is the imperative shell around the pure reconcile core. It gathers a scoped World per signal, runs reconcile.Step to a fixpoint, executes the resulting Actions, and persists the new ChangeSet — serialized per (pr, environment).

func NewShell added in v0.9.9

func NewShell(app *App) *Shell

NewShell builds a Shell bound to an App.

func (*Shell) Handle added in v0.9.9

func (sh *Shell) Handle(ctx context.Context, pr int, env, repo string, sig reconcile.Signal) error

Handle processes one signal for (pr, env) to a fixpoint: gather → Step → save → execute → feed results back, repeating while RequestGrant actions yield new observations. Serialized per (pr, env). maxIters guards the loop.

Jump to

Keyboard shortcuts

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