Skip to main content
One YAML file. One workflow. Every target repo in sync.
JacobPEvans/secrets-sync is the distribution layer. Doppler holds the source-of-truth values; secrets-sync fans them out to every target repo’s GitHub Actions secrets and variables. It is intentionally not a vault: it never stores plaintext at rest and never logs values.

Doppler is the only writer

Every GitHub Actions secret and variable — org level and repo level alike — is owned by Doppler and arrives by sync. None are authored in GitHub, and none can be set through the API. This is enforced, not merely conventional. The GitHub App behind every minted token deliberately holds no secrets or variables permission. App permissions are granted once at installation; a per-call request can only narrow what the installation already holds, never widen it. So any read or write against /actions/secrets or /actions/variables returns 403 Resource not accessible by integration at either scope. That 403 is the control working as intended — not a gap to work around by minting a different token or escalating privileges. Every change here is a manual, human-reviewed step. Rotating a value means editing it in Doppler. Granting an existing secret to a new repository means adding that repo to the appropriate anchor in secrets-config.yml and merging the PR under CODEOWNERS review. There is no automated path, and automation is not the goal: writes to the credential distribution layer are deliberately gated on a human.

Workflow internals

load-config reads secrets-config.yml and emits two JSON arrays (secrets, variables). The fail-fast gate is the most important defence: if the PAT cannot reach any repo named in the config, the run terminates before writing anywhere.

Repo groupings via YAML anchors

The config uses YAML anchors so each repo joins a group exactly once; secrets reference the group, not the repo list. Anchors are append-only in practice: a repo joins a group by adding it to the anchor’s list, not by referencing it from a single secret. The two-level structure (anchor → secret) keeps the config DRY and reviewable.

Adding a secret — the high-level path

  1. Add the secret value to Doppler (or directly to secrets-sync repo if it is not a Doppler-managed value).
  2. Add an entry under secrets: in secrets-config.yml, referencing the appropriate anchor for repositories:.
  3. Open a PR. CODEOWNERS (you) approves; branch protection requires it.
  4. Merge to main. The workflow runs and syncs.
For the literal commands (PAT setup, gh secret set, dry-run flag, fork-friendly forking), see the secrets-sync README. That is the operational runbook; this page is the architecture.

Source / alias semantics

Secrets can have a source: field separate from name:. When set, the workflow reads the value from secrets[source] and writes it to target repos under name. This is how a single Doppler-held secret can be distributed under different names per target repo without renaming it in Doppler.

Rotation cadence — best practice

  • GH_PAT_SECRETS_SYNC_ACTION (the PAT the workflow uses): 90 days, aligned with GitHub’s fine-grained PAT default.
  • Doppler service tokens (the DOPPLER_TOKEN distributed to infra repos): 90 days, aligned with PAT.
  • GitHub App private keys: annually or on suspected compromise.
  • SSH signing keys: on key rotation, which is rare.
Each rotation updates a single value in Doppler (or secrets-sync repo secrets) and triggers a fresh workflow run. Target repos pick up the new value automatically.

What secrets-sync is not

  • Not a vault. Values are written, never queried by the workflow.
  • Not a CI runtime fetcher — Tier 2 infra secrets use dopplerhq/secrets-fetch-action at workflow runtime instead.
  • Not a label / branch-protection / metadata manager — that is dryvist/tofu-github.
  • Not a bootstrap tool. New repos must already exist; the workflow validates and writes.

See also

  • Doppler — the upstream source of truth for most Tier 1 secrets.
  • GitHub access — how GitHub credentials are issued for local work, without storing a token.
  • How it fits together — flow diagrams placing secrets-sync in the larger picture.