Public validation and private CI/CD¶
GitHub Actions runs autonomous validation on pull requests (including forks) and merge queues. GitLab revalidates integrated revisions, runs Ceph, builds official images and distributes releases. There is no bridge, label-based private approval, external-PR checkout in a privileged job, or new mirror service.
Selection and required checks¶
ops/ci/plan.py owns event policy, path classification and dependencies.
events.py resolves the event revision and emits schema-1 ci-plan.json with the
compared base, contribution head, tested SHA, expected jobs and selection reasons.
GitHub tests the PR merge commit (or merge-group commit), with full Git history.
Local git diff --no-renames -z includes removed paths and both sides of renames;
it has no PR-files API pagination limit. Unknown paths, missing history, a first
integration and changes to CI select all relevant checks conservatively.
| Event | Profile and work |
|---|---|
| GitHub PR into main/dev or merge queue | Impact-selected autonomous checks, hosted ephemeral runners, read-only token |
| Protected GitLab main/dev push | Compare to the last successful integration on that same branch, revalidate selected work |
| Effective version metadata change on main | Complete qualification, including Ceph and all official images |
Web pipeline on main, CI_MODE=qualify |
Complete qualification of the pipeline's exact main SHA, including docs-only revisions |
Protected stable vX.Y.Z push |
Check qualification, rescan and distribute existing artifacts; no image rebuild |
Schedule on main, CI_MODE=regression |
All autonomous checks and Ceph, without producing official images |
Schedule on main, CI_MODE=security |
Dependency/secret checks and both architectures of the latest qualified public images |
Schedule on main, CI_MODE=secrets-history |
Full-history secret scan only |
Web pipeline on main, CI_MODE=docs |
Strict docs build, screenshot inventory and Cloudflare deployment only |
Web pipeline on main, CI_MODE=recover-release |
Recover GitLab metadata for an existing public release only |
Version detection compares version fields, rather than treating every lockfile
edit as a new release. Cancellation or failure does not advance the integration
baseline: the next integration compares against the previous completed successful
parent and child pipeline with verifiable integration.json. A docs deployment,
maintenance run or release tag cannot become that baseline. The read API failing
is an error; an available API with no previous evidence triggers a full selection.
Backend changes select pytest, PostgreSQL/migrations and Vulture; runtime changes
also select browser checks, Ceph and image tests. Frontend selects the existing
quality suite, Vitest and browser tests. Dependency changes add the corresponding
Trivy scans; npm audit --omit=dev --audit-level=high remains in frontend quality.
Release scripts select Python tests and Helm/Compose contracts. Deploy changes
also select image onboarding checks. Cron/scheduler selects Python/ops contracts,
a public native scheduler smoke and the private scheduler build/scan. Backend and
frontend images are built together when Kind needs the pair at the exact SHA;
no old component is relabeled as a new commit. Documentation and capture scripts
select strict MkDocs, screenshot inventory and associated script tests.
The workflow has no global path filter. Require the stable CI / required
check in GitHub. Its always() gate requires a successful selector and success
for every expected fixed job. Missing, failed, canceled or incorrectly skipped
jobs fail the gate. Unselected jobs may be skipped. Logs, JUnit, Playwright HTML
and failure traces are available in the public Actions run. Fork approval uses
GitHub's native workflow approval, never a private execution label.
GitLab generates one bounded child pipeline from ops/ci/gitlab/jobs.yml.
Every selected dependency is mandatory, with no optional or allow_failure
escape. The parent uses strategy: depend for GitLab CE 18.1 compatibility.
integration-ready and release-ready also inspect real API job results,
including both named members of scan/smoke matrices and each job's commit SHA.
Trust and credentials¶
Root and child workflows reject unprotected references and unsupported pipeline
sources, including external pull requests and merge requests. Only integrated,
reviewed commits on protected main/dev and protected stable tags reach private
runners. GitHub uses no infrastructure secrets, privileged self-hosted runner or
pull_request_target. A fresh commit requires fresh validation of that SHA.
Configure protected, masked/hidden variables with these environment scopes:
| Environment | Credentials and purpose |
|---|---|
ci-ceph |
Dedicated Ceph lab credentials used only by ceph-functional-tests |
ci-orchestration |
Project GITLAB_CI_READ_API_TOKEN with read_api, for selection and evidence; no production credentials |
release-public |
GHCR package token, GitHub release Contents-write token; read_api token for the final evidence recheck |
docs-production |
Cloudflare Pages token limited to the documentation project and account |
Use two environment-scoped entries for the read token if needed. GitLab 18.1's
CI_JOB_TOKEN cannot perform the general pipeline/job reads used for evidence.
Keep it for Git transport, built-in registry operations and supported Release API
operations. Do not store a personal administrator token. Pipeline variables are
not forwarded wholesale to children; the validated recovery version is the only
user value explicitly transferred beyond the selected plan.
Ceph is mandatory whenever selected. Missing lab configuration fails the job.
The central test_account_bucket_object_flow must exist and pass; a skipped core
is a failure. Optional-capability skips remain governed by the documented Ceph
suite and appear in JUnit and the skip summary. Its lab is serialized to avoid
competing tests. See the suite's README for the current capability exclusions.
Tools, caches and maintenance¶
ops/ci/tools.json locks image indexes and CLI versions. GitHub actions are pinned
to commit SHAs. Node 24.21.0 is shared by the workflow, frontend image and
frontend/.node-version. The Playwright image and npm package both use 1.58.2;
its job replaces the image's embedded Node with the checksummed Node 24 binary
and verifies the installed package/version before running. Upgrade these together.
The dependency lockfile remains authoritative for the browser payload.
Image builds read the index digest from Buildx's JSON manifest output, supported
by the pinned Docker 27 CLI. Missing or invalid digests stop the job before runtime
checks or publication of the immutable SHA tag.
Runtime checks pull each architecture by its platform manifest digest from that
index. This supports Docker's classic image store while qualification and SHA tags
continue to identify the complete multiarchitecture index, including attestations.
Only npm/pip downloads are cached, keyed by dependencies and tool versions. Public GitHub caches and protected GitLab caches are separate; do not share runner caches across trust boundaries. BuildKit cache writes are restricted to protected builds and component/branch namespaces. Builds still run tests and scans when reusing an existing SHA image. Global retries cover infrastructure errors only; test failures are not retried as entire jobs. Playwright retains its explicit single retry and failure diagnostics.
One Trivy JSON scan produces table and CycloneDX output, preserving HIGH/CRITICAL,
ignore-unfixed and reviewed .trivyignore exceptions. Qualification records six
architecture-specific scan receipts with job IDs, exact image inputs, report
hashes, tool versions and timestamps. Release pipelines rescan the same digests.
Secret detection requires a successful analyzer report and zero unresolved findings.
Public PostgreSQL CI URLs and synthetic AWS identifiers used in redaction tests
and screenshots are exempt only when the detector rule, file and complete
extracted value match ops/ci/secret_report.py. This includes the former root
GitLab template and the exception definition itself. Removed localhost database
examples additionally require their original commit and exact extract fingerprint;
reintroducing one in a new commit still fails. Changed hosts, passwords, identifiers
or paths remain blocking. The job reports the number of exempt fixture findings.
Only redacted file/line/type diagnostics are uploaded; raw analyzer output is discarded.
Normal scans use the explicit Git range, while historical maintenance scans all
history. The scheduled image scan refuses old releases without qualification;
qualify and publish a new version before enabling that schedule after migration.
External setup and rollout¶
The repository cannot enforce these administrator settings by itself. This change does not apply them remotely:
- On GitHub main/dev, require
CI / requiredfrom GitHub Actions, reviews and current checks (or a merge queue). Disable force pushes/deletion and restrict bypass. Enable code-owner review for.github,.gitlab-ci.yml,ops/ci,ops/release, dependency locks and deployment manifests. Protect release tags. Do not require the individual conditional jobs: skipped unrelated checks are expected. Retain native fork-workflow approval and read-only token defaults. - On GitLab, protect main/dev and
v*, restrict merges/tag creation and CI config changes to maintainers, and restrict pipeline-variable overrides. Disable any integration that imports public PR code as privileged pipelines. Preserve the protected cache separation setting. - Register dedicated ephemeral runners tagged
bucketreef-protected, marked protected and locked to this project. Permit DinD/binfmt only in that trusted pool; do not expose the host Docker socket or production network credentials. Exclude this project from any broad shared runner with weaker restrictions. - Configure the environment-scoped secrets above, token expiration/rotation, Ceph lab isolation and Cloudflare permissions. The first new pipeline fails closed until the read token and required lab configuration are present.
- Keep explicit, fast-forward synchronization of main/dev and matching tags between GitHub and GitLab. Preserve commit SHAs; never recreate commits or move published tags. Tag GitHub first, then GitLab, after main qualification succeeds.
- Keep qualification and distribution manifests, reports, bundles and referenced
image digests indefinitely (
expire_in: neveron evidence jobs). Exclude their registry tags/manifests from cleanup. Back up GitLab artifacts and registry; a missing proof or source digest blocks publication rather than triggering a rebuild. Set storage quotas/retention for routine one-week reports separately. - Make the GHCR application images,
charts/bucketreefandbucketreef-bundlespackages public. Configure the three explicit schedule profiles on main with a trusted owner. Avoid duplicate schedules; start security maintenance only after the first qualified release is available.
No branch or tag is pushed as part of local implementation. After settings and synchronization, exercise one fork PR, one merge-group run if enabled, main/dev integration, a deliberate canceled integration, a full qualification, and a new release. The release run must prove Ceph, registry copy/visibility and DinD/Kind on the actual runners; local fixtures and graph checks cannot prove these.
Local validation¶
Install Python CI dependencies and the pinned tools, then run:
python3 -m pip install -r ops/ci/requirements.txt
python3 -m pytest ops/ci/tests -q
sh ops/ci/tasks/lint.sh
# With application dependencies installed:
sh ops/ci/tasks/run.sh backend-tests
sh ops/ci/tasks/run.sh frontend-quality
sh ops/ci/tasks/run.sh frontend-tests
sh ops/ci/tasks/run.sh docs-build
Tests cover event/path selection, rename/delete and incomplete-history fallback, failed selectors, canceled/missing jobs and matrices, trust rejection, successful baseline provenance, qualification tampering, immutable conflicts and interrupted publication. Graph checks use the assembled configuration with locked images.
References: GitLab child strategy, GitLab job-token permissions, GitHub required checks.