Skip to content

Orchestration - #143

Open
pbuncic wants to merge 182 commits into
mainfrom
orchestration
Open

pbuncic wants to merge 182 commits into
mainfrom
orchestration

Conversation

@pbuncic

@pbuncic pbuncic commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Orchestration: certification by bits-orchestrator, SBOM scanning, build plan, several stores

This merges orchestration into main: 148 commits since 35b7773, with contributions from Juan Miguel Carceller (#134, #136, #138), Maria Folina (#139, #142) and Akrit Kumar Behera (#131). CHANGELOG.md (Unreleased) lists every change by area; the main lines are below.

bits-orchestrator (console-backend)

  • A worker beside the console backend, with its own SQLite database: builds reconciled from GitLab and the S3 build index, failures deduplicated into issues, typed actions with approvals, and a hash-chained event log with an outside copy (audit-log service).
  • Certification: the worker replays and then performs certification itself from the console pre-approval, as soon as a build is in the store. With BITS_ORCH_OWNS_SET=1 it owns the certified set: it writes numbered per-architecture manifests to MANIFESTS/, mirrors the set to bits-manifests and marks the store (MANIFESTS/orchestrator.json). Admins take builds or packages out with decertify and decertify-package; the worker then withdraws them from the signed manifests. bits then defers: bits certify stops after the approval and bits sign refuses the store.
  • Build queue: console builds wait in the orchestrator, not in GitLab (where they counted against the job limit), and start one per free build host. Hosts with offline runners are skipped, and one passkey approves a whole batch's certifications.
  • Supply chain: every published build's SBOM is scanned (bits-services sbom-scanner, grype), and rescanned when the vulnerability database updates. Community admins triage findings (VEX, including package-wide rules). Upgrade plans and licence and dependency analyses are computed from the scans. Separately, bits trace reports who built, published and approved a file on CVMFS.
  • Credentials can go through a second security proxy, so neither the backend nor the worker holds a GitLab token or store key.

bits

  • Build plan before every build: build-only dependencies of reused packages are neither fetched nor built (skip downloading only build_requires packages if a package is found. #141; --fetch-build-requires restores the old behaviour). The store is listed in parallel, and certified listings are cached in <work dir>/.store-cache/. An end-of-build summary says why each package was built.
  • Stores: several read and write stores, each bucket with its own credentials (Multiple endpoints --remote-store and --write-store can we support multiple S3 buckets? #130). Builds work offline when a read store can't be reached, and fetch_cache caches a recipe's own downloads (Caching Support for additional sources. #129).
  • Trust: manifests are fetched afresh each run (revalidated with their ETag). Entries are per architecture and hash, trust_manifest_prefix accepts several prefixes, and manifest sequence numbers prevent rollback to an older manifest.
  • SBOM: recipe references: (CPEs and purls), versions of system packages, sbom: tool for host tools, and version pins.
  • bits upgrade sets new versions in the recipes from a console upgrade plan.
  • --symlink-packages-from (Adding an feature that help us create symlink of packages that are already deployed on cvmfs. #131, Akrit Kumar Behera): links packages from a deployed tree without modulefiles (CMS) into the work directory. Strict mode needs a matching .build-hash and, with signed reuse on, a certified one; a SYMLINK_STAGE recipe-repository hook handles SCRAM. The companion cms.bits change is a separate PR.
  • Environment commands (q, enter, load, setenv) work from CVMFS without Python or a work directory, replacing bitsenv. A release with a complete view is set up through the view's setup.sh.
  • Also: a macOS build sandbox, site configuration in site.d/NN-<name>.yaml, bits status hashes that now match the build's (--set, --docker, source form), regrouped bits -h, and CVMFS publish fixes.

Compatibility

  • No package hash changes for existing recipes, and BUILD_EPOCH stays 0. The new hash-excluded inputs are references:, sbom:, system_package: and the SYMLINK_STAGE hook.
  • Behaviour changes:
    • A defaults chain with a compiler but no build type now builds opt (e.g. key4hep::gcc15 → key4hep::gcc15::opt). This puts those builds under the -opt architecture, where the certified tarballs are.
    • Build-only dependencies of reused packages are skipped.
    • CERN builds read lcgapp-bits-testing.
    • bitsenv is removed.
  • The build manifest gains additive fields (rebuilt_because, references, pinned_by, sbom, symlinked_from, symlink_policy); the schema version is unchanged.
  • The orchestrator features are opt-in through environment variables (see console-backend/README.md). Without them the backend behaves as before.

Merging

main has d3ea1a6 (grep -R → -r in build_template.sh), which this branch has as cfa3bbe. The merge is clean. On main alone, test_build_epoch fails because that commit didn't update COVERED_SHA256; the merge fixes it.

Testing

  • bits: 2568 passed, 37 skipped.
  • console-backend: 573 passed, 2 skipped.
  • test_build_epoch passes on the merge result.

The worker recomputes each bits-manifests certification and compares it
with what was signed; events are sent to the audit-log service and checked
against its head. certify: build_by_arch, s3_probe with a digest cache.
The worker keeps each certified BOM's bytes and follows bits-manifests as
versions of the set, every change an event; the shadow also computes each
certification from the set; GET /ops/certified.
With BITS_CRED_PROXY_AGENT_SOCKET the backend and the worker hold no
GitLab token or store key, only the credentials proxy's gate tokens.
Pushed by make unlock from an encrypted bundle (tools/service-secrets.py);
Both were installed only by the image; the credentials proxy needs boto3.
test_credproxy skips the S3 client test where boto3 is missing.
The proxy decodes the path once, so a project or group path's %2F must be sent as %252F.
BITS_ORCH_STORE_ANONYMOUS=1: unsigned requests at BITS_ORCH_S3_ENDPOINT (https).
Console pre-approval, store BOMs, certify group, admin and key policy; no signing.
A retry resumes and a stack seen before costs nothing; fresh hashing waits for signing.
certifier.py signs each pre-approved build via the signer proxy and writes it
through a worker-only store writer, under CANARY/ until M8b; canary.py matches
it against the CI's certification of the same build.
A cached copy was never refreshed, so build nodes kept trusting their first
manifest and gc swept by stale roots. A failed fetch now trusts nothing from
that manifest (rebuild; gc and cleanup refuse) instead of an older copy.
The store pass ran serially, twice per certified build. Packages now go 8 at a
time (BITS_PUBLISH_JOBS), and bits certify uses the BOM the publish step wrote
when it matches what this publish would write, but for who and when.
Concurrent certification MRs got 405 while GitLab rechecked them after another
merged. Pending states are retried for 5 min; other refusals fail at once. With
sha, only the validated head is merged, and an already-merged MR must match it.
Concurrent certification MRs made every comparison 'rebased'. The worker's and
the CI's sets now only have to agree for the architecture; packages' provenance
is not compared; a base the set never takes in is 'unbased'.
Already-installed packages were reused silently. The summary counts installed,
from-store and built packages, names the latter with the reason, keeps the reason
in the build manifest and pushes the counts to the build-host metrics.
An unchanged signed manifest is a 304: the local copy, whose sha256 is kept with
its ETag, stays and is verified as before. Weak ETags are never sent; a truncated
download is a failed fetch.
key4hep::gcc15 built as x86_64-el9-gcc15 and missed every certified -opt tarball
of the same hash. Such a chain now gets opt before any overlay, exempt from
valid_defaults, so the same binaries always land under one qualified arch.
A link to the venv's Python runs the base Python, without the venv's
packages: CI's has no yaml, so bits stopped before printing its help.
Inside "...", bash 3.2 keeps the quotes of a ${x//pat/"rep"}, so the
other build type's tree was never found on macOS.
Only a NUL byte makes a file binary then; macOS grep in a UTF-8 locale
skipped text with invalid UTF-8 (e.g. Latin-1), which GNU grep rewrote.
SimpleNamespace takes a mapping only from 3.13 on; before, the strict
symlink test raised TypeError.
Fetching, finalizing, done, uploaded, linked and reused lines now look like
the spinner's, with --builders too; no spaces are left after ': done'.
sh ends a script whose '.' finds no file, so on macOS the rpm/dpkg answers
were dropped and only the checks' versions recorded.
relocate-me.sh relocates to the physical path; on macOS the temp dir is
under /var, which is /private/var.
After --console, $BITS_CONSOLE_URL and system: console_url, the site's
console.backend_url (bits.cern.ch at CERN), as bits trace already does.
The approval printed only the link, silently, without the Python module
qrcode; it now says the module is missing and how to install it.
The order a setting is looked for in, the CERN values now in 10-CERN.yaml,
how another site masks them, and the console URL default; CHANGELOG.
A build made with the CLI had no builds row: never scanned nor in the
vulnerability views. Once certified it is recorded as pipeline 0's
(migration 18 reserves it), its community the approved group.
Once a day the worker records each release's open findings by severity
and their risk (migration 19), earlier builds at their publish days;
GET /ops/sbom/history serves them with today's point afresh.
It was taken for a commit and failed at checkout, leaving a clone behind.
…e is redone

A clone left by a failed or killed run stopped every later build.
… and queue

Read-only, for the community named; admins as before, vulnerabilities theirs.
…ay so

A runner tagged bits-host-<name> is a host; build-hosts.yaml is no longer read.
Migration 20; /ops/schedules for a community's admins to edit, anyone to read;
times in the instance's time zone (site console.time_zone).
One build per platform with the fan-out's variables; missed nights, overlaps,
certification under the schedule's standing approval.
Runs follow their builds; /ops/nightlies; POST /ops/schedules/{id}/run.
…host

Actions host.pause, host.resume (the host's runners in GitLab) and host.refresh (its builder images, a pipeline pinned to it).
Action host.prune (a pipeline pinned to the host); per-host target, 200 GiB unless saved.

# Conflicts:
#	console-backend/README.md
GET /ops/worker, from the worker's step events; errors for overall admins.

# Conflicts:
#	CHANGELOG.md
#	console-backend/console_backend/orch/api.py
phases.failed_in from the job's marks (migration 21).

# Conflicts:
#	CHANGELOG.md
GET /ops/admin/ci-var?key=BITS_DESIRED_REF.

# Conflicts:
#	CHANGELOG.md
phases.host is bits-host-<name> of a pinned build, else the runner's description.
The community's defaults_overlay last, as DEFAULTS too; --day, the weekday of the night.
Variants are defaults chains put before its own; a run is one cell (migration 22).
Heads read with git protocol v2 over HTTPS; a moved head, settled, builds every cell (migration 23).
WORKFLOWS Phase 4 gains steps 4 and 5; release notes summarise both.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants