Files
cgalo5758 ad7a219adf Enforce schema and boot invariants
Enforce 10j's verified gaps (schema-hardening change):

- Migration 00010: partial unique indexes for one default pool and one
  primary assignment per workspace, plus CHECKs pinning
  pool/provider/subscription vocabularies and provider lifecycle
  timestamps.
- Workspace creation shares a transactional provisioning function;
  extension validates its target pool; last-tier deletion of a defaulted
  ladder is guarded; signup completes plan-less on a broken ladder.
- Boot asserts integration slug parity and validates declared config
  enums; Stripe invoice amounts are range-checked; domain cancellation
  runs a final evidence probe; rule authoring is additive-only.
2026-08-22 18:02:46 -05:00

4.8 KiB

startup-configuration Specification

Purpose

TBD - created by archiving change boot-config-validation. Update Purpose after archive.

Requirements

Requirement: Boot-time configuration validation

The member-console start command SHALL validate its required configuration before initializing any service (database, Temporal, or HTTP server), and SHALL exit non-zero with an aggregated, actionable error when validation fails. Validation SHALL run after configuration is resolved from flags, environment variables, the config file, and any *-secret-file references, so that file-backed secrets are validated by value. Each reported problem SHALL name the offending configuration key and how to set it (its MC_* environment variable or mc-config.yaml key), and a single run SHALL report every problem at once rather than only the first.

The following core configuration SHALL be required unconditionally: db-dsn (a valid PostgreSQL URL), valkey-addr, oidc-idp-issuer-url (a valid URL), oidc-sp-client-id, base-url (a valid URL), and csrf-secret (exactly 32 bytes). oidc-sp-client-secret SHALL NOT be required (public PKCE clients have none).

Core conditional requirements SHALL apply: when temporal-host is set, temporal-namespace SHALL be present, and if any temporal-oauth-* field is set then temporal-oauth-token-url, temporal-oauth-client-id, and temporal-oauth-client-secret SHALL all be present.

Integration configuration SHALL be validated from the registered integrations' declared config specs — key presence, secret-file resolution, and required-together groups — with the same aggregation and error-message conventions. Per-integration validation rules SHALL NOT be hardcoded in the core validator; Stripe's rule (when stripe-mode is live or any Stripe credential is present, both stripe-api-key and stripe-webhook-secret SHALL be present) SHALL be expressed as the Stripe integration's declared requirement.

Scenario: Missing required configuration fails fast with a clear message

  • WHEN member-console start runs with an empty db-dsn
  • THEN the command SHALL exit non-zero before connecting to the database or running migrations
  • AND the error SHALL name db-dsn and how to set it (MC_DB_DSN or the db-dsn key in mc-config.yaml)

Scenario: All configuration problems reported together

  • WHEN member-console start runs with several required keys missing or malformed
  • THEN the command SHALL report every problem in a single aggregated error, not just the first

Scenario: Invalid CSRF secret is caught before service startup

  • WHEN csrf-secret is present but not exactly 32 bytes
  • THEN validation SHALL fail before database migrations run (rather than after migrations and Temporal scheduling, as before)

Scenario: Partially configured Stripe is rejected via its declaration

  • WHEN stripe-api-key is set but stripe-webhook-secret is empty
  • THEN validation SHALL fail with a message that both are required to enable billing (or both omitted to disable it)
  • AND the rule SHALL originate from the Stripe integration's config declaration, not from core validator code

Scenario: Partially configured Temporal OAuth is rejected

  • WHEN temporal-host is set and temporal-oauth-client-id is set but temporal-oauth-token-url is empty
  • THEN validation SHALL fail, requiring the OAuth token URL, client ID, and client secret to be set together

Scenario: Valid configuration passes

  • WHEN all required keys are present and well-formed
  • THEN validation SHALL succeed and startup SHALL proceed unchanged

Requirement: Declared enum values are validated at boot

For every registered configuration key that declares an enumerated value set, startup validation SHALL check that the resolved value (from flags, environment, or config file) is a member of the declared set, and SHALL report a violation in the same aggregated, actionable format as other validation failures — naming the key, the offending value, and the allowed values. Unset or empty values SHALL NOT fail this check (presence is governed by the existing required-key rules). The membership logic SHALL be shared with the operator-settings override validation so the two paths cannot diverge.

Scenario: Misspelled enum value stops the boot

  • WHEN the environment sets a declared enum key to a value outside its set (for example an auto-create flag set to "yes" where the set is "true"/"false")
  • THEN startup fails with an error naming the key, the bad value, and the allowed values, instead of booting with silently wrong behavior

Scenario: Valid and unset values pass

  • WHEN every declared enum key is unset or holds a member of its set
  • THEN validation passes exactly as before