4040 ("GEOLITE2_ASN_MMDB_FILE_LOCATION" , str , "" ),
4141 # Whether to try adding dummy data
4242 ("ADD_DUMMY_DATA" , bool ),
43- # Donations
44- ("ENABLE_DONATIONS" , bool ),
43+ # Donations (gated at runtime by the `donations_enabled` feature flag)
4544 ("STRIPE_API_KEY" , str ),
4645 ("STRIPE_WEBHOOK_SECRET" , str ),
4746 ("STRIPE_RECURRING_PRODUCT_ID" , str ),
48- # Strong verification through Iris ID
49- ("ENABLE_STRONG_VERIFICATION" , bool ),
47+ # Strong verification through Iris ID (gated at runtime by the `strong_verification_enabled` feature flag)
5048 ("IRIS_ID_PUBKEY" , str ),
5149 ("IRIS_ID_SECRET" , str ),
5250 ("VERIFICATION_DATA_PUBLIC_KEY" , bytes ),
53- # Postal verification
54- ("ENABLE_POSTAL_VERIFICATION" , bool ),
55- # MyPostcard API credentials
51+ # Postal verification (MyPostcard API; gated at runtime by the `postal_verification_enabled` feature flag)
5652 ("MYPOSTCARD_API_KEY" , str ),
5753 ("MYPOSTCARD_USERNAME" , str ),
5854 ("MYPOSTCARD_PASSWORD" , str ),
5955 ("MYPOSTCARD_PRODUCT_CODE" , str ),
6056 ("MYPOSTCARD_CAMPAIGN_ID" , str ),
61- # SMS
62- ("ENABLE_SMS" , bool ),
57+ # SMS (gated at runtime by the `sms_enabled` feature flag)
6358 ("SMS_SENDER_ID" , str ),
6459 # Email
6560 ("ENABLE_EMAIL" , bool ),
6964 ("NOTIFICATION_EMAIL_ADDRESS" , str ),
7065 # An optional prefix for email subject, e.g. [STAGING]
7166 ("NOTIFICATION_PREFIX" , str , "" ),
72- ("ENABLE_NOTIFICATION_TRANSLATIONS" , bool ),
73- ("ENABLE_EMAIL_ICS_ATTACHMENTS" , bool ),
7467 # Address to send emails about reported users
7568 ("REPORTS_EMAIL_RECIPIENT" , str ),
7669 # Address to send contributor forms when users sign up/fill the form
108101 ("LISTMONK_API_USERNAME" , str ),
109102 ("LISTMONK_API_KEY" , str ),
110103 ("LISTMONK_LIST_ID" , int ),
111- # Google recaptcha antibot
112- ("RECAPTHCA_ENABLED" , bool ),
104+ # Google recaptcha antibot (gated at runtime by the `recaptcha_enabled` feature flag)
113105 ("RECAPTHCA_PROJECT_ID" , str ),
114106 ("RECAPTHCA_API_KEY" , str ),
115107 ("RECAPTHCA_SITE_KEY" , str ),
122114 # GrowthBook SDK configuration
123115 ("GROWTHBOOK_API_HOST" , str , "https://cdn.growthbook.io" ),
124116 ("GROWTHBOOK_CLIENT_KEY" , str , "" ),
117+ # Disk path for the last-known-good feature payload, used as a cold-start fallback when GrowthBook
118+ # is unreachable. Required when experimentation is enabled so we never start on in-code defaults.
119+ ("GROWTHBOOK_CACHE_PATH" , str , "" ),
125120 # Moderation auto-approval deadline in seconds (0 to disable auto-approval)
126121 ("MODERATION_AUTO_APPROVE_DEADLINE_SECONDS" , int ),
127122 # User ID of the bot user for automated moderation actions
@@ -147,32 +142,35 @@ def check_config(cfg: dict[str, Any]) -> None:
147142 raise Exception ("Production site must be over HTTPS" )
148143 if not cfg ["ENABLE_EMAIL" ]:
149144 raise Exception ("Production site must have email enabled" )
150- if not cfg ["ENABLE_SMS" ]:
151- raise Exception ("Production site must have SMS enabled" )
152145 if cfg ["IN_TEST" ]:
153146 raise Exception ("IN_TEST while not DEV" )
154147
155- if cfg ["ENABLE_DONATIONS" ]:
148+ # Donations are gated at runtime by the `donations_enabled` feature flag, which can be flipped on
149+ # remotely at any time, so prod must always have Stripe credentials present so the feature can run.
156150 if not cfg ["STRIPE_API_KEY" ] or not cfg ["STRIPE_WEBHOOK_SECRET" ] or not cfg ["STRIPE_RECURRING_PRODUCT_ID" ]:
157- raise Exception ("No Stripe API key/recurring donation ID but donations enabled " )
151+ raise Exception ("Stripe credentials must be configured in production " )
158152
159- if cfg ["ENABLE_STRONG_VERIFICATION" ]:
153+ # The following features are gated at runtime by feature flags (`strong_verification_enabled`,
154+ # `postal_verification_enabled`, `recaptcha_enabled`), which can be flipped on remotely at any
155+ # time, so prod must always have their credentials present.
160156 if not cfg ["IRIS_ID_PUBKEY" ] or not cfg ["IRIS_ID_SECRET" ] or not cfg ["VERIFICATION_DATA_PUBLIC_KEY" ]:
161- raise Exception ("No Iris ID pubkey/secret or verification data pubkey but strong verification enabled" )
162-
163- if cfg ["ENABLE_POSTAL_VERIFICATION" ]:
157+ raise Exception ("Iris ID credentials must be configured in production" )
164158 if (
165159 not cfg ["MYPOSTCARD_API_KEY" ]
166160 or not cfg ["MYPOSTCARD_USERNAME" ]
167161 or not cfg ["MYPOSTCARD_PASSWORD" ]
168162 or not cfg ["MYPOSTCARD_PRODUCT_CODE" ]
169163 or not cfg ["MYPOSTCARD_CAMPAIGN_ID" ]
170164 ):
171- raise Exception ("MyPostcard API credentials not configured but postal verification enabled" )
165+ raise Exception ("MyPostcard API credentials must be configured in production" )
166+ if not cfg ["RECAPTHCA_PROJECT_ID" ] or not cfg ["RECAPTHCA_API_KEY" ] or not cfg ["RECAPTHCA_SITE_KEY" ]:
167+ raise Exception ("reCAPTCHA credentials must be configured in production" )
172168
173169 if cfg ["EXPERIMENTATION_ENABLED" ]:
174170 if not cfg ["GROWTHBOOK_CLIENT_KEY" ]:
175171 raise Exception ("No GrowthBook client key but experimentation enabled" )
172+ if not cfg ["GROWTHBOOK_CACHE_PATH" ]:
173+ raise Exception ("No GrowthBook cache path but experimentation enabled" )
176174
177175
178176def make_config () -> dict [str , Any ]:
0 commit comments