Private repos are excluded from the 9-host mirror cron
Private repos excluded from mirror cron
Decision
The 9-host mirror cron in .github/workflows/mirror-all.yml MUST NOT push private repos to public mirror hosts. Two filters in series:
- gh list
isPrivatefilter — thegh repo listcalls in the discover step filter byisPrivate == false. Public repos only. - Explicit name EXCLUDE list — even if a repo is mis-flagged as public, its name in this hardcoded list drops it. Defense in depth.
The current exclude list (in mirror-all.yml):
["secrets", "Recovery-codes", "recovery-codes", "envpact-secrets"]
What's covered by this exclusion
| Repo | Owner | Why excluded |
|---|---|---|
chirag127/secrets |
chirag127 | Brand-family secrets store (env files, recovery codes, backups). Private. |
chirag127/secrets |
chirag127 | Personal secrets store. Private. |
chirag127/Recovery-codes |
chirag127 | Personal 2FA codes. Private + air-gapped from secrets. |
chirag127/envpact-secrets |
chirag127 | envpact per-project vault. Private. |
Adding a new private repo to the family
Order matters:
- Create the repo as
privateon GitHub. - Verify the discover step's
isPrivate == falsefilter catches it (it should — automatic). - Add the repo's NAME to the
EXCLUDEarray inmirror-all.ymleven though step 2 already handles it. Belt-and-suspenders. - THEN add as a submodule to the umbrella if desired.
Reversing step 3 + step 4 is the most likely way to leak. Always exclude FIRST, submodule SECOND.
Why filter + exclude both
Single-layer filtering breaks if:
- A repo's
privateflag is accidentally toggled to public via the GitHub UI gh repo listAPI output schema changes (unlikely but possible)- The discover step's jq filter has a typo
The name-list catches all three. Cost of maintaining two filters: 0 (just add the name when creating). Cost of a leak: catastrophic.
What's NOT in scope of this rule
- Per-repo
.github/workflows/*.ymlworkflows — those run inside their own repo's context and can't accidentally leak it (GitHub Actions in a private repo can't push the repo's code to a public destination unless the workflow explicitly does so). - B2 metadata backup — that pushes to a private B2 bucket, not a public mirror, so privacy is preserved regardless.
Cross-refs
- The mirror decision: [[decisions/ops/mirror-to-9-popular-alternatives-2026-06-28]]
- The mirror workflow itself:
.github/workflows/mirror-all.yml(umbrella root) - The secrets repo this rule primarily protects: chirag127/secrets (private)