Environment Variables Setup - striae-org/striae GitHub Wiki
This guide is the source of truth for Striae environment and secret handling after the proxy/auth migration.
All deployment automation is Bash-based. On Windows, run commands in Git Bash or WSL.
Script Inventory
npm run deploy-config->scripts/deploy-config.shnpm run update-env->scripts/deploy-config.sh --update-envnpm run install-workers->scripts/install-workers.shnpm run deploy-workers-> deploy all worker servicesnpm run deploy-workers:secrets->scripts/deploy-worker-secrets.shnpm run deploy-pages:secrets->scripts/deploy-pages-secrets.shnpm run deploy-pages->scripts/deploy-pages.shnpm run deploy:all->scripts/deploy-all.shnpm run enable-totp-mfa->scripts/enable-totp-mfa.mjs
Required Before Setup: admin-service.json
Create the Firebase Admin credential file before running config/secrets scripts:
mkdir -p app/config
cp -f app/config-example/admin-service.json app/config/admin-service.json
Populate the file with real Firebase service-account JSON.
Required fields:
project_idclient_emailprivate_key
Imported by scripts as:
PROJECT_IDFIREBASE_SERVICE_ACCOUNT_EMAILFIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY
Variable Ownership Model
Use this model to avoid drift during deployments:
.envis local source input for deployment scripts.- Worker secrets are pushed with
deploy-worker-secrets.sh. - Pages secrets are pushed with
deploy-pages-secrets.sh. - Generated runtime/config files are updated by
deploy-config.sh.
Important:
- Firebase Web SDK values (
API_KEY,AUTH_DOMAIN,PROJECT_ID, etc.) are client config, not server secrets. - Firebase Admin values remain private and are loaded from
app/config/admin-service.json. - Cloudflare Access worker JWT variables (
CF_ACCESS_*) are not part of the default script-driven deployment flow.
What deploy-config Updates
npm run deploy-config performs the full config sync/replace pass:
- Creates
.envfrom.env.examplewhen needed. - Copies/syncs config examples and worker template files.
- Preserves
app/config/admin-service.jsonduring sync. - Imports Firebase Admin credentials from
app/config/admin-service.json. - Prompts for required values and auto-generates selected secrets.
- Generates manifest signing, export encryption, data-at-rest encryption, and user-KV encryption key pairs/key ids when missing.
- Normalizes key registry env vars for export/data-at-rest/user-KV encryption (
*_KEYS_JSON+*_ACTIVE_KEY_ID) to support key-rotation fallback. - Replaces placeholders in generated files.
- Runs validation checkpoint (
required vars, format checks, placeholder checks, generated-file checks).
deploy-config.sh also prompts for IMAGE_SIGNED_URL_SECRET, which the Image Worker uses to mint and verify signed image-access tokens.
IMAGE_SIGNED_URL_BASE_URL is auto-derived from PAGES_CUSTOM_DOMAIN by deploy-config.sh (for example https://your-domain.com/api/image) and overrides the base URL used when the Image Worker builds signed delivery URLs. It is optional but should be set for all standard Page-proxied deployments.
Files updated by deploy-config.sh include:
wrangler.toml(PAGES_PROJECT_NAME)workers/*/wrangler.jsonc(worker names, account id, bucket/kv bindings)app/config/config.json(app URL, signing, export encryption key metadata)app/config/firebase.ts(Firebase Web SDK config placeholders)
Use npm run update-env only when you intentionally want to reset from .env.example and refresh generated config files.
Secret Deployment Contracts
Worker secrets
npm run deploy-workers:secrets currently sets:
- Audit Worker: optional
DATA_AT_REST_ENCRYPTION_ENABLED,DATA_AT_REST_ENCRYPTION_PRIVATE_KEY,DATA_AT_REST_ENCRYPTION_PUBLIC_KEY,DATA_AT_REST_ENCRYPTION_KEY_ID,DATA_AT_REST_ENCRYPTION_KEYS_JSON,DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID - User Worker:
PROJECT_ID,FIREBASE_SERVICE_ACCOUNT_EMAIL,FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY; optionalDATA_AT_REST_ENCRYPTION_PRIVATE_KEY,DATA_AT_REST_ENCRYPTION_KEY_ID,DATA_AT_REST_ENCRYPTION_KEYS_JSON,DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID,USER_KV_ENCRYPTION_PRIVATE_KEY,USER_KV_ENCRYPTION_KEYS_JSON,USER_KV_ENCRYPTION_ACTIVE_KEY_ID; whenUSER_KV_WRITE_ENDPOINTS_ENABLEDis true:USER_KV_ENCRYPTION_KEY_ID,USER_KV_ENCRYPTION_PUBLIC_KEY - Data Worker:
MANIFEST_SIGNING_PRIVATE_KEY,MANIFEST_SIGNING_KEY_ID,EXPORT_ENCRYPTION_PRIVATE_KEY,EXPORT_ENCRYPTION_KEY_ID; optionalDATA_AT_REST_ENCRYPTION_ENABLED,DATA_AT_REST_ENCRYPTION_PRIVATE_KEY,DATA_AT_REST_ENCRYPTION_PUBLIC_KEY,DATA_AT_REST_ENCRYPTION_KEY_ID,DATA_AT_REST_ENCRYPTION_KEYS_JSON,DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID,EXPORT_ENCRYPTION_KEYS_JSON,EXPORT_ENCRYPTION_ACTIVE_KEY_ID - Image Worker:
DATA_AT_REST_ENCRYPTION_PUBLIC_KEY,DATA_AT_REST_ENCRYPTION_KEY_ID,IMAGE_SIGNED_URL_SECRET; optionalDATA_AT_REST_ENCRYPTION_PRIVATE_KEY,DATA_AT_REST_ENCRYPTION_KEYS_JSON,DATA_AT_REST_ENCRYPTION_ACTIVE_KEY_ID,IMAGE_SIGNED_URL_BASE_URL - PDF Worker:
ACCOUNT_ID,BROWSER_API_TOKEN - Lists Worker:
LISTS_ADMIN_SECRET
EXPORT_ENCRYPTION_PRIVATE_KEY and EXPORT_ENCRYPTION_KEY_ID are mandatory for case package, confirmation package, and archive package workflows, which are encrypted by default and fail closed when encryption material is missing.
EXPORT_ENCRYPTION_KEYS_JSON and EXPORT_ENCRYPTION_ACTIVE_KEY_ID are optional but recommended for key rotation. When present, the Data Worker attempts decryption with package key ID first and then registry fallback keys.
MANIFEST_SIGNING_PRIVATE_KEY and MANIFEST_SIGNING_KEY_ID are mandatory for the Data Worker to sign case manifests.
USER_KV_ENCRYPTION_PRIVATE_KEY, USER_KV_ENCRYPTION_PUBLIC_KEY, and USER_KV_ENCRYPTION_KEY_ID are mandatory for user profile reads/writes in the User Worker. User profile requests fail closed when this key material is missing or when stored KV values are not encrypted envelopes. USER_KV_ENCRYPTION_PUBLIC_KEY and USER_KV_ENCRYPTION_KEY_ID are only pushed when USER_KV_WRITE_ENDPOINTS_ENABLED is true (the default); set it to false for read-only deployments.
USER_KV_ENCRYPTION_KEYS_JSON and USER_KV_ENCRYPTION_ACTIVE_KEY_ID are optional rotation helpers for user-KV decryption fallback.
DATA_AT_REST_ENCRYPTION_ENABLED must be true in all standard deployments; data-at-rest encryption is mandatory and validation will fail if it is disabled.
For detailed encryption implementation, key registry architecture, and rotation strategy, see Data-at-Rest Encryption.
app/config/config.json is also populated with the public export encryption key material (EXPORT_ENCRYPTION_PUBLIC_KEY, EXPORT_ENCRYPTION_KEY_ID) for browser-side package encryption.
IMAGE_SIGNED_URL_SECRET is an Image Worker secret only and is not deployed as a Pages secret. Signed image GET requests carry an st query token that Pages forwards directly to the Image Worker via service binding; the Image Worker validates the token against IMAGE_SIGNED_URL_SECRET.
IMAGE_SIGNED_URL_BASE_URL overrides the base URL the Image Worker uses when building signed delivery URLs. It is auto-derived from PAGES_CUSTOM_DOMAIN by deploy-config.sh. Only set a custom value when routing signed image delivery through a non-standard domain.
BROWSER_API_TOKEN must be a Cloudflare API token with Browser Rendering - Edit permission.
LISTS_ADMIN_SECRET is the Bearer token guarding the lists-worker write endpoints (POST /members, DELETE /members, POST /primershear, DELETE /primershear). It is auto-generated by deploy-config.sh and pushed to the lists-worker by deploy-workers:secrets.
Pages secrets
npm run deploy-pages:secrets requires:
PROJECT_ID
Worker routing is handled by Cloudflare Service Bindings defined in wrangler.toml; no *_WORKER_DOMAIN secrets are required in the Pages environment.
Registration Gateway Workflow
Use this workflow to restrict new account registration to specific email addresses or domains.
The registration allowlist is stored in the STRIAE_LISTS KV namespace under the key "allow" (managed by the lists-worker). To add or remove entries:
# Add an entry
curl -X POST https://lists.<your-domain>/members \
-H "Authorization: Bearer $LISTS_ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"entry": "[email protected]"}'
# Or write the full CSV directly via wrangler
wrangler kv key put --remote --namespace-id=<STRIAE_LISTS_KV_ID> "allow" "[email protected],@organization.com"
Each entry is either an exact email address ([email protected]) or a domain wildcard (@organization.com). Matching is case-insensitive. When the list is empty, registration is unrestricted.
To inspect the current list:
curl https://lists.<your-domain>/members
# or
wrangler kv key get --remote --namespace-id=<STRIAE_LISTS_KV_ID> "allow"
PrimerShear Email List Workflow
Use this workflow when you want verified users on an allowlist to receive the primershear PDF format.
The primershear allowlist is stored in the STRIAE_LISTS KV namespace under the key "primershear" (managed by the lists-worker). To add or remove entries:
# Add an entry
curl -X POST https://lists.<your-domain>/primershear \
-H "Authorization: Bearer $LISTS_ADMIN_SECRET" \
-H "Content-Type: application/json" \
-d '{"entry": "[email protected]"}'
# Or write the full CSV directly via wrangler
wrangler kv key put --remote --namespace-id=<STRIAE_LISTS_KV_ID> "primershear" "[email protected]"
To inspect the current list:
curl https://lists.<your-domain>/primershear
# or
wrangler kv key get --remote --namespace-id=<STRIAE_LISTS_KV_ID> "primershear"
Recommended Deployment Sequence
npm run deploy:all runs this sequence:
deploy-config.shinstall-workers.sh- Worker deploys (
npm run deploy-workers) deploy-worker-secrets.shdeploy-pages-secrets.shdeploy-pages.sh
Redeploy Guidance After Secret Changes
- Worker-secret-only changes usually do not require re-running worker code deployment.
- Pages secret changes should be followed by a Pages deployment so current deployments pick up updated values.
- Any
deploy-configchange that modifies generated source/config files should be followed by normal deploy steps for affected services.
Validation and Troubleshooting
Validate generated state without changing files:
bash ./scripts/deploy-config.sh --validate-only
Common issues:
- Missing
app/config/admin-service.json: create from template and populate required fields. - Placeholder errors: run
npm run deploy-configand complete prompts. - Invalid domain values: remove protocol/path/trailing slash from domain vars.
- Missing worker Wrangler files: ensure
wrangler.jsoncis copied from eachwrangler.jsonc.example. - JSON parse failures in app requests (
Unexpected token '<'): confirm requests go through/api/*, verify Pages secrets, and inspect response status/body for upstream auth/challenge failures.
Security Notes
- Never commit
.envor real credentials. - Keep
app/config/admin-service.jsonprivate. - Avoid logging secrets or sensitive validation material.