Workflows
gitfor runs GitHub Actions–style workflows from .gitfor/workflows/*.yml.
# .gitfor/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: cloudflare
strategy:
matrix:
node: [22, 24]
steps:
- uses: actions/checkout@v4
- run: bun install && bun test
- uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.node }}
path: coverage
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: [self-hosted, linux]
steps:
- run: ./deploy.sh
env:
TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Triggers
push (branches, tags and paths filters), pull_request (types, branches, paths), release and
workflow_dispatch (with inputs).
Steps
runscripts in bash, sh, python, node or bun- Built-in
checkout,cacheandupload-artifact setup-nodeandsetup-bun(built in unless a version is requested)- JavaScript actions from public github.com repositories, or from the repository itself (
uses: ./path)
Job status is published as commit statuses named <workflow> / <job>, which branch protection can require.
CI jobs fetch only the commit they run on (depth 1). Set GITFOR_FETCH_DEPTH in a workflow's env to fetch
more history, or to 0 for a full fetch.
Third-party actions
- A tag or branch is resolved to its commit when the run is scheduled. That SHA is stored with the run, shown in the log ("Download action repository … (SHA: …)") and used for every retry.
- A full commit SHA is accepted only if a branch or tag of the named repository reaches it, so a commit that only exists in a fork can't pose as the repository. Short SHAs are refused.
- Code is fetched over git and every object is checked against its SHA. The archive is stored once per commit and the runner verifies its sha256 before extracting. Actions run only inside the job's runner, never in the Worker.
- Repository settings → Allowed actions chooses between any public action, only SHA-pinned actions, or only built-in ones.
${{ github.token }}written in a step'swith:reads theGITHUB_COM_TOKENsecret (a github.com token, for actions that call the GitHub API). An action's own${{ github.token }}defaults get an empty value, so no action receives that secret unless the workflow passes it. Fork pull request runs get no secrets.- Composite and Docker actions are not supported yet. A pin covers the action's code, not what it downloads while it runs.
Self-hosted runners
Create a registration token under Repository settings → Runners (or /orgs/<owner>/runners for owner-wide
runners), choosing the labels and the isolation. Then, on a host with Docker or Podman:
gfd runner register --url https://gitfor.dev --token gitfor_reg_...
gfd runner run
Each job runs in a fresh, non-root container with a read-only root filesystem and an egress firewall that blocks cloud metadata and private networks.
Fork pull request jobs never reach self-hosted runners unless a repository admin opts in, and then only runners
whose container isolation the admin declared on the token. See the gfd README for what is and isn't isolated.
The old runner/gitfor-runner.ts is retired.