// Package config loads and validates the application's runtime configuration. // // Cloud selection is CONFIGURATION, not code (the cloud-portability mandate): the same binary runs // on AWS GovCloud or Azure Government by flipping MM_CLOUD and the provider settings. Nothing here // imports a cloud SDK, adapters live behind interfaces in their own packages and are wired in // cmd/api from this config. package config import ( "encoding/base64" "encoding/hex" "errors" "fmt" "os" "strconv" "strings" "time" ) // Env is the deployment environment. type Env string const ( EnvDevelopment Env = "development" EnvProduction Env = "production" ) // Cloud is the target government cloud. Local is for dev (MinIO, self-hosted embeddings, no managed services). type Cloud string const ( CloudLocal Cloud = "local" CloudAWSGovCloud Cloud = "aws_govcloud" CloudAzureGov Cloud = "azure_gov" ) // EmbeddingProvider selects the embedding adapter. "fake" is a deterministic offline provider for // dev/tests; "openai" is any OpenAI compatible endpoint (self hosted vLLM, the production CUI path, // or OpenAI); "bedrock"/"azure_openai" are the managed gov cloud adapters (wired at deploy time). type EmbeddingProvider string const ( ProviderFake EmbeddingProvider = "fake" ProviderOpenAI EmbeddingProvider = "openai" ProviderBedrock EmbeddingProvider = "bedrock" ProviderAzureOpenAI EmbeddingProvider = "azure_openai" // ProviderMegamind routes embeddings through the stateless MEGAMIND inference plane (the typed // inference client to the gateway), the production self hosted path for cleared CUI data. ProviderMegamind EmbeddingProvider = "megamind" ) // Embeddings configures the embedding provider. Dimension MUST match the vector(N) column width in // the schema (default 384); changing the provider's native dimension is a re-embed migration, not a // config flip (STACK_DECISIONS.md ยง6). type Embeddings struct { Provider EmbeddingProvider Endpoint string // base URL for the OpenAI-compatible / Azure endpoint Model string // e.g. "text-embedding-3-large", "amazon.titan-embed-text-v2:0", a local model id Dimension int APIKey string // bearer/api-key; for Bedrock/Azure-Entra the adapter uses cloud credentials instead MegamindURL string // base URL of the MEGAMIND gateway when Provider is "megamind" } // Inference configures the typed client to the stateless MEGAMIND inference plane (embeddings, // reranking, generation, faithfulness). The heavy models run out of process on the Apple Silicon // cluster; this is the only AI compute the FIPS API binary reaches, over HTTP. URL empty means the AI // layer is unconfigured and its routes degrade rather than fail the boot. type Inference struct { URL string // MEGAMIND gateway base, reached over Tailscale EmbedModel string // 384 dim embedder (all-minilm or bge-small-en-v1.5) RerankModel string // cross encoder (bge-reranker-v2-m3) or the cosine baseline GenerateModel string // local instruct model (e.g. llama3.1:8b) Dimension int // must match the vector(N) column width TimeoutSeconds int // per request MaxRetries int // additional attempts on a transient failure BreakerTrips int // consecutive failures before the breaker opens BreakerCoolSec int // how long the breaker stays open TeachingEnabled bool // federated craft signal transmission; disabled until multiple live clients exist } // ExtractorProvider selects the Mission Check structured extraction adapter (resume or job description // text to proposed fields). "deterministic" is the offline rules plus ontology extractor and the // default; an LLM backed provider (self hosted vLLM for CUI in production) is a future addition behind // the same port. Extraction runs server side only, so a key here never reaches the browser bundle. type ExtractorProvider string const ( ExtractorDeterministic ExtractorProvider = "deterministic" ) // Extraction configures the Mission Check structured extraction provider. Endpoint, Model, and APIKey // are reserved for a future provider backed extractor and are unused by the deterministic one. type Extraction struct { Provider ExtractorProvider Endpoint string Model string APIKey string } // Auth holds the server side secrets and tunables for the authentication module. Every secret here // loads from the environment (the root owned secrets file), never the repo or the browser bundle. type Auth struct { PepperVersion int // active credential pepper version stored on new credentials Pepper []byte // active credential pepper key (HMAC applied before PBKDF2) PepperPrevious []byte // optional prior pepper key (version PepperVersion minus 1) for rotation TOTPKEKVersion int // active TOTP secret KEK version TOTPKEK []byte // 32 byte AES 256 key encrypting TOTP secrets at rest TOTPKEKPrevious []byte // optional prior TOTP KEK (version TOTPKEKVersion minus 1) so a rotated KEK still decrypts older secrets // OrgSecretKEK seals per organization credentials in org_secrets: a customer's own SMTP password today, // a source connector credential when in place federation lands. It is a SEPARATE key from the TOTP KEK // on purpose. Both are 32 byte AES 256 keys handled by the same primitive, but they protect different // populations of secret with different rotation pressure, and one key covering both means one disclosure // covers both. When it is unset, storing an organization secret fails closed and says so. OrgSecretKEKVersion int OrgSecretKEK []byte OrgSecretKEKPrevious []byte CSRFKey []byte // HMAC key binding a CSRF token to its session RecoveryLookupKey []byte // HMAC key for recovery code lookup tags TOTPIssuer string // issuer shown in the authenticator app SessionIdleSeconds int // idle timeout (NIST 800-171 3.1.11 default 900) SessionAbsoluteSeconds int // absolute session cap (default 43200, 12 hours) PendingAbsoluteSeconds int // auth_pending (pre MFA) session cap (default 300) InviteExpirySeconds int // invite and activation link lifetime (default 259200, 72 hours) CookieSecure bool // Secure attribute on the session cookie (true except plain http dev) MFARequired bool // when false, login mints an active session after password with no TOTP step (pilot only, forbidden in production) // OperatorMFARequired governs the operator seat alone. Amendment 6 decision 1 makes a second factor // mandatory for operator from the day the role exists, independent of MM_MFA_REQUIRED, and that stays // the DEFAULT here so the rule holds unless a deployment deliberately stands it down. // // It is a setting rather than a constant because Joseph explicitly directed, on 28 July 2026, that his // production operator account not be prompted for MFA at this time. Making that a configuration value // keeps his decision in one auditable place instead of deleting the rule from the code, keeps the // staging gate proving the rule on its default, and turns re arming it into an env change rather than a // release. Like MM_MFA_REQUIRED it cannot be stood down in a production MM_ENV. OperatorMFARequired bool } // Config is the fully-resolved, validated application configuration. type Config struct { Env Env HTTPAddr string // AppDBRole is the database role the app pool MUST authenticate as, asserted at boot. It is // configuration rather than a constant so an environment can run under its OWN isolated role: staging // and production share one Postgres cluster, so staging running as the production app role means the // staging process can reach the production database. Naming the expected role per environment is what // lets staging hold a role with zero privileges on production while the assertion stays exactly as // strict, still failing the boot closed on a mismatch and still refusing a role with BYPASSRLS. AppDBRole string AppDatabaseURL string // NOBYPASSRLS app role DSN MigratorDatabaseURL string // BYPASSRLS migrator role DSN (used by goose only) ComplianceDatabaseURL string // compliance role DSN, the only path that reads the eeo schema; empty disables adverse impact reporting (503) AioeDatabaseURL string // the dedicated missionmatch_aioe role DSN for the optimization engine batch updater; empty leaves the updater off while outcome capture keeps recording AioeShadowMode bool // when true the updater proposes candidate weight profiles a human must promote, never auto activating (the safe pilot posture) SecretsFile string // path of the root owned KEY=VALUE secret file (0600); empty means env only (local dev) DecisionRetentionDays int // retention window for identifiable screening artifacts after a decision (default 90) Cloud Cloud Embeddings Embeddings Inference Inference Extraction Extraction RequireFIPS bool // when true, cmd/api aborts unless crypto/fips140.Enabled() AllowDevHeaderAuth bool // dev only X-Org-ID resolver toggle; MUST be false in production // AllowSelfHostedProduction lets a production deployment run with MM_CLOUD=local. It exists so a self // hosted federation can enforce every OTHER production control without lying about which cloud it is on. AllowSelfHostedProduction bool CurationEnforceSeparation bool // MM_CURATION_SEPARATION_OF_DUTIES: require the curation verifier to differ from the approver (default true); a single operator pilot may set it false to self verify, an explicit audited choice BidOutcomesEnabled bool // MM_BID_OUTCOMES_ENABLED: gate the M7 bid outcomes recording routes (default false); ships DORMANT so the ledger accrues win and loss labels only once an operator turns it on, no learned model consumes it yet AllowedOrigins []string // CSRF Origin allowlist for unsafe verbs; empty disables the check (dev) TrustedProxyHeader string // header carrying the real client IP (set by a trusted reverse proxy); empty uses the TCP peer // AppBaseURL is the public address of the web application, used to build the activation link inside an // invitation email. It DEFAULTS to the first allowed origin rather than to a guess, because that value is // already the address the browser really talks to, and a credential bearing link to the wrong hostname is // worse than no link at all. AppBaseURL string Auth Auth Federated Federated Tenancy Tenancy } // TenancyMode selects how tenant isolation is achieved physically. type TenancyMode string const ( // TenancyShared is the pool model: one database, every tenant's rows in the same tables, isolation // enforced by forced Row Level Security and the per request org GUC. This is the default and the // posture the product has shipped with. TenancyShared TenancyMode = "shared" // TenancyPerTenant is the silo model: each organization's business data lives in its OWN database, // resolved per request through the tenant directory. RLS stays forced inside every tenant database, // so the two mechanisms stack rather than one replacing the other. // // The reason this mode exists is not only isolation. Because the directory records a host and port // per tenant, tenants can live on DIFFERENT MACHINES, which is what lets the deployment spread load // across the federation without ever needing multi master writes: every tenant still has exactly one // primary, so the row locks that enforce seat caps, stage transitions, and ownership claims keep // working unchanged. TenancyPerTenant TenancyMode = "per_tenant" ) // Tenancy configures the database per tenant routing layer. It is INERT in shared mode: none of the // pool, directory, or secret resolver machinery is constructed unless Mode is per_tenant. type Tenancy struct { Mode TenancyMode // SecretsBackend resolves a tenant's credential REFERENCE from the directory into a real DSN. // "env" reads a root owned environment file (development and staging); the government cloud stores // are wired at deploy so no cloud SDK enters the core build. SecretsBackend string // SecretTTL bounds how long a resolved tenant DSN is cached before the backend is consulted again. // A rotated credential is additionally picked up immediately on an authentication failure, because // the pool manager forgets the reference and retries once. SecretTTL time.Duration // MaxPools caps how many tenant pools are live at once, least recently used evicted beyond it. The // product of MaxPools and MaxConnsPerPool must stay under the server's max_connections, which is why // both are configuration rather than constants. MaxPools int // MaxConnsPerPool keeps each tenant pool small, since many exist concurrently. MaxConnsPerPool int // IdleEvict closes a whole tenant pool after this long with no use, freeing the pool object itself // rather than merely shrinking it the way pgx per connection idle close does. IdleEvict time.Duration } // Federated configures the cross tenant differential privacy aggregation path (WS8). It is INERT by // default: the whole federated package is dead code unless Enabled is true and a real cohort of five or // more live non test tenants exists. Epsilon and Delta are the privacy budget, expressed as // configuration and never as code constants so a privacy officer can sign off and tune them without a // rebuild. In tenant LIVE keeps this off, only the in tenant producer and the human approved curation // pipeline ship enabled. type Federated struct { DPEnabled bool // MM_FEDERATED_DP_ENABLED: master switch for the cross tenant DP release path (default false) DPEpsilon float64 // MM_FEDERATED_DP_EPSILON: the (epsilon, delta) DP budget epsilon target (default 10) DPDelta float64 // MM_FEDERATED_DP_DELTA: the (epsilon, delta) DP budget delta target (default 1e-7) } // Load reads configuration from the environment, applies defaults, and validates it. func Load() (Config, error) { // Secret key decode errors are collected and surfaced alongside validation errors, so a // misconfigured deploy sees every problem at once instead of one boot failure at a time. var secretErrs []error getB := func(key string) []byte { b, err := getBytes(key) if err != nil { secretErrs = append(secretErrs, err) } return b } c := Config{ Env: Env(getDefault("MM_ENV", string(EnvDevelopment))), HTTPAddr: getDefault("MM_HTTP_ADDR", ":8080"), AppDBRole: getDefault("MM_APP_DB_ROLE", "missionmatch_app"), AppDatabaseURL: os.Getenv("MM_DATABASE_URL"), MigratorDatabaseURL: os.Getenv("MM_MIGRATOR_DATABASE_URL"), ComplianceDatabaseURL: os.Getenv("MM_COMPLIANCE_DATABASE_URL"), AioeDatabaseURL: os.Getenv("MM_AIOE_DATABASE_URL"), AioeShadowMode: os.Getenv("MM_AIOE_SHADOW") == "true", SecretsFile: os.Getenv("MM_SECRETS_FILE"), DecisionRetentionDays: getInt("MM_DECISION_RETENTION_DAYS", 90), Tenancy: Tenancy{ // Shared is the default, so an existing deployment that sets none of these keeps its current // behaviour exactly. Per tenant routing is opt in, per environment. Mode: TenancyMode(getDefault("MM_TENANCY_MODE", string(TenancyShared))), SecretsBackend: getDefault("MM_TENANT_SECRETS_BACKEND", "env"), SecretTTL: getDuration("MM_TENANT_SECRET_TTL", 15*time.Minute), MaxPools: getInt("MM_TENANT_MAX_POOLS", 32), MaxConnsPerPool: getInt("MM_TENANT_MAX_CONNS_PER_POOL", 4), IdleEvict: getDuration("MM_TENANT_IDLE_EVICT", 15*time.Minute), }, Cloud: Cloud(getDefault("MM_CLOUD", string(CloudLocal))), Embeddings: Embeddings{ Provider: EmbeddingProvider(getDefault("MM_EMBED_PROVIDER", string(ProviderFake))), Endpoint: os.Getenv("MM_EMBED_ENDPOINT"), Model: os.Getenv("MM_EMBED_MODEL"), Dimension: getInt("MM_EMBED_DIMENSION", 384), APIKey: os.Getenv("MM_EMBED_API_KEY"), MegamindURL: os.Getenv("MM_MEGAMIND_URL"), }, Inference: Inference{ URL: os.Getenv("MM_MEGAMIND_URL"), // bge-small-en-v1.5 (384 dim) is the production embedder, served on Ollama as the qllama handle. // Stored and query vectors MUST use the same model: switching the model requires a FULL re // backfill (existing vectors from another model are incompatible), see DEPLOY_PLAN.md. EmbedModel: getDefault("MM_MEGAMIND_EMBED_MODEL", "qllama/bge-small-en-v1.5"), RerankModel: getDefault("MM_MEGAMIND_RERANK_MODEL", "bge-reranker-v2-m3"), GenerateModel: getDefault("MM_MEGAMIND_GENERATE_MODEL", "llama3.1:8b"), Dimension: getInt("MM_EMBED_DIMENSION", 384), TimeoutSeconds: getInt("MM_MEGAMIND_TIMEOUT_SECONDS", 30), MaxRetries: getInt("MM_MEGAMIND_MAX_RETRIES", 2), BreakerTrips: getInt("MM_MEGAMIND_BREAKER_TRIPS", 5), BreakerCoolSec: getInt("MM_MEGAMIND_BREAKER_COOL_SECONDS", 30), TeachingEnabled: getBool("MM_MEGAMIND_TEACHING_ENABLED", false), }, Extraction: Extraction{ Provider: ExtractorProvider(getDefault("MM_EXTRACT_PROVIDER", string(ExtractorDeterministic))), Endpoint: os.Getenv("MM_EXTRACT_ENDPOINT"), Model: os.Getenv("MM_EXTRACT_MODEL"), APIKey: os.Getenv("MM_EXTRACT_API_KEY"), }, RequireFIPS: getBool("MM_REQUIRE_FIPS", false), AllowDevHeaderAuth: getBool("MM_ALLOW_DEV_HEADER_AUTH", false), AllowSelfHostedProduction: getBool("MM_ALLOW_SELF_HOSTED_PRODUCTION", false), CurationEnforceSeparation: getBool("MM_CURATION_SEPARATION_OF_DUTIES", true), BidOutcomesEnabled: getBool("MM_BID_OUTCOMES_ENABLED", false), AllowedOrigins: splitCSV(os.Getenv("MM_ALLOWED_ORIGINS")), TrustedProxyHeader: os.Getenv("MM_TRUSTED_PROXY_HEADER"), AppBaseURL: strings.TrimRight(strings.TrimSpace(os.Getenv("MM_APP_BASE_URL")), "/"), Auth: Auth{ PepperVersion: getInt("MM_CREDENTIAL_PEPPER_VERSION", 1), Pepper: getB("MM_CREDENTIAL_PEPPER"), PepperPrevious: getB("MM_CREDENTIAL_PEPPER_PREVIOUS"), TOTPKEKVersion: getInt("MM_TOTP_KEK_VERSION", 1), TOTPKEK: getB("MM_TOTP_KEK"), TOTPKEKPrevious: getB("MM_TOTP_KEK_PREVIOUS"), OrgSecretKEKVersion: getInt("MM_ORG_SECRET_KEK_VERSION", 1), OrgSecretKEK: getB("MM_ORG_SECRET_KEK"), OrgSecretKEKPrevious: getB("MM_ORG_SECRET_KEK_PREVIOUS"), CSRFKey: getB("MM_CSRF_KEY"), RecoveryLookupKey: getB("MM_RECOVERY_LOOKUP_KEY"), TOTPIssuer: getDefault("MM_TOTP_ISSUER", "missionMATCH"), SessionIdleSeconds: getInt("MM_SESSION_IDLE_SECONDS", 900), SessionAbsoluteSeconds: getInt("MM_SESSION_ABSOLUTE_SECONDS", 43200), PendingAbsoluteSeconds: getInt("MM_SESSION_PENDING_SECONDS", 300), InviteExpirySeconds: getInt("MM_INVITE_EXPIRY_SECONDS", 259200), CookieSecure: getBool("MM_COOKIE_SECURE", true), MFARequired: getBool("MM_MFA_REQUIRED", true), OperatorMFARequired: getBool("MM_OPERATOR_MFA_REQUIRED", true), }, Federated: Federated{ DPEnabled: getBool("MM_FEDERATED_DP_ENABLED", false), DPEpsilon: getFloat("MM_FEDERATED_DP_EPSILON", 10), DPDelta: getFloat("MM_FEDERATED_DP_DELTA", 1e-7), }, } if err := c.Validate(); err != nil { secretErrs = append(secretErrs, err) } if len(secretErrs) > 0 { return Config{}, errors.Join(secretErrs...) } return c, nil } // Validate enforces invariants and environment-specific requirements. Errors are joined so a // misconfigured deploy surfaces every problem at once. func (c Config) Validate() error { var errs []error switch c.Env { case EnvDevelopment, EnvProduction: default: errs = append(errs, fmt.Errorf("MM_ENV %q invalid (want development|production)", c.Env)) } switch c.Cloud { case CloudLocal, CloudAWSGovCloud, CloudAzureGov: default: errs = append(errs, fmt.Errorf("MM_CLOUD %q invalid (want local|aws_govcloud|azure_gov)", c.Cloud)) } // The activation link host falls back to the first allowed origin, which is already the exact address the // browser is permitted to talk to. Deriving it means one fewer setting an operator can get wrong, and the // derived value cannot point somewhere the CSRF allowlist would have refused anyway. if c.AppBaseURL == "" && len(c.AllowedOrigins) > 0 { c.AppBaseURL = strings.TrimRight(strings.TrimSpace(c.AllowedOrigins[0]), "/") } switch c.Embeddings.Provider { case ProviderFake, ProviderOpenAI, ProviderBedrock, ProviderAzureOpenAI, ProviderMegamind: default: errs = append(errs, fmt.Errorf("MM_EMBED_PROVIDER %q invalid", c.Embeddings.Provider)) } if c.Embeddings.Dimension <= 0 { errs = append(errs, errors.New("MM_EMBED_DIMENSION must be > 0")) } switch c.Tenancy.Mode { // Empty is shared. A Config built programmatically rather than through Load leaves Tenancy zero // valued, and the zero value must mean the default posture rather than a validation failure. case TenancyShared, "": case TenancyPerTenant: // In per tenant mode MM_DATABASE_URL stops being the data plane and becomes the CONTROL PLANE // pool: it is what the router reads the tenant directory through. Without it there is no way to // discover any tenant database, so the service could not serve a single request. if c.AppDatabaseURL == "" { errs = append(errs, errors.New("MM_DATABASE_URL (the control plane pool) required when MM_TENANCY_MODE=per_tenant")) } if c.Tenancy.MaxPools < 1 { errs = append(errs, errors.New("MM_TENANT_MAX_POOLS must be >= 1")) } if c.Tenancy.MaxConnsPerPool < 1 { errs = append(errs, errors.New("MM_TENANT_MAX_CONNS_PER_POOL must be >= 1")) } switch c.Tenancy.SecretsBackend { case "env", "aws_govcloud", "azure_gov": default: errs = append(errs, fmt.Errorf("MM_TENANT_SECRETS_BACKEND %q invalid (want env|aws_govcloud|azure_gov)", c.Tenancy.SecretsBackend)) } default: errs = append(errs, fmt.Errorf("MM_TENANCY_MODE %q invalid (want shared|per_tenant)", c.Tenancy.Mode)) } // Empty selects the deterministic extractor (the same default extraction.New applies), so a Config // built without an explicit provider validates. switch c.Extraction.Provider { case ExtractorDeterministic, "": default: errs = append(errs, fmt.Errorf("MM_EXTRACT_PROVIDER %q invalid (want deterministic)", c.Extraction.Provider)) } // OpenAI-compatible providers need an endpoint + model. if c.Embeddings.Provider == ProviderOpenAI || c.Embeddings.Provider == ProviderAzureOpenAI { if c.Embeddings.Endpoint == "" { errs = append(errs, fmt.Errorf("MM_EMBED_ENDPOINT required for provider %q", c.Embeddings.Provider)) } if c.Embeddings.Model == "" { errs = append(errs, fmt.Errorf("MM_EMBED_MODEL required for provider %q", c.Embeddings.Provider)) } } // The MEGAMIND provider needs the gateway URL and the embed model name. if c.Embeddings.Provider == ProviderMegamind { if c.Embeddings.MegamindURL == "" { errs = append(errs, errors.New("MM_MEGAMIND_URL required for provider \"megamind\"")) } if c.Embeddings.Model == "" && c.Inference.EmbedModel == "" { errs = append(errs, errors.New("MM_EMBED_MODEL or MM_MEGAMIND_EMBED_MODEL required for provider \"megamind\"")) } } // TOTP secrets are AES 256, so the KEK must be exactly 32 bytes whenever it is set, in any env. if len(c.Auth.TOTPKEK) != 0 && len(c.Auth.TOTPKEK) != 32 { errs = append(errs, errors.New("MM_TOTP_KEK must decode to exactly 32 bytes (AES 256)")) } if len(c.Auth.TOTPKEKPrevious) != 0 && len(c.Auth.TOTPKEKPrevious) != 32 { errs = append(errs, errors.New("MM_TOTP_KEK_PREVIOUS must decode to exactly 32 bytes (AES 256)")) } // Same rule for the organization secret KEK, and for the same reason: a key of the wrong length is a boot // time mistake, not a runtime surprise discovered the first time a customer saves a password. if len(c.Auth.OrgSecretKEK) != 0 && len(c.Auth.OrgSecretKEK) != 32 { errs = append(errs, errors.New("MM_ORG_SECRET_KEK must decode to exactly 32 bytes (AES 256)")) } if len(c.Auth.OrgSecretKEKPrevious) != 0 && len(c.Auth.OrgSecretKEKPrevious) != 32 { errs = append(errs, errors.New("MM_ORG_SECRET_KEK_PREVIOUS must decode to exactly 32 bytes (AES 256)")) } if c.Auth.PepperVersion <= 0 { errs = append(errs, errors.New("MM_CREDENTIAL_PEPPER_VERSION must be positive")) } if c.Auth.SessionIdleSeconds <= 0 || c.Auth.SessionAbsoluteSeconds <= 0 || c.Auth.PendingAbsoluteSeconds <= 0 { errs = append(errs, errors.New("session timeout seconds must all be positive")) } if c.DecisionRetentionDays <= 0 { errs = append(errs, errors.New("MM_DECISION_RETENTION_DAYS must be positive")) } if c.Env == EnvProduction { if c.AppDatabaseURL == "" { errs = append(errs, errors.New("MM_DATABASE_URL required in production")) } if c.Embeddings.Provider == ProviderFake { errs = append(errs, errors.New("the fake embedding provider must not be used in production")) } // A production deployment must name a government cloud, UNLESS the operator explicitly declares a // self hosted deployment with MM_ALLOW_SELF_HOSTED_PRODUCTION. // // The check exists to stop someone shipping to a commercial region by accident, not to forbid // running the platform on hardware you own. Self hosting is a legitimate posture for cleared work, // and it is arguably the stricter one: nothing leaves the operator's own network. What is NOT // acceptable is resolving the conflict by setting MM_CLOUD to a government cloud you are not on, // because that string travels into compliance conversations and would be a false claim. // // So the escape hatch is deliberately a SEPARATE, explicitly named flag rather than a widening of // the cloud vocabulary: MM_CLOUD keeps telling the truth (local), and the operator has to state // once, on purpose, that local is intended here. It is logged at boot so it can never be a silent // default that somebody inherits without knowing. if c.Cloud == CloudLocal && !c.AllowSelfHostedProduction { errs = append(errs, errors.New( "MM_CLOUD must be a government cloud in production, or set MM_ALLOW_SELF_HOSTED_PRODUCTION=true "+ "to declare a deliberate self hosted deployment")) } // The dev X-Org-ID resolver may never be the production tenant source. if c.AllowDevHeaderAuth { errs = append(errs, errors.New("MM_ALLOW_DEV_HEADER_AUTH must be false in production")) } // FIPS must be enforced, not optional, so the validated crypto path is the one that runs. if !c.RequireFIPS { errs = append(errs, errors.New("MM_REQUIRE_FIPS must be true in production")) } // Every auth secret must be present so the validated crypto has its keys. if len(c.Auth.Pepper) == 0 { errs = append(errs, errors.New("MM_CREDENTIAL_PEPPER required in production")) } if len(c.Auth.TOTPKEK) != 32 { errs = append(errs, errors.New("MM_TOTP_KEK (32 byte AES 256 key) required in production")) } if len(c.Auth.CSRFKey) == 0 { errs = append(errs, errors.New("MM_CSRF_KEY required in production")) } if len(c.Auth.RecoveryLookupKey) == 0 { errs = append(errs, errors.New("MM_RECOVERY_LOOKUP_KEY required in production")) } // The CSRF Origin allowlist must be enforced; an empty list disables it (a dev only path). if len(c.AllowedOrigins) == 0 { errs = append(errs, errors.New("MM_ALLOWED_ORIGINS required in production (the CSRF Origin allowlist must be enforced)")) } // Both cookies use the __Host- prefix, which a browser only accepts when Secure is set; a non // Secure production deploy silently breaks all auth and exposes the token. if !c.Auth.CookieSecure { errs = append(errs, errors.New("MM_COOKIE_SECURE must be true in production (the __Host- cookie prefix requires Secure)")) } // MFA is mandatory in production. The pilot only password only relaxation can never ship to a // government cloud, so a production deploy with it set is a hard configuration error. if !c.Auth.MFARequired { errs = append(errs, errors.New("MM_MFA_REQUIRED must be true in production (MFA is mandatory)")) } // The operator relaxation is a pilot accommodation like the one above, and it is refused in a // production MM_ENV for the same reason: the platform plane reaches every tenant at once, so it is // the last seat that should ever be reachable with a password alone in a government cloud. if !c.Auth.OperatorMFARequired { errs = append(errs, errors.New("MM_OPERATOR_MFA_REQUIRED must be true in production (the platform plane always requires a second factor)")) } } return errors.Join(errs...) } // IsProduction reports whether this is a production deployment. func (c Config) IsProduction() bool { return c.Env == EnvProduction } func getDefault(key, def string) string { if v := strings.TrimSpace(os.Getenv(key)); v != "" { return v } return def } func getInt(key string, def int) int { if v := strings.TrimSpace(os.Getenv(key)); v != "" { if n, err := strconv.Atoi(v); err == nil { return n } } return def } // getDuration reads a Go duration string such as "15m" or "90s". An unparseable value falls back to the // default rather than failing the boot, matching how getInt and getBool already behave: a malformed // tuning knob should not take the service down, and the effective value is logged at startup. func getDuration(key string, def time.Duration) time.Duration { if v := strings.TrimSpace(os.Getenv(key)); v != "" { if d, err := time.ParseDuration(v); err == nil { return d } } return def } func getBool(key string, def bool) bool { if v := strings.TrimSpace(os.Getenv(key)); v != "" { if b, err := strconv.ParseBool(v); err == nil { return b } } return def } func getFloat(key string, def float64) float64 { if v := strings.TrimSpace(os.Getenv(key)); v != "" { if f, err := strconv.ParseFloat(v, 64); err == nil { return f } } return def } // splitCSV splits a comma separated env value into trimmed, non empty entries. func splitCSV(v string) []string { if strings.TrimSpace(v) == "" { return nil } parts := strings.Split(v, ",") out := make([]string, 0, len(parts)) for _, p := range parts { if t := strings.TrimSpace(p); t != "" { out = append(out, t) } } return out } // getBytes loads a secret key from the environment using an EXPLICIT encoding prefix so the key // material is never ambiguous: "base64:", "hex:", or "raw:". A bare value (no prefix) is decoded as // standard base64, and a decode failure is a hard error rather than a silent fall back to the raw // string. The silent fall back was a real footgun: a passphrase that happens to be valid base64 would // be decoded to different bytes than the operator intended, so the same variable could mean two // different keys in two contexts (a TOTP KEK that no longer decrypts its secrets, a pepper that no // longer verifies its passwords). Forcing the operator to declare the encoding removes that class of // bug. An unset variable yields nil with no error. func getBytes(key string) ([]byte, error) { v := strings.TrimSpace(os.Getenv(key)) if v == "" { return nil, nil } switch { case strings.HasPrefix(v, "raw:"): return []byte(strings.TrimPrefix(v, "raw:")), nil case strings.HasPrefix(v, "hex:"): b, err := hex.DecodeString(strings.TrimPrefix(v, "hex:")) if err != nil { return nil, fmt.Errorf("%s: invalid hex value: %w", key, err) } return b, nil case strings.HasPrefix(v, "base64:"): b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(v, "base64:")) if err != nil { return nil, fmt.Errorf("%s: invalid base64 value: %w", key, err) } return b, nil default: b, err := base64.StdEncoding.DecodeString(v) if err != nil { return nil, fmt.Errorf("%s: value must be base64, or carry a raw: / hex: / base64: prefix: %w", key, err) } return b, nil } }