Infisical CI Secrets Migration
Centralized secret management for GitHub Actions via self-hosted Infisical.
Architecture
Section titled “Architecture”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 varsGitHub Secrets (only 3 required)
Section titled “GitHub Secrets (only 3 required)”| 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.
Infisical Secret Paths
Section titled “Infisical Secret Paths”All CI secrets are organized under /ci/ with environment-scoped slugs
(staging, production).
| Path | Secrets | Used By |
|---|---|---|
/ci/shared | TURBO_TOKEN, RELEASE_PAT | validate.yml, release.yml |
/ci/cloudflare | CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID | deploy-email-worker, deploy-ops-mcp, deploy-tidycal-hubspot-sync, graphify-nightly, version-aware-build, deploy-docs |
/ci/gcp | GCP_SA_KEY | gcp-deploy, deploy-webapp (base image pull) |
/ci/coolify | COOLIFY_TOKEN, COOLIFY_PRODUCTION_WEBHOOK_WEB, COOLIFY_STAGING_WEBHOOK_WEB, COOLIFY_PRODUCTION_WEBHOOK_INTERNAL | deploy-webapp, version-aware-build |
/ci/clerk | PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY | deploy-webapp, deploy-branch-gate, validate, version-aware-build, flagsmith-seed, staging-canary (E2E) |
/ci/posthog | PUBLIC_POSTHOG_KEY, PUBLIC_POSTHOG_HOST | deploy-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, MOMENTIC_API_KEY, E2E_FLAG_OVERRIDE_SECRET | momentic-staging, staging-canary |
/ci/database | DATABASE_URL (env-scoped: staging has STAGING_DATABASE_URL, production has PROD_DATABASE_URL) | deploy-webapp (migrations), db-maintenance, flagsmith-seed |
/ci/integrations | LINEAR_API_KEY, GEMINI_API_KEY, STAGING_WEBAPP_URL | linear-close-on-merge, graphify-nightly, version-aware-build |
Migrated Workflows
Section titled “Migrated Workflows”| 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-ops-mcp.yml | /ci/cloudflare | Both staging + production jobs |
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/coolify, /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 |
linear-close-on-merge.yml | /ci/integrations | Linear API key |
match-correctness-eval.yml | /ci/eval | Langfuse keys |
gcp-deploy.yml | /ci/gcp | GCP service account |
release.yml | /ci/shared | RELEASE_PAT for auto-merge |
momentic-staging.yml | /ci/e2e | E2E test + Momentic secrets |
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 |
Workflows NOT Migrated (no secrets needed)
Section titled “Workflows NOT Migrated (no secrets needed)”These workflows use only GITHUB_TOKEN (auto-provided) or no secrets at all:
detect-versions.ymltest-migrations.ymlcodeql.ymldeploy-dagster.yml(uses GITHUB_TOKEN only)deploy-temporal.yml(uses GITHUB_TOKEN only)
Setup Instructions
Section titled “Setup Instructions”1. Create Machine Identity in Infisical
Section titled “1. Create Machine Identity in Infisical”- Go to
https://infisical.ordermatic.co> Project Settings > Machine Identities - Create a new identity (e.g.,
github-actions-ci) - Enable Universal Auth method
- Copy the Client ID and Client Secret
2. Create Folder Structure in Infisical
Section titled “2. Create Folder Structure in Infisical”Create the following folders under both staging and production environments:
/ci/shared/ci/cloudflare/ci/gcp/ci/coolify/ci/clerk/ci/posthog/ci/eval/ci/flagsmith/ci/e2e/ci/database/ci/integrations
3. Populate Secrets
Section titled “3. Populate Secrets”Copy the current GitHub Secrets values into the corresponding Infisical paths. See the path→secret mapping table above for which secrets go where.
4. Grant Machine Identity Access
Section titled “4. Grant Machine Identity Access”Grant the github-actions-ci identity read access to /ci/* in both
staging and production environments.
5. Configure GitHub Secrets
Section titled “5. Configure GitHub Secrets”Add these 3 secrets to the GitHub repository:
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID= Client ID from step 1INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET= Client Secret from step 1INFISICAL_PROJECT_ID= your Infisical project ID
6. Remove Old GitHub Secrets
Section titled “6. Remove Old GitHub Secrets”After verifying all workflows work with Infisical, remove the ~40 individual secrets from GitHub Settings > Secrets.
Composite Action Usage
Section titled “Composite Action Usage”# 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"