type: decision
status: active
timestamp: 2026-06-22
tags: [decision, env, secrets, single-source, automation, gh-org-secrets, minimum-manual]

Single env source: c:/D/oriz/.env ? auto-push to chirag127 GH Org Secrets ? apps consume at build

Master .env single source. GH Action pushes org secrets daily

Single env source: c:/D/oriz/.env ? GH Org Secrets

Decision

c:/D/oriz/.env (gitignored on master) is the single, authoritative source of every secret + config value used anywhere in the chirag127/oriz family.

A scheduled cron (.github/workflows/sync-env-to-org-secrets.yml on master) runs daily at 06:30 IST (or on-demand workflow_dispatch when c:/D/oriz/.env changes):

  1. Reads templates/.env.example to enumerate canonical key names
  2. For each key, reads the corresponding value from c:/D/oriz/.env (loaded via secure GH-Action secret OR encrypted file — see “Bootstrapping” below)
  3. Pushes each value to chirag127 GH Org Secrets: gh secret set <KEY> --org chirag127 --visibility all --body "<VALUE>"
  4. Every repo’s workflows + builds inherit the org secret automatically (no per-repo setup)

User mandate verbatim (2026-06-22 evening): “I want to set the single token for all of the authentication and all of the monetization and all of the everything. I want minimum number of environment variable to be set. … I will set them only one time. Throughout the organization of my GitHub. … The builder will generate the website and deploy it on whatever server or this repository’s .env file will also be served as a single source of truth for all of the environment variables. You will periodically push all of the environment variable from this repository to GitHub. … I don’t want to set environment variable manually for all of the apps and all of the websites.”

Bootstrap (one-time, manual — minimum manual work)

You manually populate c:/D/oriz/.env ONCE with the canonical values (~50-80 env vars total). Then never touch them per-repo again.

To run the sync script the first time:

  1. Generate a chirag127 GH Personal Access Token with admin:org scope (one-time, 1-year expiry)
  2. Add it to c:/D/oriz/.env as GH_ADMIN_PAT=ghp_...
  3. Run node scripts/sync-env-to-org-secrets.mjs locally — this pushes all current keys to org-level secrets
  4. After local verification, the GH Action takes over on the daily cron

Sync script

c:/D/oriz/scripts/sync-env-to-org-secrets.mjs:

// 1. Parse templates/.env.example for canonical key names
// 2. Parse c:/D/oriz/.env for values
// 3. For each key, call: gh secret set <KEY> --org chirag127 --visibility all
// 4. Report diff (keys added, updated, deleted)

Bootstrapping the GH Action

The cron workflow needs access to c:/D/oriz/.env itself. Options:

A. encrypted-file approach (RECOMMENDED): encrypt .env with age or sops, commit the encrypted blob to master, decrypt in GH Action using a single bootstrap key stored as SOPS_AGE_KEY org secret. One bootstrap secret ? unlimited derived secrets.

B. manual-paste approach: GH Action accepts the .env content as an input on workflow_dispatch; you paste it once + it pushes all keys. Re-paste only when keys rotate.

Choosing (A): encrypted-file. Use sops + age. The unencrypted .env stays gitignored locally; the encrypted .env.enc is committed to master.

Consuming env vars in app builds

Every app’s CF Pages build inherits chirag127 org secrets automatically. Apps reference process.env.RAZORPAY_KEY_ID etc. — no per-app setup needed.

For client-side env vars (PUBLIC_*), Astro embeds them at build time via import.meta.env.PUBLIC_*. Same single source.

Implications

Supersedes-in-part

security/env-and-secrets-single-source.md — that file describes the two-track delivery (.env.example synced + GH Actions secrets set once). This file extends it with the AUTOMATED periodic-sync mechanism (was implicit; now explicit).

Cross-refs

Status: deployed 2026-06-22

First-run results (local bootstrap, 2026-06-22):


Edit on GitHub · Back to index