From 17ad38aef8c186af47461ee5282460c77c0cac20 Mon Sep 17 00:00:00 2001 From: Albert Bausili Date: Sun, 6 Sep 2026 00:43:09 +0200 Subject: [PATCH 1/5] ci: add a SHA-pinned build/check/test gate for pull requests Until now nothing checked a pull request before it reached main: the only build of the site was Cloudflare Workers Builds on the push to main, so a broken change surfaced as a failed deploy after the merge. This workflow runs on pull_request and on push to main with the same install and build the deploy performs (bun install --frozen-lockfile, bun run build), then astro check and the data-layer tests. The job is named `build` so a required status check on main can reference it. Hardening details: - actions are pinned to full commit SHAs with a `# vX.Y.Z` trailer (actions/checkout v7.0.1, oven-sh/setup-bun v2.2.0); Dependabot's github-actions ecosystem keeps them current. - permissions: contents: read only, and checkout uses persist-credentials: false because no later step pushes or calls the API, so the token is never left in .git/config. - setup-bun rather than setup-node + npm ci: the repo is a Bun project (bun.lock, engines.bun >= 1.3, scripts run `bun scripts/*.ts`) and has no package-lock.json, so npm ci could not install it. - build runs before check: astro check type-checks imports of the gitignored src/data/generated/*.json that build:data emits. Org hardening review 2026-09-06. --- .github/workflows/ci.yml | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c5b2b04 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI + +# Pull-request / push gate for the site. Cloudflare Workers Builds is what +# actually deploys (`bun run build` on every push to `main`), but until this +# workflow existed nothing checked a PR *before* it reached `main` — a broken +# build only surfaced as a failed deploy. This job runs the same install and +# build as the deploy, plus `astro check` (types + content schema) and the +# data-layer tests, so a required status check named `build` can gate `main`. +# +# It is deliberately read-only: no deploy, no token use, no writes. + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + build: + name: build + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Nothing in this job pushes or calls the API; do not leave the + # GITHUB_TOKEN in .git/config for later steps to pick up. + persist-credentials: false + + # The site is a Bun project (bun.lock, engines.bun >= 1.3, scripts invoke + # `bun scripts/*.ts` directly) — there is no package-lock.json, so + # setup-node + `npm ci` would not work here. `latest` mirrors what + # Cloudflare Workers Builds installs; package.json only sets a floor. + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: latest + + - name: Install (frozen lockfile) + run: bun install --frozen-lockfile + + # `build` = build:data -> astro build -> pagefind. It must run before + # `check` because `astro check` type-checks imports of the gitignored + # src/data/generated/*.json that build:data emits. + - name: Build + run: bun run build + + - name: Check (astro check) + run: bun run check + + - name: Test (data layer) + run: bun test From 212f50d5dc7149cd914d4a7ce0920a72f2cfd817 Mon Sep 17 00:00:00 2001 From: Albert Bausili Date: Sun, 6 Sep 2026 00:43:09 +0200 Subject: [PATCH 2/5] chore: add Dependabot for npm and GitHub Actions The site had no Dependabot configuration, so neither its JavaScript dependencies nor the action SHAs the new CI workflow pins would ever be proposed for update. Both ecosystems run weekly and are grouped into one PR per run: this is a static site with no runtime server, so a daily PR stream buys nothing. typescript is deliberately pinned to exactly 6.0.3 because @astrojs/check breaks on TypeScript 7 and drifting the pin would ship the site with no type-check gate. An ignore rule excludes semver-major and semver-minor updates for it so only patch releases of the 6.0 line are proposed. Dependabot's npm ecosystem reads package.json + bun.lock, so it covers a Bun-installed project without any extra configuration. Org hardening review 2026-09-06. --- .github/dependabot.yml | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..647eb97 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,43 @@ +version: 2 +updates: + # ----- npm (Astro site, installed with Bun) ----- + # The site is installed and run with Bun (`bun install --frozen-lockfile`, + # engines.bun >= 1.3), but Dependabot's `npm` ecosystem reads the same + # package.json + bun.lock, so bumps land as reviewable PRs that the `build` + # CI job then compiles. Weekly cadence: this is a static site with no + # runtime server, so a daily dependency PR stream buys nothing. + # + # `typescript` is pinned EXACTLY to 6.0.3 on purpose: @astrojs/check breaks + # on TypeScript 7, and drifting the pin would silently ship the site with + # no type-check gate. Only patch releases of the 6.0 line may be proposed; + # a major or minor bump must be a deliberate, hand-made change. + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + ignore: + - dependency-name: typescript + update-types: + - version-update:semver-major + - version-update:semver-minor + groups: + all-js-deps: + patterns: + - "*" + commit-message: + prefix: "deps" + + # ----- GitHub Actions ----- + # Every workflow pins its actions to a full commit SHA with a `# vX.Y.Z` + # trailer; this entry is what keeps those SHAs current. Group all action + # bumps into ONE PR per scheduled run. + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + all-actions: + patterns: + - "*" + commit-message: + prefix: "ci" From 22ade00cbb0c9976112af0590f46ca38dbfb8f3a Mon Sep 17 00:00:00 2001 From: Albert Bausili Date: Sun, 6 Sep 2026 00:43:09 +0200 Subject: [PATCH 3/5] chore: add CODEOWNERS with the repository owner as default reviewer Lets GitHub request review from the owner on every pull request and lets the main ruleset require a code-owner approval before merge. Includes a commented example of delegating an area to a co-maintainer so the format is obvious when the first delegation happens. Org hardening review 2026-09-06. --- .github/CODEOWNERS | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..29ae45f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,15 @@ +# Code owners for goceleris/docs. +# +# GitHub requests a review from the matching owner(s) on every pull request +# and, when the branch protection / ruleset for `main` requires code-owner +# review, blocks the merge until one of them approves. Later rules override +# earlier ones, so the catch-all comes first and area delegations go below it. +# +# Syntax: https://docs.github.com/articles/about-code-owners + +# Default: the repository owner reviews everything. +* @FumingPower3925 + +# Area delegation example (uncomment and adjust when a co-maintainer takes an +# area; the more specific path wins over the catch-all above): +# /src/content/docs/ @FumingPower3925 @WdnLiu From b2aa1d6a3678cab52b22a50b8d4fd2e97ded77f0 Mon Sep 17 00:00:00 2001 From: Albert Bausili Date: Sun, 6 Sep 2026 00:43:09 +0200 Subject: [PATCH 4/5] docs: add SECURITY.md and CONTRIBUTING.md SECURITY.md gives reporters a private channel: the repository's Security tab -> "Report a vulnerability" (private vulnerability reporting is enabled on this repo) as the preferred route, security@goceleris.dev as the alternative, with a 72-hour acknowledgement commitment. It scopes the policy to the site build pipeline and hosting configuration and points engine reports at celeris/SECURITY.md, which owns the supported-versions table. CONTRIBUTING.md documents how to run the site locally with Bun, what CI runs (build, astro check, bun test), the PR flow, the pinned-typescript and results/-is-publisher-owned rules, and the merge rule: green `build` job plus a code-owner approval. Org hardening review 2026-09-06. --- CONTRIBUTING.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ SECURITY.md | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..76e3523 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,57 @@ +# Contributing + +Thanks for helping improve the Celeris documentation and benchmark dashboard. +This repository is the source of [goceleris.dev](https://goceleris.dev). + +## Running the site locally + +Requires [Bun](https://bun.sh) `>= 1.3.0` (see `engines` in `package.json`). + +```sh +bun install --frozen-lockfile +bun run dev # build:data, then astro dev at http://localhost:4321 +bun run demo # same, against a synthesized demo dataset +``` + +Before opening a pull request, run what CI runs: + +```sh +bun run build # build:data -> astro build -> pagefind +bun run check # astro check (types + content schema); needs build:data first +bun test # data-layer tests +``` + +`bun run validate` checks every committed `results/` cell without emitting +anything — it is the gate the benchmark publisher relies on. + +Documentation pages live in `src/content/docs/**/*.{md,mdx}` and are validated +against the frontmatter schema described in the [README](README.md#content-structure). + +## Pull-request flow + +1. Fork (or branch, if you have write access) from `main`. Branch names follow + `docs/`, `feat/`, `fix/`, `chore/`. +2. Keep one topic per pull request and use a conventional commit prefix + (`docs:`, `feat:`, `fix:`, `chore:`, `ci:`, `deps:`) with a body that + explains *why*. +3. Do not touch dependency versions in a content PR; Dependabot proposes those. + `typescript` is pinned exactly to `6.0.3` on purpose (`@astrojs/check` + breaks on TypeScript 7) — do not bump it by hand. +4. Do not edit `results/` by hand. Benchmark cells are committed by the + probatorium publisher, and `src/data/generated/` and `public/data/` are + gitignored build outputs. + +## Merge rule + +`main` is protected. A pull request merges only when: + +- the `build` CI job is green (install, build, `astro check`, tests), and +- a code owner (see `.github/CODEOWNERS`) has approved it. + +Every push to `main` is deployed automatically by Cloudflare Workers Builds, so +a merged PR is live within minutes — make sure the site builds and looks right +locally before merging. + +## Security + +Never report a vulnerability in a public issue; see [SECURITY.md](SECURITY.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ac8cef5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,47 @@ +# Security Policy + +This repository builds the **goceleris.dev** static site: documentation and the +benchmark dashboard. It contains no server code and no runtime — every page is +rendered at build time and served as plain HTML from Cloudflare Workers static +assets. The security surface is therefore the build pipeline, the published +content, and the small client-side dashboard island. + +## Reporting a vulnerability + +**Do not open a public GitHub issue for security vulnerabilities.** + +Report privately through either channel: + +1. **Preferred:** this repository's **Security** tab → **"Report a + vulnerability"** (private vulnerability reporting is enabled): + +2. Email **security@goceleris.dev** + +Please include a description of the issue, steps to reproduce, the potential +impact, and a suggested fix if you have one. + +We will acknowledge your report within **72 hours** and keep you informed as we +triage and fix it. + +## Scope + +In scope for this repository: + +- The site build pipeline (`scripts/`, `src/lib/results/`) and the way it + ingests the committed `results/` benchmark cells +- Published content that could mislead users about Celeris's security posture +- The client-side dashboard island under `src/dashboard/` +- Static hosting configuration (`public/_headers`, `wrangler.jsonc`) + +## The engine itself + +Vulnerabilities in **Celeris** — the HTTP framework and its I/O engines that this +site documents — are handled by the celeris repository's policy, which also +lists the supported versions: + +(). + +Issues in the load generator or the benchmark harness belong to +[loadgen](https://github.com/goceleris/loadgen/security/policy) and +[probatorium](https://github.com/goceleris/probatorium/security/policy) +respectively. From 5adc264bd301a56cd06c1450ec408328966a3412 Mon Sep 17 00:00:00 2001 From: Albert Bausili Date: Sun, 6 Sep 2026 01:10:55 +0200 Subject: [PATCH 5/5] chore(dependabot): use the bun ecosystem, not npm, for the site's JS deps The npm entry could not do what its comment claimed. Dependabot's `npm` ecosystem is dependabot-core's npm_and_yarn, which reads package-lock.json, yarn.lock and pnpm-lock.yaml and never bun.lock (its file fetcher has no Bun code path); Bun is a separate ecosystem, `bun`, with its own fetcher and bun.lock parser. Pointed at this repo, npm would have seen a manifest-only project: no PRs for the ^-ranged dependencies until a new major shipped, and the one exact pin (typescript 6.0.3) would have got a patch PR that edited package.json without refreshing bun.lock, so the `bun install --frozen-lockfile` step of the `build` CI job would have failed on every Dependabot npm PR. Switch the entry to `package-ecosystem: bun` (GitHub: Bun >= 1.1.39, text lockfile). directory, weekly schedule, the typescript semver-major/minor ignore, the all-js-deps group and the `deps` commit prefix carry over unchanged. The comment now states the actual mechanism and records the one caveat: the bun ecosystem does version updates only, so Dependabot security alerts on JS dependencies do not auto-generate PRs here. Verified against dependabot-core (common/lib/dependabot/config/file.rb maps "npm" => "npm_and_yarn" and "bun" => "bun"; bun/lib/dependabot/bun/ is a separate ecosystem; npm_and_yarn's file_fetcher.rb has zero Bun references) and GitHub's supported-ecosystems table. dependabot.yml still parses and both entries are in the SchemaStore dependabot-2.0 enum. --- .github/dependabot.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 647eb97..7bf72dd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,17 +1,30 @@ version: 2 updates: - # ----- npm (Astro site, installed with Bun) ----- + # ----- Bun (Astro site) ----- # The site is installed and run with Bun (`bun install --frozen-lockfile`, - # engines.bun >= 1.3), but Dependabot's `npm` ecosystem reads the same - # package.json + bun.lock, so bumps land as reviewable PRs that the `build` - # CI job then compiles. Weekly cadence: this is a static site with no - # runtime server, so a daily dependency PR stream buys nothing. + # engines.bun >= 1.3) and its only lockfile is the text `bun.lock`; there + # is no package-lock.json. That rules out the `npm` ecosystem: it is + # dependabot-core's npm_and_yarn, which reads package-lock.json, yarn.lock + # and pnpm-lock.yaml but never bun.lock. Pointed at this repo it would see + # a manifest-only project, propose nothing for the ^-ranged deps until a + # new major shipped, and any PR it did open would edit package.json without + # refreshing bun.lock, so the frozen-lockfile install in the `build` CI job + # would fail. `bun` is its own ecosystem (Bun >= 1.1.39, text lockfile) that + # parses and rewrites bun.lock, so bumps land as reviewable PRs that the + # `build` job then installs, compiles, checks and tests. + # + # Caveat: `bun` supports version updates only, not security updates. A + # Dependabot alert on a JS dependency will not auto-generate a PR here; it + # is closed by the next weekly version PR or by a hand-made bump. + # + # Weekly cadence: this is a static site with no runtime server, so a daily + # dependency PR stream buys nothing. # # `typescript` is pinned EXACTLY to 6.0.3 on purpose: @astrojs/check breaks # on TypeScript 7, and drifting the pin would silently ship the site with # no type-check gate. Only patch releases of the 6.0 line may be proposed; # a major or minor bump must be a deliberate, hand-made change. - - package-ecosystem: npm + - package-ecosystem: bun directory: / schedule: interval: weekly