How FFC Automation Works

Free For Charity runs its infrastructure β€” Cloudflare DNS, WHMCS billing, Microsoft 365, Zeffy donations, Google Analytics, and the GitHub sites themselves β€” through 102 auditable GitHub Actions workflows. This page is the living catalog: what each workflow does, how they are numbered and named, and the safety model that protects every run. It is generated from the workflows themselves, so it cannot drift.

102
Workflows
52
Read-only
43
Write (gated / dry-run)
7
Repo plumbing

The numbering convention β€” and why

Every workflow has a 3-digit number whose first digit is the system the workflow targets. A new admin (or an AI agent) can tell from the number alone which external API a workflow drives, and new workflows can never collide β€” each category has its own numbering space.

Naming: workflows are named NNN. Target - Description [TAG] and their files are NNN-slug.yml. The [TAG] lists every API the workflow calls, joined with + (for example [CF+M365]).

What counts as β€œan API”: the API the workflow actually calls β€” not the service the records are for (creating Microsoft 365 DNS records via the Cloudflare API is [CF]), and not plumbing (fetching credentials from Azure Key Vault, or posting a result comment to GitHub, never counts).

Multi-system workflows keep one number from the system that owns the deliverable (writes beat reads). They exist as single workflows only when they are aggregators (a report that joins several sources) or transactions (two writes that must succeed together to avoid a half-configured state).

The safety model

A live change generally has to get past several independent layers, not just one:

  1. Read vs. write credentials. Read-only workflows load reader-scope credentials and cannot mutate anything; write workflows load writer-scope credentials.
  2. Environment approval gates. Write environments (and some sensitive read environments) require a human reviewer to approve the run before it proceeds.
  3. dry_run defaults to preview. Write workflows preview what they would change; going live requires explicitly passing dry_run=false.
  4. Typed confirmation for the highest-stakes actions (for example, domain registration requires retyping the exact domain).
  5. No stored secrets. Credentials are fetched from Azure Key Vault at run time via OIDC and masked line-by-line; nothing sensitive lives in the repository.

The complete catalog

Generated from the workflow files in FreeForCharity/FFC-Cloudflare-Automation. Safety levels: Reads = no external mutation; Writes (dry-run default) = mutates only with dry_run=false; Writes (gated) = mutates when run, protected by an approval gate.

1xx

Cloudflare / DNS / Domain

