openpreflight

A small CI provider for private repos.

One Go binary and one SQLite file, on a server you already run. Every commit gets a Check Run with full logs.

Check Run · pull request
Example Check Run: three steps passed on a private pull request in 42 seconds
private/api·#142·c7e4a91·main ← fix/hmac-skew
Passed
42s
  • install8s
    npm ci
  • test21s
    go test ./...
  • build13s
    go build ./...
View full logs
The smallest useful version

Where it fits

Full platforms, hosted control planes, and Kubernetes-oriented runners already exist for teams that need them. openpreflight is for the case where you just want a private repo checked: a binary and a SQLite file on a box you already pay for, with no Actions workflow to write and no pipeline DSL to learn.

Security model
01

One process

UI, JSON API, webhook receiver, and job runner in a single Go binary. There is no message broker to operate and no separate frontend to deploy.

02

One file of state

State lives in one SQLite file, and every secret column is AES-256-GCM encrypted at rest. Apps and bindings are rows in that database.

03

Configured in a UI

Register GitHub Apps, bind repos, and mint tokens from the web UI. You do not need a fresh block of env vars for every installation.

How a run happens

From webhook to Check Run

The webhook has ten seconds to answer, so it validates and enqueues while the worker does the slow part. Only one run is ever live for a given commit.

  1. 01

    Webhook validates and enqueues

    GitHub POSTs /webhook/{slug}. openpreflight verifies the HMAC, checks that the binding is enabled and the branch is allowed, then answers 202 within ten seconds.

  2. 02

    Worker opens a Check Run

    The worker mints an installation token and creates the Check Run. It then fetches the exact commit, detaches the checkout, and strips the remote before any step runs.

  3. 03

    Pipeline runs under a timeout

    Steps run in-process, or via docker run when runtime: is set. The Check Run carries a truncated log tail, and the full log stays on the details page.

Read ADR 005
Pipeline

A .ci.yml, if you want one

Set runtime to run steps in a container, or omit it to run them in the worker process. If the repo has no file, commands come from the binding overrides first, then from Node defaults in package.json. When there is nothing to run at all, the check reports skipped instead of failed.

Pipeline reference
runtime: node:24
install: npm ci
test: npm test
build: npm run build
timeout: 15m
Run it

One variable and a compose file

Nothing to clone: the file pulls the published image. Then open the UI, run the first-boot wizard, register your GitHub App, and enable the repos you want checks on.

curl -O https://raw.githubusercontent.com/openpreflight/openpreflight/main/compose.prod.yaml
export CI_SECRET_KEY="$(openssl rand -base64 48)"
docker compose -f compose.prod.yaml up -d

What it isn't

If any of these are requirements for you, this is the wrong tool. None of them are in v1:

  • GitHub Actions YAML
  • actions/runner
  • Creating GitHub Apps for you
  • Matrices
  • Caches
  • Artifacts

Woodpecker, Drone, a self-hosted actions/runner, and Jenkins all do more than this. The comparison says when to pick one of them instead, and what running this costs you day to day is in operations — backups, upgrades, and what a restart does to a running job.

Contributing

The test suite runs offline

go test ./... runs without credentials because Coolify and GitHub are faked. The most useful contributions are bug fixes that come with a failing test, small gaps in v1, and docs corrected to match the code.