preflight

package
v0.41.4-rc.2 Latest Latest
Warning

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

Go to latest
Published: Nov 8, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package preflight is the read-only launch check behind `rivolt launch-preflight`: one report an operator reads before the Rivolt Pro flip (the launch runbook: rivolt-infra docs/launch-flip.md). It prints counts, names and status codes only, never a value of a setting, an id or an address, and it switches nothing on: the database part runs in a read-only transaction and the URL part is a GET of public pages.

Index

Constants

This section is empty.

Variables

View Source
var RequiredAlertRules = []RequiredRule{
	{Name: "RivoltBillingOnNoFoundingGrant"},
	{Name: "RivoltEntitlementCountsMissing"},
	{Name: "RivoltStripeWebhookRejected"},
	{Name: "RivoltStripeWebhookUnmapped"},
	{Name: "RivoltStripeWebhookUnmappedExpired"},
	{Name: "RivoltStripeWebhookLag"},
	{Name: "RivoltStripeWebhook5xx", QueryHas: `status=~"5..`},
	{Name: "RivoltStripeRefundApplied"},
	{Name: "RivoltBillingPaymentFailures"},
	{Name: "RivoltBillingNonUS"},
	{Name: "RivoltStripeCancelPending"},
	{Name: "RivoltStripeCancelStuck"},
	{Name: "RivoltDatedNoticeFailed"},
	{Name: "RivoltFoundingNoticeLate"},
	{Name: "RivoltAppleNotificationsRejected"},
	{Name: "RivoltAppleNotificationsUnmapped"},
	{Name: "RivoltBillingStartFailing", QueryHas: `5..`},
}

RequiredAlertRules are the billing alerts that must be loaded for a launch (rivolt-infra rivolt-alerts/manifests billing.yaml and accounts.yaml). Names only are ever printed.

Functions

func EmailURLs

func EmailURLs() []string

EmailURLs are the pages the emails and the launch notice link to, exactly as they state them (rivolt.dev), fragments dropped.

func FoundingFromDB

func FoundingFromDB(pool *sql.DB, demo uuid.UUID) func(ctx context.Context, launch time.Time) (Founding, error)

FoundingFromDB reads the founding dry run's counts in a read-only transaction: nothing can be written through it.

func HTTPAlertRules added in v0.40.23

func HTTPAlertRules(base string) func(context.Context) ([]AlertRule, error)

HTTPAlertRules reads the loaded alerting rules from a Prometheus server (GET /api/v1/rules?type=alert; read-only). The error never carries the address or the body.

func HTTPFetch

func HTTPFetch(ctx context.Context, url string) (int, error)

HTTPFetch GETs url with a short timeout and reports the status after redirects; the body is not read.

func HTTPPostUnsigned

func HTTPPostUnsigned(ctx context.Context, url string) (int, error)

HTTPPostUnsigned POSTs an empty body to url without following redirects and reports the status: what Stripe would get for an event with no signature.

func ManualSteps

func ManualSteps() []string

ManualSteps are the launch prerequisites that live in the Stripe Dashboard, Cloudflare and the Valkey pod, where this command has no view.

func URLs

func URLs(base string) []string

URLs are the pages the launch notice and the billing emails link to, on this deployment's own public base URL (the emails themselves carry rivolt.dev). Fragments are dropped; the Plan card and the export page are one path.

Types

type AlertRule added in v0.40.23

type AlertRule struct {
	Name   string
	Query  string
	Health string // "ok", "err" or "unknown"
}

AlertRule is one alerting rule Prometheus has loaded: its name, its expression and whether the last evaluation worked.

type AlertRuleFindings added in v0.40.23

type AlertRuleFindings struct {
	Found   []string // loaded, with the expected expression, evaluating
	Missing []string // not loaded at all
	Stale   []string // loaded, but the expression is not the fixed one
	Failing []string // loaded, but the last evaluation failed
}

AlertRuleFindings is the outcome of comparing the loaded rules with RequiredAlertRules; names only.

func CheckAlertRules added in v0.40.23

func CheckAlertRules(loaded []AlertRule, required []RequiredRule) AlertRuleFindings

CheckAlertRules compares the loaded rules with the required ones.

type Founding

