Skip to content

Infisical CI Secrets Migration

Centralized secret management for GitHub Actions via self-hosted Infisical.

GitHub Actions Workflow
β”‚
β”œβ”€β”€ secrets.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID ─┐
β”œβ”€β”€ secrets.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET β”œβ”€β”€ 3 GitHub Secrets (only)
└── secrets.INFISICAL_PROJECT_ID β”€β”˜
β”‚
β–Ό
.github/actions/infisical-secrets/action.yml
β”‚ 1. Validate creds
β”‚ 2. Install Infisical CLI
β”‚ 3. infisical login --method=universal-auth
β”‚ 4. infisical export --format=dotenv
β”‚ 5. Append to $GITHUB_ENV + mask values
β–Ό
All downstream steps see secrets as env vars
Secret Purpose
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID Machine identity client ID
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET Machine identity client secret
INFISICAL_PROJECT_ID Infisical project identifier

GITHUB_TOKEN is auto-provided by GitHub and not managed by Infisical.

All CI secrets are organized under /ci/ with environment-scoped slugs (staging, production).

Path Secrets Used By
/ci/shared TURBO_TOKEN validate.yml (release.yml uses the ordermatic-release-bot GitHub App via RELEASE_APP_ID + RELEASE_APP_PRIVATE_KEY rather than RELEASE_PAT)
/ci/cloudflare CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_PAGES_API_TOKEN deploy-email-worker, deploy-content-mcp, deploy-partner-data-api, deploy-tidycal-hubspot-sync, graphify-nightly, deploy-docs (Pages token)
/ci/gcp GCP_SA_KEY gcp-deploy
/ci/clerk PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY deploy-branch-gate, validate, version-aware-build, flagsmith-seed, staging-canary (E2E)
/ci/posthog PUBLIC_POSTHOG_KEY, PUBLIC_POSTHOG_HOST gcp-deploy / Cloud Build (/build/webapp)
/ci/eval EVAL_SERVICE_TOKEN, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, R2_* eval, match-correctness-eval
/ci/flagsmith FLAGSMITH_API_URL, FLAGSMITH_ADMIN_EMAIL, FLAGSMITH_ADMIN_PASSWORD, FLAGSMITH_ENVIRONMENT_KEY flagsmith-seed
/ci/e2e STAGING_TEST_EMAIL, STAGING_TEST_PASSWORD, E2E_FLAG_OVERRIDE_SECRET staging-canary
/ci/database DATABASE_URL (env-scoped: staging has STAGING_DATABASE_URL, production has PROD_DATABASE_URL) db-maintenance, flagsmith-seed, stuck-order-monitor
/ci/integrations GEMINI_API_KEY, STAGING_WEBAPP_URL graphify-nightly, version-aware-build
Workflow Secret Paths Notes
eval.yml /ci/eval E2E test credentials + Langfuse
deploy-email-worker.yml /ci/cloudflare Both staging + production jobs
deploy-docs.yml /ci/cloudflare Pages deploy; token needs Pages:Edit
deploy-tidycal-hubspot-sync.yml /ci/cloudflare Single production deploy
deploy-branch-gate.yml /ci/clerk Typecheck jobs (webapp + internal)
validate.yml /ci/shared, /ci/clerk TURBO_TOKEN + Clerk key
version-aware-build.yml /ci/clerk, /ci/cloudflare, /ci/integrations Build + deploy jobs
db-maintenance.yml /ci/database Environment-scoped (staging/production)
flagsmith-seed.yml /ci/flagsmith, /ci/clerk, /ci/database Multi-path, identity sync
graphify-nightly.yml /ci/cloudflare, /ci/integrations Gemini + Cloudflare R2
match-correctness-eval.yml /ci/eval Langfuse keys
gcp-deploy.yml /ci/gcp GCP service account
release.yml GitHub App (ordermatic-release-bot) Uses RELEASE_APP_ID + RELEASE_APP_PRIVATE_KEY for PR creation and auto-merge (replaced RELEASE_PAT)
staging-canary.yml /ci/e2e Playwright E2E secrets
stuck-order-monitor.yml /ci/database Read-only prod DB
auto-deploy-main.yml /ci/e2e Post-promotion smoke tests

These workflows use only GITHUB_TOKEN (auto-provided) or no secrets at all:

  • detect-versions.yml
  • test-migrations.yml
  • codeql.yml
  • deploy-dagster.yml (uses GITHUB_TOKEN only)
  • deploy-temporal.yml (uses GITHUB_TOKEN only)
  1. Go to https://infisical.ordermatic.co > Project Settings > Machine Identities
  2. Create a new identity (e.g., github-actions-ci)
  3. Enable Universal Auth method
  4. Copy the Client ID and Client Secret

Create the following folders under both staging and production environments:

  • /ci/shared
  • /ci/cloudflare
  • /ci/gcp
  • /ci/clerk
  • /ci/posthog
  • /ci/eval
  • /ci/flagsmith
  • /ci/e2e
  • /ci/database
  • /ci/integrations

Copy the current GitHub Secrets values into the corresponding Infisical paths. See the path→secret mapping table above for which secrets go where.

Grant the github-actions-ci identity read access to /ci/* in both staging and production environments.

Add these 3 secrets to the GitHub repository:

  • INFISICAL_UNIVERSAL_AUTH_CLIENT_ID = Client ID from step 1
  • INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET = Client Secret from step 1
  • INFISICAL_PROJECT_ID = your Infisical project ID

After verifying all workflows work with Infisical, remove the ~40 individual secrets from GitHub Settings > Secrets.

# In your workflow job:
env:
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID: ${{ secrets.INFISICAL_UNIVERSAL_AUTH_CLIENT_ID }}
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET: ${{ secrets.INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET }}
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
- name: Fetch secrets from Infisical
uses: ./.github/actions/infisical-secrets
with:
environment: staging # or 'production'
secret-path: /ci/cloudflare # path to your secrets
# All secrets are now available as env vars
- name: Use secrets
run: echo "Token is masked: $CLOUDFLARE_API_TOKEN"