Loading
Draft: Build the EE assets with Nix from this repository
What does this MR do?
Moves the Nix build of the EE assets, and their /assets image, from hardened-builds into this repository, and adds CI jobs that build them and check their file names against build-assets-image's.
hardened-builds kept this recipe, so a frontend change here broke the Nix assets downstream, in CNG, after the merge. With the recipe here, the merge request that breaks it can fix it. The flake builds on hardened-builds' curated package set, its legacyPackages, and has no nixpkgs of its own.
nix/is a flake that buildsgitlab-assets-eefrom this checkout, with or without source maps, on x86_64-linux and aarch64-linux, the platforms GitLab supports, and on aarch64-darwin. Its/assetsimage is built on Linux only, as nix2container builds Linux images. Nothing has to be locked per commit beyond what the lockfiles hold:- Gems:
nix/gemset.jsoncomes fromGemfile.lock'sCHECKSUMS, written offline byscripts/nix/generate_gemset.rbthe way bundix would. - Yarn: each
yarn.lockentry is one fetch, checked against itsintegrity, so no mirror hash is committed. - Rust gems:
nix/lock.jsonholds the cargo vendor hashes of the four Rust gems, keyed by gem version.scripts/nix/update_lock.rbrefreshes both files. - glql:
gitlab_query_languageships itsCargo.lockat the gem's root, where cargo, building inext/, doesn't look, and without a source for glql, which glql's release builds from a checkout. The gem is repacked with that lockfile inext/and glql at its tag's commit, fromnix/lock.json, so the crates are the ones glql released with and nothing is resolved here. - Drift: Nix checks every hash it downloads, but not that
nix/gemset.jsonandnix/lock.jsonstill matchGemfile.lock. The gem env depends on a derivation that runsscripts/nix/update_lock.rb --check, so a stale file fails every build, in this repository's CI or elsewhere. The flake also exposes it aschecks.<system>.nix-lock.
- Gems:
- CI:
build-assets-image-nixbuilds the image in Nix's sandbox and pushesgitlab-assets-ee-nix:$CI_COMMIT_SHA. The sandbox needs a privileged runner, whichsaas-linux-large-amd64is. It builds in/build, as on NixOS, instead of a new/nix/var/nix/builds/nix-<pid>-<random>directory each time, where a tool that writes its path into the output changes the assets.compare-assets-image-nixchecks that every file its manifests name is ingitlab-assets-ee:$CI_COMMIT_SHA. It restores the build's cache for its tools, because building them downloadsskopeo's patches from GitHub.nix-lock-checkfails whennix/gemset.jsonornix/lock.jsonno longer matchGemfile.lock.
Commits:
- Add a Nix derivation for the EE assets: the hand-written
nix/files and the two scripts that generate the lock files, about 1,200 lines. - Add the Nix lock files:
nix/gemset.json,nix/lock.json,nix/flake.lockand the.gitattributesentry.scripts/nix/update_lock.rb --checkregeneratesnix/gemset.jsonand checks the versions innix/lock.json. - Build the EE assets image with Nix in CI: the three jobs, their rules, the build and comparison scripts.
Related issues
- hardened-builds export this MR needs, which also amends ADR-0039 to make that package set the one other projects build on (merged;
nix/flake.locklocks hardened-builds'main): gitlab-org/software-supply-chain-security/hardened-builds!245 (merged) - Rspack output independent of the checkout path, which this MR needs (merged): !262551 (merged)
- The requirement is described in ADR-0045: gitlab-org/software-supply-chain-security/hardened-builds!234 (merged)
- Prototype and e2e experiment: !261871 (closed)
- Origin of the comparison script: gitlab-org/build/CNG!3159
Validation so far
- Local build, before !262551 (merged), with hardened-builds at the export commit:
gitlab-assets-eewith source maps built in 76 minutes on a 16-core builder, and its image in about 2. Againstgitlab-assets-ee:fa79cc62f4d632420dc365b20c9939a577e160cc(master), the names are identical: webpack 4594 files, Rspack 1696 files, 939 entrypoints, Sprockets 1015 files. - CI comparison (2967035688, sandboxed, on master
e85ad990, after !259425 (merged) removed the frontend islands): every name matches a freshcompile-production-assets-rspackcompile. webpack 4585 files and 943 entrypoints, Rspack 1699 files and 943 entrypoints, Sprockets 1016 files. These pipelines ran with a test-only commit on top, since dropped, that setENABLE_COMPILE_PRODUCTION_ASSETSso they built the reference image, and fetched hardened-builds from the branch of gitlab-org/software-supply-chain-security/hardened-builds!245 (merged). 2962754292 on master89f9fcc6, the sandboxed build of 2955581957 on master24df4d74and the unsandboxed build of 2952009663 matched too. Before !262551 (merged), Rspack names differed (2950755954: 234 names), because Rspack's output depended on the build directory. - CI build:
build-assets-image-nixpassed in eleven pipelines of this merge request: 44 minutes cold (2949364597), then 23 to 29 with the CI cache (2949875030, 2950755954, 2952009663, 2955581957, 2962754292, 2967035688, 2968161029, 2975236712 on master9ab01f38with hardened-buildsmain, 2975327540, 2980629163 with hardened-buildsmainf6f4db1b, after gitlab-org/software-supply-chain-security/hardened-builds!249 (merged)). That covers fetching the now public hardened-builds without credentials (2975327540), the shallow clone, theskopeopush, and the no-source-maps variant that merge request pipelines build. - Sandbox: the build log of 2955581957 has 4874 lines with
/build/sourceand none with/nix/var/nix/builds. The unsandboxed log of 2952009663 has the reverse: none and 4872, all in/nix/var/nix/builds/nix-12016-<random>. - Systems: every output evaluates on x86_64-linux, aarch64-linux and aarch64-darwin; only x86_64-linux has been built. Supporting several systems left the x86_64-linux assets and
ci-toolsas they were: their derivation paths are the same before and after the change. - Gemset: for the
Gemfile.lockof the prototype's last run, the generator reproduces bundix's gemset exactly (771 gems). - Lock check: passes on aarch64-darwin, and on x86_64-linux as part of the gem env in 2968161029. With
gitlab-email_handlerswitched back fromgemtopathinnix/gemset.json, the drift master had on 2026-10-20, the build fails withnix/gemset.json is out of date. The check alone adds no gem rebuilds: it changes only the gem env's inputs.scripts/nix/update_lock.rbtook master'sgitlab_query_language0.42.0 bump end to end: the gemset, the tag's commit and the cargo hash. - glql: cargo accepts the gem's own
Cargo.lockplus the onesourceline and changes nothing else, and the lockfile in the vendor tree is byte-identical to the onecargo fetchwrites. The gem built on aarch64-darwin with those crates (rb-sys0.9.117,bindgen0.69.5), loads, and compiles a query. It built on x86_64-linux in 2968161029, which pushed the image. - Lint: yamllint (both profiles), shellcheck, nixfmt and RuboCop are clean. The new rules pass the checks of
spec/dot_gitlab_ci/rules_spec.rb.
Not validated yet
- Specs for
scripts/nix/*.rb.
Open questions
- Dependency bot gem bumps. Once this merges, a GitLab Dependency Bot merge request that changes only
Gemfile.lockfailsnix-lock-check, as master'soj3.17.7 bump did on this branch. The bot already regeneratesGemfile.next.lockin apostUpgradeTaskscommand. Runningscripts/nix/update_lock.rbthere too would keepnix/gemset.jsoncurrent with Ruby only. A bump of one of the four Rust gems still needs Nix for its cargo hash. nix/owner in.gitlab/CODEOWNERS:validate-codeowners-coveragefails until there is one.
Checklist
Pre-merge
- Pipeline types. The build and comparison are manual in MR pipelines that change the assets patterns,
nix/**orscripts/nix/**, and run automatically only whenENABLE_BUILD_ASSETS_IMAGE_NIXis"true".nix-lock-checkruns in MR and master pipelines that changeGemfile{,.lock},nix/*.jsonorscripts/nix/*.rb. All three are allowed to fail. Expedited MR pipelines skip the Nix jobs. - Non-canonical projects:
-
gitlab-foss,security,dev, personal forks: the build and comparison run only in gitlab-org/gitlab on gitlab.com, because the build holds a large runner for 25 to 45 minutes.nix-lock-checkneeds Ruby only.
-
- Pipeline performance. No change to existing jobs. A build holds a
saas-linux-large-amd64runner for 25 to 45 minutes, and only when someone plays it. The comparison takes minutes on the default runner; the lock check takes seconds.
New jobs:
- Change-related rules: above.
- Frequency: manual in MRs; automatic only where
ENABLE_BUILD_ASSETS_IMAGE_NIXis set, for example a schedule.
Edited by Alessio Caiazza