23 workflows
#WorkflowAPIsSafetyRuns on
101
Domain - Status (All Sources)
101-domain-status.yml
CFM365
Reads
M365 job reads FFC-tenant status; waits on m365-prod approval
workflow_dispatch
102
Domain - Add to FFC Cloudflare + WHMCS Nameservers (Admin)
102-domain-add-ffc-cloudflare-and-whmcs.yml
CFWHMCS
Writes (gated)
β€”
workflow_dispatch
103
Domain - Enforce Standard (GitHub Apex + M365)
103-enforce-domain-standard.yml
CFM365
Writes (dry-run default)
`dry_run` (default true); exo jobs act on FFC tenant β€” `skip_m365=true` for external-tenant charities
workflow_dispatch
104
Domain - Export Inventory (All Sources)
104-domain-export-inventory.yml
CFM365WHMCSWPMUDEV
Reads
waits on m365-prod and wpmudev-prod approvals (WHMCS job ungated)
workflow_dispatch
105
DNS - Manage Record (Manual / Issue Label)
105-manage-record.yml
CF
Writes (dry-run default)
`dry_run` (default true); issue-label trig
issues, workflow_dispatch
106
DNS - Enforce Standard (DNS-only)
106-enforce-standard.yml
CF
Writes (dry-run default)
`dry_run` (default true)
workflow_dispatch
107
DNS - Audit Compliance (Report)
107-audit-compliance.yml
CF
Reads
β€”
workflow_dispatch
108
DNS - Export Cloudflare Zones (Report)
108-export-summary.yml
CF
Reads
β€”
workflow_dispatch
109
DNS - Export All Records (Full, per-record)
109-dns-export-all-records.yml
CF
Reads
β€”
workflow_dispatch
110
DNS - Create Zone (Admin)
110-cloudflare-zone-create.yml
CF
Writes (gated)
β€”
workflow_dispatch
111
DNS - Create Redirect Rule (Admin)
111-dns-create-redirect-rule.yml
CF
Writes (dry-run default)
`dry_run` (default true)
workflow_dispatch
112
DNS - Bulk Replace A-record IP (All Zones)
112-dns-bulk-replace-a-ip.yml
CF
Writes (gated)
high blast radius; serialized
workflow_dispatch
113
Domain - Registrar Search / Check / Register (Admin, DRAFT)
113-cloudflare-domain-register.yml
CF
Writes (gated)
`mode` (default `check`); register needs `mode=execute-register` + `confirm_domain`
issues, workflow_dispatch
114
Domain - Validate Cloudflare Registrar API Access (Read-only)
114-cloudflare-registrar-access-check.yml
CF
Reads
never charges; but `cloudflare-tokens-from-kv` runs with **`scope: write`** β†’ loads `wr-all-*` CF tokens, so **not auto-approvable** (#915)
workflow_dispatch
115
Domain - Transfer Readiness Preflight (Report)
115-domain-transfer-preflight.yml
WHMCS
Reads
β€”
workflow_dispatch
116
Domain - Transfer EPP/Auth Code Probe (Admin)
116-domain-transfer-epp-probe.yml
WHMCS
Writes (dry-run default)
`dry-run` vs `execute`
workflow_dispatch
117
Domain - Post-Transfer Verification (Report)
117-domain-transfer-verify.yml
CF
Reads
β€”
workflow_dispatch
118
Domain - Registrar Lock / Unlock
118-whmcs-domain-lock.yml
WHMCS
Writes (dry-run default)
`dry_run` (default true)
workflow_dispatch
119
DNS - Bulk Staging CNAME -> GitHub Pages (FFC-EX)
119-bulk-staging-cname-github-pages.yml
CF
Writes (dry-run default)
`dry_run` (default true); serialized
workflow_dispatch
120
DNS + GH Pages - Bulk Cutover staging -> Apex (FFC-EX)
120-bulk-cutover-to-github-pages.yml
CFGH
Writes (dry-run default)
`dry_run` (default true); serialized
workflow_dispatch
121
DNS + GH Pages - Fleet Cutover Preflight (FFC-EX)
121-fleet-cutover-preflight.yml
Reads
read-only DoH/HTTPS probes; go/no-go for 120
workflow_dispatch
122
Cloudflare - Zone Member Add (Domain Admin)
122-cloudflare-zone-member-add.yml
CF
Writes (dry-run default)
`dry_run` (default true); preview job always runs read-only; idempotent (existing member = no change)
workflow_dispatch
123
Domain - Inbound Transfer Preflight (Report)
123-domain-inbound-transfer-preflight.yml
Reads
read-only RDAP + offline analysis; classifies foreign-registrar domains for the eNom/WHMCS inbound path
workflow_dispatch
2xx

WHMCS

30 workflows
#WorkflowAPIsSafetyRuns on
201
WHMCS - Export Domains (Report)
201-whmcs-export-domains.yml
WHMCS
Reads
ungated read lane; artifacts are export catalogs
workflow_dispatch
202
WHMCS - Export Products (Report)
202-whmcs-export-products.yml
WHMCS
Reads
ungated read lane; artifacts are export catalogs
workflow_dispatch
203
WHMCS - Export Payment Methods (Research)
203-whmcs-export-payment-methods.yml
WHMCS
Reads
ungated read lane; artifacts are export catalogs
workflow_dispatch
204
WHMCS - Charity Onboard (client + contacts + order)
204-whmcs-charity-onboard.yml
WHMCS
Writes (dry-run default)
`dry_run` (default true); idempotent
workflow_dispatch
205
WHMCS - Open Ticket (manual)
205-whmcs-ticket-open.yml
WHMCS
Writes (gated)
one-way GitHub→WHMCS
workflow_dispatch
206
WHMCS - Issue to Ticket (one-way)
206-whmcs-issue-to-ticket.yml
WHMCS
Writes (gated)
one-way GitHub→WHMCS
issues
207
WHMCS - Ticket Respond (templated)
207-whmcs-ticket-respond.yml
WHMCS
Writes (dry-run default)
`dry_run` (default true); live reply needs admin username
workflow_dispatch
208
WHMCS - Export Tickets (Report)
208-whmcs-tickets-export.yml
WHMCS
Reads
β€”
workflow_dispatch
209
WHMCS - Tickets Triage (Open/Customer-Reply)
209-whmcs-tickets-triage.yml
WHMCS
Reads
summary masks PII
schedule, workflow_dispatch
210
WHMCS - Orders Triage (Pending/Fraud/Active)
210-whmcs-orders-triage.yml
WHMCS
Reads
summary masks PII
schedule, workflow_dispatch
211
WHMCS - Order Update (accept/cancel/fraud)
211-whmcs-order-update.yml
WHMCS
Writes (dry-run default)
`dry_run` (default true); one order at a time
workflow_dispatch
212
WHMCS - Product Add (catalog)
212-whmcs-product-add.yml
WHMCS
Writes (dry-run default)
`dry_run` (default true); idempotent
workflow_dispatch
213
WHMCS -> Zeffy Payments Import (Draft)
213-whmcs-zeffy-payments-import-draft.yml
WHMCS
Reads (builds a file)
output is a draft; serialized
workflow_dispatch
214
WHMCS - Clients Metrics (aggregate, no PII)
214-whmcs-clients-metrics.yml
WHMCS
Reads
aggregate counts only β€” no PII in artifact or summary
workflow_dispatch
215
WHMCS - Nonprofit Clients Metrics (service evidence, no PII)
215-whmcs-nonprofit-clients-metrics.yml
WHMCS
Reads
aggregate counts + product names only (no PII)
workflow_dispatch
216
WHMCS - Activity Metrics (full history, no PII)
216-whmcs-activity-metrics.yml
WHMCS
Reads
aggregate counts only (no PII)
workflow_dispatch
217
WHMCS - Client Fields Survey (aggregate, no PII)
217-whmcs-client-fields-survey.yml
WHMCS
Reads
throttled per-client loop; vocabulary-matched values only (no PII)
workflow_dispatch
218
WHMCS - Sites-List Reconciliation + Product Alignment
218-whmcs-siteslist-reconciliation.yml
WHMCS
Reads
aggregate summary; artifact carries org-domain gap lists only
workflow_dispatch
219
WHMCS - Application Detail (Client + Orders, PII-masked)
219-whmcs-application-detail.yml
WHMCS
Reads
single-client projection; personal contact fields always masked
workflow_dispatch
220
WHMCS - Served-Per-Year Metrics (span evidence, no PII)
220-whmcs-served-metrics.yml
WHMCS
Reads
aggregate counts only (no PII)
workflow_dispatch
221
WHMCS - Application Search (find by domain/org)
221-whmcs-application-search.yml
WHMCS
Reads
GetClientsProducts sweep; personal contact fields masked; **ungated** β€” `whmcs-secrets-from-kv` with `scope: read` on the `READ_ALL_FFC_AZURE_*` (ffc-admin-kv-reader) identity β†’ `read-all-ffc-whmcs-*` (#920; was βœ… `whmcs-prod` on the writer identity, held under #915)
workflow_dispatch
222
WHMCS - Cloudflare Registrar Product Alignment
222-whmcs-product-alignment.yml
WHMCSCF
Writes (dry-run default)
dry_run default true; $0 AddOrder of pid 39 onto registrar-domain clients; idempotent
workflow_dispatch
223
WHMCS - Import Cloudflare Registrar Domains as Domain Records
223-whmcs-import-cloudflare-domains.yml
WHMCSCF
Writes (dry-run default)
dry_run default true; creates/populates domain records (registrar None) from CF facts
workflow_dispatch
224
WHMCS - GitHub Pages Product Alignment
224-whmcs-github-pages-product-alignment.yml
WHMCSGH
Writes (dry-run default)
dry_run default true; $0 AddOrder of pid 40 onto FFC-EX GitHub-Pages-site clients; idempotent
workflow_dispatch
225
WHMCS - Domain Order URL Verify
225-whmcs-domain-order-url-verify.yml
WHMCS
Reads
report-only; GETs charity-supplied URLs; never accepts/cancels an order
schedule, workflow_dispatch
226
WHMCS - Application Triage (rank + accept onboarding orders)
226-whmcs-application-triage.yml
WHMCS
Writes (report default)
report + reconcile-report read-only; approve accepts ONLY listed $0 orderids; reconcile cancels ONLY listed orderids + emails those clients a re-file email (email-first, no cancel-all)
workflow_dispatch
227
cPanel - Deploy WHMCS Hooks (FTPS/lftp)
227-whmcs-hooks-deploy.yml
cPanel
Writes (verify default)
mode=verify (read-only) vs deploy; hooks input is basename-validated
workflow_dispatch
228
WHMCS - Fraud Review (FraudLabs Pro)
228-whmcs-fraud-review.yml
FRAUDLABSWHMCS
Writes (issues only)
read-only external APIs; masks PII; recommends only (never clears β€” clearing is via gated 211); scaffold inert until the FraudLabs Pro key + fraudlabspro-prod-read env are provisioned; daily weekday schedule upserts one rolling GitHub tracking issue (issues:write, ambient token) that self-closes when the Fraud queue clears
schedule, workflow_dispatch
230
WHMCS - Record Field Set (client/contact/service/domain)
230-whmcs-record-field-set.yml
WHMCS
Writes (record field)
`dry_run` (default true); one record + one field per dispatch; strict per-target allowlist of writable fields; refuses to replace a different existing value without `force`; reports `previousValue`
workflow_dispatch
231
WHMCS - Domain Order Add (Register/Transfer) (Admin)
231-whmcs-domain-order-add.yml
WHMCS
Writes (dry-run default)
`mode` (default `dry-run`) previews AddOrder and writes nothing; `execute` places a real order; pid fixed by `order_type` (41 transfer / 39 register); underlying script skips when the client already has a non-terminated service for the product unless `allow_duplicate`; `no_email` defaults true so a first live run cannot surprise a charity; price forced to 0
workflow_dispatch
3xx

Microsoft (M365 / Azure / Graph)

8 workflows
#WorkflowAPIsSafetyRuns on
301
M365 (FFC Tenant) - Domain Preflight (Read-only)
301-m365-domain-preflight.yml
M365CF
Reads
M365 job waits on m365-prod approval
workflow_dispatch
302
M365 (FFC Tenant) - List Tenant Domains
302-m365-list-domains.yml
M365
Reads
waits on m365-prod approval
workflow_dispatch
303
M365 (FFC Tenant) - Domain Status + DKIM (Toolbox)
303-m365-domain-and-dkim.yml
M365
Reads
read-oriented toolbox; waits on m365-prod approval
workflow_dispatch
304
M365 (FFC Tenant) - Enable DKIM (Exchange Online)
304-m365-dkim-enable.yml
M365CF
Writes (gated)
β€”
workflow_dispatch
305
M365 (FFC Tenant) - Add Tenant Domain (INTERNAL ONLY)
305-m365-add-tenant-domain.yml
M365
Writes (dry-run default)
`dry_run` (default true); also gated by m365-prod approval
workflow_dispatch
306
Discover - Uncaptured Comms (FFC Tenant M365, PII masked)
306-discover-uncaptured-comms.yml
M365
Reads
PII masked; dispatch-only; org mailboxes only; waits on m365-prod approval
workflow_dispatch
320
Azure - Key Vault Secret Inventory (audit)
320-azure-kv-secret-inventory.yml
MS
Reads
values never printed; placeholder/stale flags only
schedule, workflow_dispatch
321
Azure - KV Credential Liveness + Expiry Monitor
321-azure-kv-credential-liveness.yml
MSGHCF
Reads
daily two-signal credential health check: expiry/enabled for every vault secret from the attribute listing (values never read), plus a read-only liveness probe (`GET /user`, Cloudflare `GET /zones`) for the four `read-all-*` credentials that can verify themselves β€” the library refuses a `wr-all-*` probe target before anything is read, so write-scope material is expiry-monitored without ever being fetched; a probe that cannot be evaluated is reported as unverifiable, never as passing; values never printed or persisted; rolling issue upsert/close; ungated by design (a credential monitor must not wait on a human)
schedule, workflow_dispatch
4xx

Zeffy

3 workflows
#WorkflowAPIsSafetyRuns on
401
Zeffy - Campaigns Export
401-zeffy-campaigns-export.yml
ZEFFY
Reads (+ PR delivery)
PII masked; the published `docs/data/ffc-zeffy-campaigns.json` is title/url/status only (no financials); `deliver` opens a reviewable data PR via CBM_TOKEN; loads `wr-all-ffc-zeffy-api-key` (default `write`) **and** `wr-all-cbm-github-pat` β†’ **not auto-approvable** (#915; on the βœ… list 2026-07-23 β†’ 2026-07-29)
workflow_dispatch
402
Zeffy - Payments Export (PII masked)
402-zeffy-payments-export.yml
ZEFFY
Reads
PII masked; never `-IncludePii`
workflow_dispatch
403
Zeffy - Contacts Export (PII masked)
403-zeffy-contacts-export.yml
ZEFFY
Reads
PII masked; never `-IncludePii`
workflow_dispatch
5xx

Google

6 workflows
#WorkflowAPIsSafetyRuns on
501
Google - API Smoke (GA4 connectivity)
501-google-api-smoke.yml
GOOGLE
Reads
read-only; fails closed; reusable via `workflow_call`
workflow_call, workflow_dispatch
502
Google - Analytics Report (GA4 -> JSON)
502-google-analytics-report.yml
GOOGLE
Reads
delivers JSON to ffcadmin via PR (`read-all-cbm-github-pat` from KV, ungated lane #834); PII-safe aggregates. Same PR also syncs the workflow catalog and the Agentic OS status feed (`agentic-os-status.json`, generated by `scripts/generate-agentic-os-status.py`, REST-only)
schedule, workflow_dispatch
503
Google - GTM Provision (per-charity container)
503-google-gtm-provision.yml
GOOGLE
Writes (dry-run default)
dry_run default true; seeds GA4/Clarity/Meta; delegates POC access
workflow_dispatch
504
Google - GTM Container Backups (weekly export)
504-google-gtm-backup.yml
GOOGLE
Reads
read-only exports; live-version JSON artifacts (90d)
schedule, workflow_dispatch
505
Google - GA4 Property Provision (per-charity)
505-google-ga-property-provision.yml
GOOGLE
Writes (dry-run default)
dry_run default true; one property per charity; idempotent by stream defaultUri
workflow_dispatch
506
Google - Fleet Telemetry Reachability
506-google-fleet-telemetry-reachability.yml
GOOGLE
Reads
read-only; enumerates GTM containers, GA4 properties/streams and Search Console sites, cross-checks them against each site's SERVED HTML, and ranks traffic. Reports "no data" distinctly from "no traffic" so an unmeasured site never sorts as unpopular. Weekly Mon 07:23 + dispatch
schedule, workflow_dispatch
6xx

WPMUDEV

1 workflows
#WorkflowAPIsSafetyRuns on
601
WPMUDEV - Export Sites/Domains (Read-only)
601-wpmudev-export-sites.yml
WPMUDEV
Reads
waits on wpmudev-prod approval
workflow_dispatch
7xx

GitHub (Website + Repo)

29 workflows
#WorkflowAPIsSafetyRuns on
701
Website - Provision (Issue Assigned)
701-website-provision.yml
CFRepo
Writes (gated)
`repo` chained behind `dns` approval
issues
702
Domain - Deploy Static Clone to FFC-EX Repo
702-ffc-ex-clone-deploy.yml
Writes (gated)
ungated preflight (repo must exist; refuses live sites and sibling-domain repos unless `force=true`); opens a draft PR (never pushes); serialized
workflow_dispatch
703
Sites List - Generate (CSV + JSON)
703-sites-list-generate.yml
GH
Writes (data PR only)
dispatches read-only exports 201/108/601 (601 waits on its own wpmudev-prod gate); regenerates `sites-list/` CSV+JSON; opens a data PR (never pushes to `main`); weekly Mon 08:00Z + dispatch; serialized concurrency group; loads `wr-all-cbm-ffc-copilot-mcp-github-pat` β†’ **held on credential scope**, not on a taxonomy gap (#915)
schedule, workflow_dispatch
704
Website - Analytics Wire
704-website-analytics-wire.yml
GH
Writes (dry-run default)
opens a draft PR (never pushes); `dry_run` (default true); idempotent
workflow_dispatch
720
Repo - Create GitHub Repo
720-create-repo.yml
Repo
Writes (gated)
dispatch-only; creates an FFC-EX repo from a template (no dry_run β€” gate is the only stop); duplicate-repo warning text in inputs; visibility/Pages options set at creation
workflow_dispatch
721
Repo - Deploy GitHub Pages
721-deploy-pages.yml
Repo
plumbingpush, workflow_dispatch
722
Repo - CI Validate and Test
722-ci.yml
Repo
plumbingmerge_group, pull_request, push
723
Repo - CodeQL Security Analysis
723-codeql-analysis.yml
Repo
plumbingmerge_group, pull_request, push, schedule, workflow_dispatch
724
Repo - Initialize Labels
724-initialize-labels.yml
Repo
plumbingworkflow_dispatch
725
Repo - Sync Labels
725-sync-labels.yml
Repo
plumbingpush, workflow_dispatch
726
Repo - Rulesets + Settings Drift Audit
726-repo-rulesets-drift-audit.yml
Org
Reads
report only; `read-all-cbm-ffc-copilot-mcp-github-pat` from KV over OIDC; ungated lane (#834) so the daily audit is never cancelled waiting at a gate
schedule, workflow_dispatch
727
Repo - Phantom Revert Guard
727-phantom-revert-guard.yml
Repo
plumbingmerge_group, pull_request, workflow_dispatch
728
Repo - AI Agent Hooks Validate
728-ai-agent-hooks-validate.yml
Repo
plumbingpull_request, push
729
Repo - Add Collaborator
729-repo-add-collaborator.yml
Repo
Writes (**live default**)
⚠️ `dry_run` defaults to **false**
workflow_dispatch
730
Repo - Audit Environment Approval Gates
730-repo-audit-environment-gates.yml
Repo
Reads
report only (environment reviewer config)
push, workflow_dispatch
731
Repo - Actions Run Metrics (30d per-workflow stats)
731-actions-run-metrics.yml
GH
Reads
GITHUB_TOKEN read-only; JSON artifact
schedule, workflow_dispatch
733
Repo - Credential Rotation Reminders (quarterly)
733-credential-rotation-reminders.yml
GH
Writes (issues only)
quarterly reminder issues; rotations stay human/gated
schedule, workflow_dispatch
734
Repo - Stale Waiting-Run Janitor
734-stale-waiting-run-janitor.yml
Repo
Writes (cancels runs)
cancels runs left waiting >N days at a gate; never approves; dispatch dry-run supported
schedule, workflow_dispatch
735
Repo - Dependabot Affected Repos
735-repo-dependabot-affected-repos.yml
Org
Reads
weekly org inventory (feeds smoke-protected waves); PR-only + auto-merge; `read-all-cbm-github-pat` from KV over OIDC on the ungated lane (#834)
schedule, workflow_dispatch
736
Repo - Archive / Application Denied (Admin)
736-repo-archive.yml
Repo
Writes (dry-run default)
ungated preflight (live archive requires a matching successful dry-run within 48h; fails fast on missing/already-archived; warns on recent push/Pages/open-issue references); archive-only (reversible, never deletes); `dry_run` default true; typed `confirm_repo`; org-locked + denylist
workflow_dispatch
737
Repo - Claim Sync
737-claim-sync.yml
Repo
Writes (issues/labels only)
syncs `claimed` label from linked PRs (pull_request event, GITHUB_TOKEN) + daily sweep reconciling this repo's claims against every open PR in the org β€” one `search/issues` read, writes only this repo's issues (ambient GITHUB_TOKEN β€” CBM_TOKEN is gated-env-only and empty on schedule); releases when no open PR in any repo still references the issue, or after 48h idle for a hand-labeled claim; no external API, ungated; sweep `dry_run` via dispatch
pull_request, schedule, workflow_dispatch
738
Repo - Fleet Smoke Engine Drift Audit
738-fleet-smoke-engine-drift-audit.yml
Org
Reads
weekly SHA-256 byte-identity audit of `post-deploy-smoke.yml` across the fleet vs canonical (FFC-IN-FFC_Single_Page_Template@main); rolling issue upsert/close on divergence; GITHUB_TOKEN (public reads + own-repo issue), no external API, ungated
schedule, workflow_dispatch
739
Repo - Process Health Metrics Report
739-process-health-metrics.yml
GH
Reads
weekly "monitor the monitors" REST sweep (backlog + data-pipeline signals) posted as a new comment on #719 with week-over-week trends (baseline read from the prior comment's hidden data block); JSON artifact; GITHUB_TOKEN (own-repo issue/Actions reads + one comment), no external API, ungated
schedule, workflow_dispatch
740
Repo - Scheduled Workflow Failure Alert (rolling issue)
740-scheduled-workflow-failure-alert.yml
GH
Writes (issues only)
**polls** every scheduled hub workflow twice hourly (`schedule` + `workflow_dispatch`; the `workflow_run` event has never fired in this repo β€” #843) and upserts one rolling issue per watched workflow (marker keyed by workflow name, so only that workflow's own green run closes it); absorbs the retired 732 Google lane (502/504); reports `cancelled`/`timed_out` as well as `failure`, latest completed default-branch run only; does **not** alert on a declined/expired approval gate (no job `failure` + β‰₯1 job `cancelled` β‡’ logged via `core.notice`, not an alert) β€” an unreadable job list still alerts, and a watched name matching no workflow fails the run loudly; ambient GITHUB_TOKEN, no external API, ungated by design (must not be blocked by the gate it watches)
schedule, workflow_dispatch
741
Repo - Fleet Security Audit Coverage
741-fleet-security-audit-coverage.yml
Org
Reads
weekly coverage audit of dependency-vulnerability detection across the FFC-EX fleet (a repo counts as covered only with BOTH `security-audit.yml` and an `audit:high` script) PLUS a lockfile-resolution check β€” real `npm ci --dry-run` per Node repo, since a lockfile that exists but does not resolve makes the nightly audit scan nothing (#889, ledger L06); rolling issue upsert/close on any gap; reports only β€” never bumps a dependency or writes to a fleet repo; GITHUB_TOKEN (public reads + own-repo issue), npm registry read-only, ungated
schedule, workflow_dispatch
742
Repo - Fleet Security Audit Backfill
742-fleet-security-audit-backfill.yml
Org
Writes (dry-run default)
closes the gap 741 measures: opens one PR per uncovered FFC-EX repo adding BOTH halves of the audit pair (`security-audit.yml` + the `audit:high` script) in a single commit, never a `partial`; cron staggered deterministically by repo name across 06:00–06:59, skipping the crowded `:17`; `dry_run` (default true) runs the ungated `plan` job only, so a preview needs no approval; never pushes a target's default branch and never bumps a dependency (#822 owns remediation); repos with no `package-lock.json` are reported, not wired
workflow_dispatch
743
Website - Fleet Security Header Audit
743-fleet-security-header-audit.yml
Reads
weekly audit of the security headers each FFC-delivered site ACTUALLY SERVES (HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, CSP), measured by fetching the live response and never by looking for a file in a repo β€” `public/_headers` is inert on this stack, so a source-file check reports coverage that does not exist (#884); scope is every domain in an FFC Cloudflare zone (derived column, not the curated host category); report-only CSP does not count as a CSP and a `<meta>` tag satisfies nothing; rolling issue upsert/close on any gap; plain HTTPS GETs to public sites, no credentials, no external API, GITHUB_TOKEN for the issue only, ungated
schedule, workflow_dispatch
744
Repo - Public Feed Freshness
744-repo-public-feed-freshness.yml
GH
Reads
daily OUTCOME check on the published Agentic OS status feed in `FFC-IN-ffcadmin.org` (`agentic-os-status.json`, both the `public/data/` and `src/data/` copies), asserting how old the timestamp the public page actually serves is β€” the three existing mechanisms are all PROCESS checks (#921 watches whether 502 succeeds, #908 watches PRs stuck behind `main`, #771 watches drift between the two copies) and every one of them was green while the page sat three days stale (#977); stale after 36h, so one missed daily tick does not report; a path that is missing, unreadable, or carries an absent/empty/non-ISO/future `generated_at` is a finding and never a pass, and a registered path the run produced no observation for is reported rather than skipped; rolling issue upsert/close; **deliberately holds no Key Vault credential** β€” ambient GITHUB_TOKEN only, since a monitor depending on the credential whose death it reveals goes dark when it is needed; ungated
schedule, workflow_dispatch
745
Repo - Agentic OS Board Audit
745-agentic-os-board-audit.yml
GH
Reads
daily audit of the public Agentic OS board (org project #9) against the real backlog, running `scripts/audit-agentic-os-board.py` β€” which #968 shipped and nothing invoked, making it assurance only when a human remembered (#969); the board has NO auto-add so every card and Status is placed by hand and the audit is the compensating control, which on a manual process has to be automatic or it inherits the same failure mode; reports the three sets (missing from board / no Status / closed-or-merged but not `Done`) to the Conductor Log and is SILENT when clean, following 734; a run that could not read one of its two sides is reported as INCOMPLETE and never as clean, since the script exits 1 for both findings and enumeration failure and the exit code alone cannot tell them apart; read-only against GitHub (adds no card, sets no Status, closes nothing), Key Vault PAT on the reader identity for the org-level ProjectsV2 read the ambient token cannot do, ambient GITHUB_TOKEN for the issue comment, ungated
schedule, workflow_dispatch
8xx

Candid (GuideStar)

2 workflows
#WorkflowAPIsSafetyRuns on
801
Candid - Charity Check (EIN)
801-candid-charity-check.yml
CANDID
Reads
read-only IRS-status lookup; public org data only
workflow_dispatch
802
Candid - Essentials Search
802-candid-essentials-search.yml
CANDID
Reads
read-only profile search; public org data only
workflow_dispatch

For AI agents & new admins

A machine-readable version of this catalog is published at https://ffcadmin.org/data/workflow-catalog.json (stable URL; source of truth: docs/workflow-catalog.json in the automation repository, regenerated on every workflow change β€” CI fails if it drifts). Schema: workflows[] with number, title, apis, file, triggers, environments, safetyLevel, approvalEnv, guard, category. To pick a workflow: match the first digit to the system you need to act on, prefer Reads before Writes, and always run write workflows with the default dry_run preview first.

Related: Technology Stack Β· Sites List