ci/forge/ci.dwarves.toml
# ci.dwarves.toml — dwarf's CI project: the dwarves forge (`dwarves serve`) is the build
# server of the constellation's mains. Registered by placing this file in the forge's
# warehouse: <DWARVES_WAREHOUSE>/projects/ci.dwarves.toml (setup.sh does it).
#
# Each push pipeline runs the repository's own `cargo xtask ci --quick` on a new head
# (pipelines/ci-<branch>.runa.ron); the Scorecard pipelines run nightly
# (pipelines/scorecard.runa.ron). The forge polls every 15 minutes, one repository at
# a time, and runs one pipeline at a time at low priority. See ci/forge/README.md.
[project]
name = "ci"
about = "dwarf's CI: the mains of Gunnar, Holger, their UIs, monetize, edda and Heimdall"
[mimir]
name = "ci"
[[workspaces]]
name = "ci"
# a CI project files no Build Thing builds at night
[nightly]
enabled = false
[ci]
poll_minutes = 15
siblings = true
# every sibling a CI repository's path dependencies name, at its branch head for each run
follow = [
"dwarves", "edda", "Skidbladnir", "draupnir", "facett", "funnel-core", "gunnar@master",
"gunnar-ui", "holger", "holger-ui", "modgunn@master", "monetize", "nornir", "skade",
"tunnr", "znippy@master", "znippy-zoomies", "openzl-sys-rs",
# edda's recipe_faithful guard reads every recipe of the constellation (CI-RED)
"korp", "ordning", "knut", "heimdall",
# dwarves' `lenses` feature: the graph cache (crates/dwarves/src/lenses/cache_graphar.rs)
"graph-ar",
]
[[pipelines]]
name = "gunnar-ci"
repo = "gunnar"
file = "pipelines/ci-master.runa.ron"
file_in = "dwarves"
# the suite's TMPDIR on /backup: Gunnar's 5%,2GiB disk floor is 186 GiB on the root array
env = { TMPDIR = "/backup/ci-tmp/gunnar" }
[[pipelines]]
name = "holger-ci"
repo = "holger"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
# the suite's TMPDIR on /backup: Gunnar's 5%,2GiB disk floor is 186 GiB on the root array
env = { TMPDIR = "/backup/ci-tmp/holger" }
# dwarves' own quick set on every new dwarves head (lane DW-HOLGER-BUILD, 2026-10-31): it
# holds `build:holger`, dwarves built with holger in it against the followed holger main.
[[pipelines]]
name = "dwarves-ci"
repo = "dwarves"
file = "pipelines/ci-main.runa.ron"
# a holger merge moves no dwarves head, so dwarves is built with holger again every six
# hours against holger main's head (Holger 3.0.0 broke the dwarves build and a media lane
# found out first)
[[pipelines]]
name = "dwarves-holger"
repo = "dwarves"
file = "pipelines/dwarves-holger.runa.ron"
[[pipelines]]
name = "gunnar-ui-ci"
repo = "gunnar-ui"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
[[pipelines]]
name = "holger-ui-ci"
repo = "holger-ui"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
[[pipelines]]
name = "monetize-ci"
repo = "monetize"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
[[pipelines]]
name = "edda-ci"
repo = "edda"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
# Heimdall (lane heimci): its own `cargo xtask ci --quick` (= scripts/ci.sh) in its OWN step
# image, heim-ci from heimdall's ci/ci.Containerfile (cargo-deny, cargo-fuzz, a dated nightly,
# libseccomp, wasi-libc headers since heimdall 03fc5a6), by digest; setup.sh builds the tag from
# the checkout when the box lacks it
[[pipelines]]
name = "heimdall-ci"
repo = "heimdall"
file = "pipelines/ci-main.runa.ron"
file_in = "dwarves"
image = "localhost/nordisk-cargo-toolchain@sha256:5470ba85216b3c38d35de0bbb36a4244e104995fce4e9bf79a0c0357e9b8b29f"
# The syscall-profile drift gate (Heimdall tooling plan step 6): tunnr's measured rows are
# built and checked by the row-pinned heimdall (nordisk-heimdall-cli 0.2.0, sha256 pinned in
# each measure.toml) on every head of main. setup.sh puts that binary at
# <warehouse>/ci/tools/heimdall/heimdall; the step sees it read-only.
[[pipelines]]
name = "tunnr-drift"
repo = "tunnr"
file = "pipelines/drift.runa.ron"
file_in = "dwarves"
tools = ["heimdall"]
# the aya row's tunnr-cni writes /run/tunnr-cni as the container's root (first run 2026-11-01:
# DEL "Permission denied" as the keep-id user), so the steps run as container root, in their
# OWN target (root-owned files never land in tunnr-ci's target)
user = "0:0"
env = { HEIMDALL_TOOL = "/opt/ci-tools/heimdall/heimdall", CARGO_TARGET_DIR = "/backup/ci-target/tunnr-drift" }
[[pipelines]]
name = "scorecard-gunnar"
repo = "gunnar"
file = "pipelines/scorecard.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", SCORECARD_BIN = "/home/rickard/opt/scorecard/5.6.0/scorecard" }
[[pipelines]]
name = "scorecard-holger"
repo = "holger"
file = "pipelines/scorecard.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", SCORECARD_BIN = "/home/rickard/opt/scorecard/5.6.0/scorecard" }
# Heimdall's Scorecard and OpenSSF badge copy (project 16105), nightly like Gunnar's and Holger's
[[pipelines]]
name = "scorecard-heimdall"
repo = "heimdall"
file = "pipelines/scorecard.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", SCORECARD_BIN = "/home/rickard/opt/scorecard/5.6.0/scorecard" }
# monetize's FULL set every night (lane CI-RED): its fast tests and trials left the quick set.
# The step gets the forge's step engine (the fast tests start containers) and the private
# monetize-impl read-only (the trials); so it publishes only its verdict and the failing
# step's name: its logs stay in the forge's warehouse on dwarf.
[[pipelines]]
name = "monetize-full"
repo = "monetize"
file = "pipelines/ci-full.runa.ron"
file_in = "dwarves"
publish = "verdict-only"
engine = true
private = ["monetize-impl"]
# its own target cap (the coordinator, 2026-10-31): the full set needs more than 40 GB
target_cap_gb = 60
# the full set in the 40 GB target (its first run stopped at 54 GB): the quick sets' lean
# profile, which every cargo the verbs start inherits
env = { CARGO_INCREMENTAL = "0", CARGO_PROFILE_DEV_DEBUG = "0", CARGO_PROFILE_TEST_DEBUG = "0", CARGO_PROFILE_DEV_STRIP = "symbols", CARGO_PROFILE_TEST_STRIP = "symbols", CARGO_PROFILE_RELEASE_DEBUG = "0", CARGO_PROFILE_RELEASE_STRIP = "symbols", TMPDIR = "/backup/ci-tmp/monetize" }
# OSSF-NEXT (2026-10-30): the nightly fuzz run of Gunnar's and Holger's cargo-fuzz crates
# (red on a crash; the corpus is kept on /backup between nights)
[[pipelines]]
name = "fuzz-gunnar"
repo = "gunnar"
file = "pipelines/fuzz.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", DWARVES_CI_FUZZ_CORPUS = "/backup/ci-fuzz" }
[[pipelines]]
name = "fuzz-holger"
repo = "holger"
file = "pipelines/fuzz.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", DWARVES_CI_FUZZ_CORPUS = "/backup/ci-fuzz" }
# the nightly test coverage (cargo llvm-cov). Gunnar: every crate of the root workspace
# (OSSF-SILVER-CODE 2026-10-31; no package list = --workspace), built lean (no debuginfo, no
# incremental cache: llvm-cov needs neither). MEASURED on oden, ci7-forge-cov: the whole
# workspace this way is a 30 GB target, inside the forge's 40 GB. The skipped tests are the
# ones Gunnar's quick set skips (xtask ci_quick::SKIP): podman, a release build, a statvfs
# that moves at once. Holger: the crates that parse and guard.
[[pipelines]]
name = "coverage-gunnar"
repo = "gunnar"
file = "pipelines/coverage.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", TMPDIR = "/backup/ci-tmp/gunnar", CARGO_INCREMENTAL = "0", CARGO_PROFILE_DEV_DEBUG = "0", CARGO_PROFILE_TEST_DEBUG = "0", DWARVES_CI_COVERAGE_SKIP = "the_community_binary_has_zero_entitlement_symbols_and_the_metered_one_has_them the_release_server_has_zero_narrate_symbols_and_the_dev_one_has_the_sender every_declared_variant_passes_through_the_cli_door the_build_kernel_line_plans_the_donor_first the_free_bytes_are_a_live_statvfs_and_move_when_the_filesystem_moves" }
[[pipelines]]
name = "coverage-holger"
repo = "holger"
file = "pipelines/coverage.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", TMPDIR = "/backup/ci-tmp/holger", DWARVES_CI_COVERAGE_PACKAGES = "holger-traits holger-errcode holger-update-bundle holger-provenance holger-inspect holger-sync holger-server-lib" }
# the weekly dependency update, proposed as a new branch after the quick CI went green on it
[[pipelines]]
name = "deps-gunnar"
repo = "gunnar"
file = "pipelines/deps-update.runa.ron"
file_in = "dwarves"
env = { TMPDIR = "/backup/ci-tmp/gunnar" }
[[pipelines]]
name = "deps-holger"
repo = "holger"
file = "pipelines/deps-update.runa.ron"
file_in = "dwarves"
env = { TMPDIR = "/backup/ci-tmp/holger" }
# MON-OSSF (2026-10-31): monetize the way OSSF-NEXT did Gunnar and Holger. Its open crates are
# fuzzed every night (monetize/fuzz, red on a crash); the private vendors' fuzz crate in
# monetize-impl too, beside it read-only and VERDICT-ONLY, so neither the private code nor its
# fuzz output (a crashing input, the log) leaves dwarf (ci-verbs fuzz --private monetize-impl).
[[pipelines]]
name = "fuzz-monetize"
repo = "monetize"
file = "pipelines/fuzz.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", DWARVES_CI_FUZZ_CORPUS = "/backup/ci-fuzz" }
[[pipelines]]
name = "fuzz-monetize-impl"
repo = "monetize"
file = "pipelines/fuzz-private.runa.ron"
file_in = "dwarves"
publish = "verdict-only"
private = ["monetize-impl"]
env = { RUSTFLAGS = "", DWARVES_CI_FUZZ_CORPUS = "/backup/ci-fuzz" }
# monetize's coverage: its tests load the guests it builds, so `cargo xtask build-guests` runs
# first (pipelines/coverage-guests.runa.ron). Only the OPEN crates are measured and published;
# not the console (monetize-ui-server's console_compiles test builds the wasm console, which
# cannot take llvm-cov's instrumentation), the mocks or the UI tests. The lean quick-set profile
# keeps the instrumented build inside the 40 GB target.
[[pipelines]]
name = "coverage-monetize"
repo = "monetize"
file = "pipelines/coverage-guests.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", TMPDIR = "/backup/ci-tmp/monetize", CARGO_INCREMENTAL = "0", CARGO_PROFILE_DEV_DEBUG = "0", CARGO_PROFILE_TEST_DEBUG = "0", DWARVES_CI_COVERAGE_PACKAGES = "monetize monetize-pay monetize-cloud monetize-product monetize-product-guest monetize-pay-guest monetize-cloud-guest monetize-signup-guest monetize-dns-guest monetize-embed monetize-guardian monetize-estate-side monetize-proto monetize-site-buy monetize-mail nordisk-estate-svg monetize-server monetize-front monetize-product-wasm monetize-cloud-wasm monetize-shop-pairing monetize-cli lake-product fast-edge" }
[[pipelines]]
name = "deps-monetize"
repo = "monetize"
file = "pipelines/deps-update.runa.ron"
file_in = "dwarves"
env = { TMPDIR = "/backup/ci-tmp/monetize" }
# monetize's Scorecard, nightly; monetize has no OpenSSF Best Practices project, so no badge step
[[pipelines]]
name = "scorecard-monetize"
repo = "monetize"
file = "pipelines/scorecard-plain.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", SCORECARD_BIN = "/home/rickard/opt/scorecard/5.6.0/scorecard" }
# README-BENCH (2026-10-31; the owner's standing rule: a performance claim comes only from a
# bencher run on REAL repositories): Gunnar's and Holger's README speed tables are generated
# from a weekly bench on oden (git.git and the real-client package sets), never copied by
# hand. `ci-verbs bench-readme` reaches oden over ssh with the forge's own bench key
# (DWARVES_CI_BENCH_SSH, its directory bound into the step: ci/forge/README.md), runs the
# repository's `cargo xtask bench-readme run|write|compare` there in ci4, and proposes the new
# result + README as a bench/ branch that the forge merges --no-ff; a regression past 25 % is
# red. Saturday 07:10 UTC (Gunnar) and 09:10 UTC (Holger): after the nightly batch.
[[pipelines]]
name = "bench-gunnar"
repo = "gunnar"
file = "pipelines/bench-readme-gunnar.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", DWARVES_CI_BENCH_SSH = "ssh -F /home/rickard/.config/dwarves-ci/bench-ssh/config" }
[[pipelines]]
name = "bench-holger"
repo = "holger"
file = "pipelines/bench-readme-holger.runa.ron"
file_in = "dwarves"
env = { RUSTFLAGS = "", DWARVES_CI_BENCH_SSH = "ssh -F /home/rickard/.config/dwarves-ci/bench-ssh/config" }