Without
++ Actions-only private CI +
+
+ Workflow YAML, hosted or self-hosted actions/runner,
+ matrices and caches if you need them. Fine when you want that
+ orchestration layer.
+
diff --git a/README.md b/README.md index 6179aba..baa75f1 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ # openpreflight website The marketing site, published at **https://openpreflight.xyz**. Astro + -Tailwind v4, static output, one page plus a branded 404. +Tailwind v4, static output. Positioning pages plus a branded 404; how-to lives +on [docs.openpreflight.xyz](https://docs.openpreflight.xyz). Reference documentation lives on a separate site, [openpreflight/docs](https://github.com/openpreflight/docs), at @@ -32,9 +33,12 @@ npm run dev ## Structure -- `src/pages/index.astro`: the marketing page +- `src/pages/index.astro`: the marketing homepage +- `src/pages/`: Product, Why, Self-hosted, Security, and the other hub routes - `src/pages/404.astro`: branded not-found -- `src/components/`: Header, CheckRunPanel, RunFlow +- `src/layouts/MarketingPage.astro`: shared header/footer chrome for inner pages +- `src/lib/site.ts`: nav, footer groups, CTAs +- `src/components/`: Header, CheckRunPanel, RunFlow, Rivelle blocks - `src/layouts/Layout.astro`: head, meta, OG tags, header/footer chrome - `src/styles/global.css`: product-green palette, JetBrains Mono, light/dark via `prefers-color-scheme` diff --git a/public/index.md b/public/index.md index f13834c..36922ba 100644 --- a/public/index.md +++ b/public/index.md @@ -38,6 +38,7 @@ See https://openpreflight.xyz/#demo ## Start here +- [Product](https://openpreflight.xyz/product/) - [Quickstart](https://docs.openpreflight.xyz/start/quickstart/) - [Configuration](https://docs.openpreflight.xyz/start/configuration/) - [Register a GitHub App](https://docs.openpreflight.xyz/setup/github-app/) diff --git a/public/llms.txt b/public/llms.txt index ea91bc4..b7304f7 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -11,6 +11,16 @@ License: Apache-2.0 ## Product +- [Product](https://openpreflight.xyz/product/): How a run happens, configuration, non-goals +- [Why](https://openpreflight.xyz/why/): Problem, shape, ceiling +- [Self-hosted](https://openpreflight.xyz/self-hosted/): You run the worker +- [Security](https://openpreflight.xyz/security/): Claims from the security model only +- [Open source](https://openpreflight.xyz/open-source/): Repos, license, contributing +- [Pipeline](https://openpreflight.xyz/pipeline/): `.ci.yml`, not a check registry +- [Integrations](https://openpreflight.xyz/integrations/): GitHub App, Coolify, Docker, process +- [vs GitHub Actions](https://openpreflight.xyz/compare/github-actions/): Complement, do not replace +- [Concepts](https://openpreflight.xyz/concepts/): Check Run, Binding, Job +- [Use cases](https://openpreflight.xyz/use-cases/): Private repos, self-hosted teams, OSS - [Product overview (Markdown)](https://openpreflight.xyz/index.md): Positioning, what it does, what is out of scope for v1 - [Marketing home](https://openpreflight.xyz/): Human-facing landing page diff --git a/scripts/check-links.mjs b/scripts/check-links.mjs index 4783705..bbd009c 100644 --- a/scripts/check-links.mjs +++ b/scripts/check-links.mjs @@ -14,6 +14,20 @@ const dist = join(root, 'dist'); const required = [ 'index.html', '404.html', + 'product/index.html', + 'why/index.html', + 'self-hosted/index.html', + 'security/index.html', + 'open-source/index.html', + 'use-cases/index.html', + 'use-cases/private-repos/index.html', + 'use-cases/self-hosted-teams/index.html', + 'use-cases/open-source/index.html', + 'concepts/index.html', + 'integrations/index.html', + 'integrations/github-app/index.html', + 'pipeline/index.html', + 'compare/github-actions/index.html', 'favicon.svg', 'favicon.ico', 'favicon-32.png', @@ -99,10 +113,12 @@ for (const file of walkHtml(dist)) { if (!href.startsWith('/')) continue; if (href.startsWith('//')) continue; + const pathOnly = href.split('#')[0] || '/'; if ( - href.startsWith('/_') || - href === '/' || - href.endsWith('.svg') || + pathOnly.startsWith('/_') || + pathOnly === '/' || + pathOnly === '' || + pathOnly.endsWith('.svg') || href.endsWith('.png') || href.endsWith('.ico') || href.endsWith('.xml') || @@ -115,11 +131,11 @@ for (const file of walkHtml(dist)) { continue; } - const normalized = href.replace(/\/$/, '') || ''; + const normalized = pathOnly.replace(/\/$/, '') || ''; const candidates = [ - join(dist, href.replace(/^\//, ''), 'index.html'), + join(dist, pathOnly.replace(/^\//, ''), 'index.html'), join(dist, `${normalized.replace(/^\//, '')}.html`), - join(dist, href.replace(/^\//, '')), + join(dist, pathOnly.replace(/^\//, '')), ]; if (!candidates.some((c) => existsSync(c))) { broken.push(`${rel} → ${href}`); diff --git a/src/components/blocks/footer-01.tsx b/src/components/blocks/footer-01.tsx index 99365cf..697fb09 100644 --- a/src/components/blocks/footer-01.tsx +++ b/src/components/blocks/footer-01.tsx @@ -58,7 +58,7 @@ function Footer01({
+ Same private GitHub repo. Different place the Check Run comes from. +
+Without
+
+ Workflow YAML, hosted or self-hosted actions/runner,
+ matrices and caches if you need them. Fine when you want that
+ orchestration layer.
+
With
+
+ One binary, SQLite, a GitHub App you register, and{" "}
+ .ci.yml. Logs stay
+ on your disk. Not a unification of GitLab and Jenkins.
+
- If any of these are requirements for you, this is the wrong + This is not another CI provider and not a replacement for GitHub + Actions. Actions orchestrates. openpreflight is a small Check Runs + runner you host. They can coexist. See{" "} + + openpreflight and GitHub Actions + + . If any of these are requirements for you, this is the wrong tool. None of them are in v1:
404
-- That URL is not on this site. The links below cover everything that is. -
- +404
+That URL is not on this site. The links below cover everything that is.
+ - +Compare
+
+ GitHub Actions is orchestration: matrices, caches, artifacts, marketplace
+ actions, hosted or self-hosted actions/runner. openpreflight is
+ a Check Runs worker you host. Use them together when that matches the setup.
+ Do not treat this product as a replacement for Actions YAML.
+
.ci.ymlactions/runner+ Those sit on + Not in v1. + Neighbors (Woodpecker, Drone, Jenkins) are compared in the + docs, not as fake “we replace + Actions” copy. +
+ +Concepts
++ A glossary that matches the docs. Each entry is the thing in v1, not a + metaphor for a future platform. +
+ ++ GitHub’s status object on a commit. openpreflight creates one per job and + writes conclusion plus a log tail. It is the product’s hero artifact. + ADR 005. +
+ ++ A row that says this App, this repo, these branches, these optional command + overrides. No enabled binding, no job. + Bindings. +
+ +.ci.yml)
+ Repo file with install, test, build,
+ optional runtime and timeout. Commands you write,
+ not a marketplace of named checks.
+ Pipeline,
+ docs.
+
+ An App you register. Webhooks, installation tokens, Check Runs. Not OAuth, + not Coolify’s GitHub connector. + Setup, + ADR 003. +
+ +
+ One queued or running attempt for an (app, repo, sha). Logs
+ are files under DATA_DIR.
+ Logs.
+
+ Process (default) or docker run when runtime: is
+ set or the job is a fork PR.
+ ADR 004.
+
+ Per-binding opt-in so GET /runs/{id} works without a
+ session. Treat the URL as a secret.
+
Integrations / GitHub App
++ openpreflight does not create the App for you. You register it, paste the + PEM and webhook secret into the UI, enable a binding, and push. +
+https://your-host/webhook/{slug}.+ The full checklist, permission table, and event list: + Register a GitHub App. + Bindings: + enable repos. +
+Integrations
++ This is not a grid of CI vendors. GitLab CI, Jenkins, CircleCI, Buildkite, + and Azure DevOps are not adapters here. +
+ +Required. Webhooks, installation tokens, Check Runs.
+ + +Optional API: inventory, repo picker, install-worker. Not a job runner.
+ + +runtime: and fork jobs via docker run.
Default when runtime is empty. Steps run in the worker.
Open source
++ The worker holds GitHub App PEMs. Open source is how you can read what it + does with them. License is Apache-2.0 on the binary; the two sites are MIT. +
+ ++ Issues and pull requests on the code repo. Development loop: + development. + Website and docs have their own CONTRIBUTING files. There is no foundation, + board, or RFC process to join. +
+ ++ Changelog lives in the code repo. GitHub Releases (when tagged) publish the + image and binaries. Until a tag exists, run from Compose build or a commit + you trust. +
+ ++ SECURITY.md + — not the public issue tracker for vulnerabilities. +
+ +Pipeline
+
+ There is no check registry. Steps are shell commands in
+ .ci.yml — illustrations like go test or
+ npm test are commands you author, not first-class products.
+
{`runtime: node:24
+install: npm ci
+test: npm test
+build: npm run build
+timeout: 15m`}
+
+ Sample in the code repo:
+ examples/.ci.yml.
+ Default filename is .ci.yml, not openpreflight.yaml.
+
Highest first:
+package.json (lockfile install, then
+ test / build only if those scripts exist)
+ A failing step stops the run; later steps are reported skipped.
+ +
+ Omit runtime to run in-process. A non-empty image uses
+ docker run --rm. If the engine is unreachable, the job fails
+ instead of falling back. Fork jobs always use Docker.
+
+ The contract, not this page, is source of truth: + pipelines. +
+ +Product
++ One Go binary and one SQLite file. You register a GitHub App, bind repos in + the UI, and every commit gets a Check Run with logs that live on your server. +
+ ++ You want CI on private GitHub repositories without GitHub Actions runners + and without a pipeline DSL. You already have a machine. The worker is the + product, not a mode. +
++ Full platforms, hosted control planes, and Kubernetes-oriented runners + already fill a different slot. This one does not replace them. See + why it is this shape and + the FAQ. +
+ +v1 does not include GitHub Actions YAML, actions/runner, matrices, caches, artifacts, or creating GitHub Apps for you. Those stay on Not in v1.
The same loop as the docs, in marketing nouns:
+{`GitHub ──POST /webhook/{slug}──► api ──enqueue──► queue.Runner
+ │ │
+Browser / CLI ──session/Bearer──► api │ ├── GitHub App (Check Run)
+ │ ├── workspace (exact SHA)
+ └── SQLite ├── pipeline (.ci.yml)
+ └── executor (process or docker run)`}
+ + Webhook → queue → checkout of the immutable SHA → install/test/build → one + Check Run. One live run per commit. Details: + architecture + and + ADR 005. +
+ +
+ The same .ci.yml and the same worker run on your host.
+ That is not “any CI vendor.” There are no GitLab, Jenkins, or CircleCI
+ adapters.
+
+ Bindings and Apps are rows in SQLite, edited in the web UI. Optional
+ .ci.yml in the repo supplies commands; binding overrides and
+ package.json scripts fill gaps. Resolution order lives in
+ pipelines. Marketing summary:
+ /pipeline.
+
+ GitHub shows the Check Run. The details URL is GET /runs/{id}
+ on your instance — session by default, or a shareable log if that binding
+ opted in.
+
+ Claims match the docs only: + security model. + Marketing page: /security. +
+ + +Security
++ This page restates the published security model. It does not add claims. + Source: + security model + and + SECURITY.md. +
+ +
+ Steps run as a local process, or as docker run --rm when
+ runtime: is set. Job containers drop capabilities, set
+ no-new-privileges, and do not get the engine socket. Image
+ names are allow-listed.
+
+ GitHub POSTs webhooks to your public HTTPS URL. The worker clones with an
+ installation token via GIT_CONFIG_* Basic auth — never in the
+ remote URL — then strips the remote before pipeline steps run.
+
+ App PEM, webhook secret, and Coolify token columns are AES-256-GCM.
+ GET responses return a redacted marker. The key is CI_SECRET_KEY.
+ Rotation uses CI_SECRET_KEY_OLD on boot.
+
+ Job env is built from scratch: no CI_SECRET_KEY, no PEMs, no
+ webhook secrets, no Coolify tokens, no installation token.
+
+ Fork PRs are skipped by default. Opt-in requires a reachable Docker engine
+ and default_runtime. Fork jobs always run in Docker.
+
+ Session cookies are HttpOnly, Secure behind HTTPS. Browser writes need a + CSRF token. Bearer callers skip CSRF. See + ADR 002. +
+ +
+ A binding can opt into unauthenticated GET /runs/{id}.
+ Job ids are random UUIDs; treat the link as a secret.
+
+ Report vulnerabilities as described in + SECURITY.md + (private reporting on the GitHub repo, and + security@openpreflight.xyz). +
+ +Self-hosted
++ There is no hosted openpreflight control plane. Compose or the binary on + your server is the whole deployment. +
+ +{`Your infra GitHub
+───────── ──────
+compose / binary
+ UI + API + webhook + runner ◄── HTTPS webhooks
+ SQLite in DATA_DIR ──► Check Runs
+ logs on disk ──► details_url (your host)`}
+
+ CI_SECRET_KEY — the only required env var. Keep it forever.DATA_DIR. That volume must persist.+ Walkthrough: + quickstart + and + deployment. +
+ +
+ Process executor is the default. runtime: and fork PRs need a
+ Docker engine (CI_DOCKER_HOST or a mounted socket). Coolify is
+ optional inventory, a repo picker, and an install-worker API — not required
+ to run CI, and not a job runner.
+
+ There is no first-class Kubernetes operator and no air-gap product. If you + put the binary on an isolated network, that is ordinary self-hosting, not a + documented mode. +
+ + +Use cases
++ Three honest stories. Not a policy engine, and not one YAML across GitLab + and Jenkins. +
+ +Check Runs on private code without Actions runners.
+ + +Keep the worker, the database, and the logs on your box.
+ + +Public demo PRs and the same log pages you get behind auth.
+ +Use cases / Open source
++ openpreflight/demo + is a small Node utility with six pull requests. Each is meant to produce a + Check Run on a self-hosted instance — passing, failing test, failing build, + timeout, skipped, container runtime. +
+
+ The log pages are the same /runs/{id} pages you get
+ behind auth. Shareable logs are on for that binding only. Until the demo
+ App is bound, the site links the pull requests and leaves run URLs empty
+ rather than inventing them.
+
+ This is contributor-facing proof, not a hosted CI service for arbitrary + public repos. You still run your own worker. +
+ +Use cases / Private repos
++ GitHub already stores the repo. You want a status on the commit. You do not + want to put that work on hosted Actions minutes or write workflow YAML for + install/test/build. +
++ Register a GitHub App against those private repos, bind them in the UI, and + the worker clones with an installation token that never lands in the remote + URL. The Check Run is the artifact GitHub already knows how to display. +
++ Setup: + GitHub App + and + bindings. +
+Use cases / Self-hosted teams
++ The team already pays for a VPS or a home-lab machine. openpreflight is a + Compose stack on that machine: UI, webhook, runner, SQLite, logs. +
++ GitHub only receives Check Run payloads and a details URL that points at + you. Shareable logs are opt-in per binding. Operations (backups, upgrades, + what a restart does to an in-flight job) are in + operations. +
++ Coolify can inventory servers and install the worker. It is not required, + and it does not execute jobs. +
+Why
++ The problem is not “we need another CI platform.” It is: we want a Check + Run on our private code, on our machine, without learning a second + workflow language. +
+ ++ GitHub already knows how to show a Check Run. Hosted Actions is the default + path, and it brings YAML, hosted minutes, and a lot of surface area. Full + self-hosted platforms exist for teams that need matrices, caches, and + artifacts. Plenty of people want something in between: the commit is gated, + the logs stay here, and the operator is a binary. +
+ +
+ One process is configurator and worker. One SQLite file holds Apps,
+ bindings, jobs, and encrypted secrets. You register a GitHub App you own.
+ Pipelines are install/test/build in .ci.yml, not a new DSL.
+ Runs are gated on the commit the way Zuul does it — trigger on the check
+ suite, build the immutable SHA, one live run per commit. The ceiling of
+ that model is in
+ ADR 005.
+
+ Hosted runners and full platforms solve orchestration. This product does + not. It reports Check Runs from a worker you host. GitHub Actions can still + orchestrate everything else. They can coexist; this does not replace + workflow YAML. See + openpreflight and GitHub Actions. +
+ +
+ Not in v1: Actions YAML, actions/runner, creating Apps for
+ you, matrices, caches, artifacts. Jobs on another machine use a Docker
+ engine (CI_DOCKER_HOST), not Coolify as a job runner. If those
+ are requirements, pick a different tool — the
+ docs comparison is honest about
+ that.
+