ci(secrets->kms): molecule-core fetches CF/staging secrets from Infisical (wave B aliases) #3289
Reference in New Issue
Block a user
Delete Branch "ci/secrets-wave-b-aliases"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Wave-B alias migration: Cloudflare / staging secrets -> Infisical SSOT
Rewires the three Cloudflare-consuming Gitea workflows from direct
Gitea-Actions-secret use to the Infisical KMS-fetch pattern (#971 / #3274):
a
Fetch <CRED> from Infisical SSOTstep is added in the same job(
INFISICAL_CIuniversal-auth login ->GET /api/v3/secrets/raw/<KEY>with
environment+secretPath-> null-safe extractor ->[ -z ]fail-closed ->
::add-mask::-> export to$GITHUB_ENVunder the env-varname the workflow/script already expects), and each
secrets.<NAME>is replaced with
env.<NAME>. Nothing downstream changes.Migrated aliases
secrets.*sweep-cf-orphans.ymlCF_API_TOKENCF_API_TOKEN || CLOUDFLARE_API_TOKENprod :: /shared/cloudflare-tunnel-admin :: CLOUDFLARE_API_TOKEN(zone:dns:edit)sweep-cf-orphans.ymlCF_ZONE_IDCF_ZONE_ID || CLOUDFLARE_ZONE_IDprod :: /shared/cloudflare-tunnel-admin :: CLOUDFLARE_ZONE_ID(apex zone)sweep-cf-tunnels.ymlCF_API_TOKENCF_API_TOKEN || CLOUDFLARE_API_TOKENprod :: /shared/cloudflare-admin :: CLOUDFLARE_API_TOKEN_ADMIN(account:cloudflare_tunnel:edit)sweep-cf-tunnels.ymlCF_ACCOUNT_IDCF_ACCOUNT_ID || CLOUDFLARE_ACCOUNT_IDprod :: /shared/cloudflare-admin :: CLOUDFLARE_ACCOUNT_IDe2e-staging-saas.ymlCF_API_TOKENCF_STAGING_DNS_API_TOKENstaging :: /shared/cloudflare-tunnel-admin :: CLOUDFLARE_API_TOKENe2e-staging-saas.ymlCF_ZONE_IDCF_STAGING_ZONE_IDstaging :: /shared/cloudflare-tunnel-admin :: CLOUDFLARE_ZONE_IDScope correctness
Each token's scope matches the CF API surface the consuming script hits:
sweep-cf-orphans.sh->/zones/<id>/dns_records-> zone-scoped token + zone id.sweep-cf-tunnels.sh->/accounts/<id>/cfd_tunnel-> account-scoped admin token + account id.staging.moleculesai.apprecords live in the singlemoleculesai.appapex zone, so the staging zone id is the same value as the prod zone id
(confirmed by SHA-256 hash, values never printed). The staging zone-scoped
token resolves identically to the prod one for that path; pointing the
staging fetch at
environment=stagingkeeps the SSOT lookup correct ifthe staging value ever diverges.
Trusted-ref gating (PUBLIC repo)
sweep-cf-*) only ever run onschedule/workflow_dispatch, so each fetch is gated to those events — anuntrusted-fork PR can never reach the
INFISICAL_CI_*machine identity.e2e-staging-saasprune fetch mirrors that file's existingFetch platform model+runtime from KMS SSOTtrusted-ref gate(protected-branch push / dispatch / schedule / same-repo PR; fork PR
skips). On a fork PR the fetch exits 0,
CF_API_TOKEN/CF_ZONE_IDstayempty, and the pre-existing dry-run-preview soft-skip short-circuits the
prune — PR behavior is unchanged.
validate-before-delete
The
CF_API_TOKEN,CLOUDFLARE_API_TOKEN,CF_ZONE_ID,CLOUDFLARE_ZONE_ID,CF_ACCOUNT_ID,CLOUDFLARE_ACCOUNT_ID,CF_STAGING_DNS_API_TOKEN, andCF_STAGING_ZONE_IDGitea Actionssecrets are intentionally LEFT IN PLACE. Delete them only after a green
scheduled
sweep-cf-*run and a green push/dispatche2e-staging-saasrun confirm the KMS path resolves end-to-end.
Validation done in this PR
yaml.safe_load).(env, path, key)lookups verified non-empty via thesame
/api/v3/secrets/rawendpoint the steps use (values never printed).Fetch CP_ADMIN_API_TOKEN from Infisical KMS/Fetch platform model+runtime from KMS SSOTstepsin these same files.
No merge, no self-approve — gate-disciplined per team merge bar.
🤖 Generated with Claude Code
REQUEST_CHANGES on head
ee65dfeeab.Blocking correctness/security issue: the Cloudflare scope split is wired opposite the requested contract. The review requirement says sweep-cf-tunnels must fetch/use CLOUDFLARE_API_TOKEN for the tunnel-admin scope, and sweep-cf-orphans must fetch/use CLOUDFLARE_API_TOKEN_ADMIN for the dns:edit/orphan cleanup scope. Current head does the reverse: .gitea/workflows/sweep-cf-tunnels.yml reads CLOUDFLARE_API_TOKEN_ADMIN from /shared/cloudflare-admin, while .gitea/workflows/sweep-cf-orphans.yml reads CLOUDFLARE_API_TOKEN from /shared/cloudflare-tunnel-admin. That risks running each workflow with the wrong Cloudflare privilege boundary.
Non-blocking observations from this pass: the added Infisical accessToken/secretValue extractors use string-only isinstance shapes, I did not find added raw/default-empty/or-empty fail-open extractor forms, masks are before $GITHUB_ENV, and the old Gitea aliases/fallbacks appear to be left in place. CI was not green at review time (CI/all-required pending plus review/SOP gates red), but the scope reversal is enough to block before CI settles.
REQUEST_CHANGES — reviewed head
ee65dfeeab.Scope: Wave-B migration of Cloudflare/staging aliases to Infisical across
e2e-staging-saas.yml,sweep-cf-orphans.yml, andsweep-cf-tunnels.yml.Good: the new Infisical accessToken/secretValue extractors in the changed workflows are all string-only
isinstance(v,str)forms. I found zero prevention-SSOT fail-open shapes in the changed files: no rawprint(json.load(...)["accessToken"]), noprint(... or ""), no.get("secretValue", "")default-empty form, and no unguardedprint(v|secretValue|token). New values are masked before$GITHUB_ENV, and the old Gitea aliases/fallbacks are not deleted in this PR.Blocker: the Cloudflare scope split is wired opposite the requested alias mapping. The requested split was
sweep-cf-tunnels -> CLOUDFLARE_API_TOKENfor the tunnel-admin token andsweep-cf-orphans -> CLOUDFLARE_API_TOKEN_ADMINfor the DNS-edit token. This head wiressweep-cf-orphanstoCLOUDFLARE_API_TOKENat/shared/cloudflare-tunnel-admin, whilesweep-cf-tunnelsreadsCLOUDFLARE_API_TOKEN_ADMINat/shared/cloudflare-admin. Please align the secret names/paths/comments with the agreed least-privilege split so the tunnel sweep cannot accidentally consume the broader/admin alias and the orphan DNS sweep cannot accidentally consume the tunnel alias.CI is also not green on the reviewed head: full-paginated statuses show
CI / all-requiredpending andE2E Staging SaaS / Prune stale e2e DNS recordsfailing. So this is not approvable yet even aside from the Cloudflare alias mapping issue.The wave-B aliases migration wired each CF sweep to the WRONG Infisical token+path, so the account-scoped tunnel token and the zone-scoped DNS token were swapped: - sweep-cf-tunnels (hits /accounts/<id>/cfd_tunnel) was reading the zone:dns:edit token (CLOUDFLARE_API_TOKEN_ADMIN @ /shared/cloudflare-admin). - sweep-cf-orphans (hits /zones/<id>/dns_records) was reading the account:cloudflare_tunnel:edit token (CLOUDFLARE_API_TOKEN @ /shared/cloudflare-tunnel-admin) — which lacks dns:edit, failing the "Prune stale e2e DNS records" job. Swap the fetch <KEY> + secretPath in each workflow's "Fetch ... from Infisical SSOT" step so each sweep reads its correctly-scoped token: - tunnels -> CLOUDFLARE_API_TOKEN @ /shared/cloudflare-tunnel-admin - orphans -> CLOUDFLARE_API_TOKEN_ADMIN @ /shared/cloudflare-admin CF_ACCOUNT_ID / CF_ZONE_ID move to the matching path alongside their token. No other change — extractor, ::add-mask::, fail-closed [ -z ], and validate-before-delete are untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>APPROVED on head
0a839673f8.5-axis re-review: correctness issue from my prior RC is resolved. The new head swaps only the two Cloudflare sweep fetch key/path pairs versus
ee65dfee(+8/-8 across.gitea/workflows/sweep-cf-orphans.ymland.gitea/workflows/sweep-cf-tunnels.yml):sweep-cf-tunnelsnow readsCLOUDFLARE_API_TOKENfrom/shared/cloudflare-tunnel-adminplus matching account id, andsweep-cf-orphansnow readsCLOUDFLARE_API_TOKEN_ADMINfrom/shared/cloudflare-adminplus matching zone id. Extractor shape, fail-closed[ -z ]guards, masks-before-export, trusted event gates, and validate-before-delete comments are otherwise unchanged.CI/status review: full-paginated statuses show
CI / all-required (pull_request)success on0a839673. TheE2E Staging SaaS / Prune stale e2e DNS recordsfailure is non-required and reproducible on the old RC headee65dfeeas well, so it is not introduced by this fix and does not block all-required.Security/robustness: public-repo secret fetches remain event-gated to trusted schedule/workflow_dispatch for the sweep jobs; old Gitea secret aliases/fallbacks are not deleted in this PR. Scoped diff; no unrelated edits found.
REQUEST_CHANGES on head
0a839673f8.The runtime wiring is now corrected: sweep-cf-tunnels reads
CLOUDFLARE_API_TOKENfrom/shared/cloudflare-tunnel-admin, and sweep-cf-orphans readsCLOUDFLARE_API_TOKEN_ADMINfrom/shared/cloudflare-admin. The fresh-head commit is scoped to the two sweep workflow files, and the extractor / ::add-mask:: / [ -z ] fail-closed shape is unchanged.CI / all-requiredis green; current red rows are review/SOP gates, not required CI.Blocking readability/security issue: the adjacent comments in those same fetch blocks still describe the old/reversed mapping. In
.gitea/workflows/sweep-cf-tunnels.yml, the comments still say the values come from/shared/cloudflare-adminand describeCLOUDFLARE_API_TOKEN_ADMIN, while the code now readsCLOUDFLARE_API_TOKENfrom/shared/cloudflare-tunnel-admin. In.gitea/workflows/sweep-cf-orphans.yml, the comments still say/shared/cloudflare-tunnel-admin/CLOUDFLARE_API_TOKEN, while the code now readsCLOUDFLARE_API_TOKEN_ADMINfrom/shared/cloudflare-admin. This PR is specifically a Cloudflare privilege-boundary fix, so leaving the in-file scope map reversed is likely to cause the next operator or reviewer to re-break it. Please update the comments to match the corrected key/path/scope mapping.On the reported red-herring job: I do not see
Prune stale e2e DNS recordsas a current red status on this head;CI / all-requiredis green. The full PR still contains changes toe2e-staging-saas.ymlfrom the original migration, while the fresh fix commit only touched the two sweep files.New commits pushed, approval review dismissed automatically according to repository settings
APPROVED on head
fc15cffe4b.Re-confirmed against my prior approved head
0a839673: the new commit is comment-only, 8 inserted / 8 deleted#lines across.gitea/workflows/sweep-cf-orphans.ymland.gitea/workflows/sweep-cf-tunnels.yml; no fetch key, secretPath, extractor, mask, guard, or executable workflow code changed.The comments now match the corrected scope mapping:
sweep-cf-tunnelsdocumentsCLOUDFLARE_API_TOKENfrom/shared/cloudflare-tunnel-adminfor account tunnel edit, andsweep-cf-orphansdocumentsCLOUDFLARE_API_TOKEN_ADMINfrom/shared/cloudflare-adminfor zone DNS edit. Full-paginated statuses showCI / all-required (pull_request)success onfc15cffe.APPROVED on head
fc15cffe4b.Verified the RC 14395 blocker is resolved. The follow-up commit is comment-only in the two CF sweep workflows, and the comments now match the already-verified corrected fetch code:
The
fc15cffediff changes only comment/description lines relative to 0a839673; no fetch key, secretPath, extractor, mask, guard, trigger gate, or validate-before-delete logic changed. CI / all-required is green; Prune-DNS/review-gate noise is not blocking.