type Founding struct {
	Accounts int // every account
	Demo     int // 1 when the demo account exists
	Eligible int // accounts created at or before launch, the demo excluded
	Already  int // of those, with a founding row
	ToGrant  int
	After    int // accounts created after the launch instant (not granted)
}

Founding is what the founding grant would do at the launch instant, counts only.

type Input

type Input struct {
	Getenv func(string) string
	// Founding reads the counts; nil: the database part is skipped and the report says so.
	Founding func(ctx context.Context, launch time.Time) (Founding, error)
	// Fetch returns the status of a GET of url; nil skips the URL checks.
	Fetch func(ctx context.Context, url string) (int, error)
	// Webhook returns the status of an UNSIGNED, empty POST to url (Stripe's webhook endpoint); nil skips it.
	Webhook func(ctx context.Context, url string) (int, error)
	// RedisTime runs TIME as the app's Redis user, which is what the shared rate-limit script needs; nil skips it. It reports a denial
	// (the ACL) apart from the other failures.
	RedisTime func(ctx context.Context) (denied bool, err error)
	// AlertRules lists the alerting rules Prometheus has loaded; nil skips the check. An error is a problem: the rules are unverified.
	AlertRules func(ctx context.Context) ([]AlertRule, error)
	// RequiredAlertRules overrides RequiredAlertRules (tests).
	RequiredAlertRules []RequiredRule
	// Stripe reads the Stripe API with the configured key; nil skips it.
	Stripe func(ctx context.Context) StripeFacts
	// BillingAddress is what our Checkout sessions ask for as the billing address (stripebill.BillingAddressCollection): "required" lets the
	// webhook check the country (Rivolt Pro is sold in the US only).
	BillingAddress string
	Launch         time.Time
}

Input is everything the report reads, so a test drives it without a database, a network or the process environment.

type Report

type Report struct {
	Lines []string
	// Problems are what stops the flip; Warnings are worth a look but do not.
	Problems []string
	Warnings []string
}

Report is the result: lines to print and whether the deployment is ready for the flip.

func Run

func Run(ctx context.Context, in Input) *Report

Run builds the report.

func (*Report) Print

func (r *Report) Print(w io.Writer)

Print writes the report.

func (*Report) Ready

func (r *Report) Ready() bool

Ready is true when nothing stops the flip.

type RequiredRule added in v0.40.23

type RequiredRule struct {
	Name     string
	QueryHas string
}

RequiredRule is a billing alert the flip needs live. QueryHas, when set, must appear in the loaded expression: the same name with an older expression is not the fixed rule. (The Stripe webhook 5xx alert existed for a while matching status="5xx" against series whose status label is the numeric code, so it could never fire: the name was there, the rule was dead.)

type StripeFacts

type StripeFacts struct {
	Err                 error
	Live                bool // the key and the prices are in live mode
	PricesActive        bool // both prices exist and are active
	PortalFound         bool
	TermsSet            bool // the Customer Portal's Terms of service URL
	PrivacySet          bool // and its Privacy policy URL
	PaymentMethodUpdate bool // customers can update their payment method in the portal
	// The payment method configuration our Checkout sessions use (RIVOLT_STRIPE_PAYMENT_METHOD_CONFIG): read at all, found and active, and the
	// payment method types it has on (sorted).
	PMCRead    bool
	PMCFound   bool
	PMCActive  bool
	PMCLive    bool // the configuration's livemode, to compare with the mode of the key (Live)
	PMCMethods []string
	// The account's DEFAULT configuration, which our sessions do not use but the Customer Portal's update-payment-method follows.
	CheckoutMethods []string
	CheckoutRead    bool
	// The Stripe API version the server pins on every call (stripebill.APIVersion) and the versions of the account's ENABLED webhook endpoints,
	// whose payloads the webhook structs read. A mismatch, no enabled endpoint, or an unreadable list is a problem.
	PinnedVersion   string
	WebhookRead     bool
	WebhookVersions []string
	TaxRead         bool // Stripe Tax's settings were read (only asked when automatic tax is on)
	TaxActive       bool // and Stripe Tax is active in this mode
}

StripeFacts is what the Stripe API says, booleans and a mode only. Err is set when the key could not read it (sanitised, no key).

Jump to

Keyboard shortcuts

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