nandi/jolt-nativepublic Fork 0
8288c38
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

A second checker that checked nothing anyone was waiting on

Added two commits ago and removed before it ever passed, which is the honest
summary. The job re-ran `nix flake check` and the three builds on a second
host and then published none of it — deliberately, because GitLab holds the
only credential that should be publishing — so what it produced was run
artifacts nobody fetches and a nixbuild dispatch per push.

The case for it was a push reaching rickub and not GitLab. That is not how
anything here is pushed, and if it ever becomes so, the fix is to push both
places rather than to build twice.

Against it: two failed runs and a cancellation, all of them in the same six
lines of SSH plumbing — no systemctl in the image, no daemon to restart, and
ssh not reading a root dotfile because $HOME is not /root. None of that was
near the thing being built, and none of it taught us anything about
libsPortable, which is what actually wanted proving. GitLab's pipeline proves
it, on the push that matters, with the tarball at the end of it.

The rickub repo stays as a mirror. A mirror that builds nothing is a
reasonable thing to be; this was the other kind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-18T17:34:47-07:00 Browse files
8288c38 parent: 459c9cd
deleted .rickub/workflows/build.yml +0 -158
deleted file mode 100644
@@ -1,158 +0,0 @@
1-# The build, on rickub. The same `nix flake check` and the same three objects
2-# GitLab builds next door, for the case where a push reaches this host and not
3-# that one.
4-#
5-# It does not compile here, and could not: a rickub runner is a Linux x86-64
6-# container, and this graph is ~800 vendored crates behind libcosmic, iced,
7-# wgpu and aws-lc-sys. What the runner does is evaluate, dispatch and fetch —
8-# eu.nixbuild.net holds every vendor path from previous runs and does the
9-# compiling, exactly as it does for GitLab. So the two hosts share a cache
10-# rather than duplicating an hour of work, and a warm pipeline here is a
11-# pipeline that mostly substitutes.
12-#
13-# What it deliberately does NOT do is publish. The tarballs go to GitLab's
14-# generic package registry, and the token for that is CI_JOB_TOKEN — a GitLab
15-# job's own credential, issued to the job, not something to mint and carry
16-# here as a long-lived secret. One publisher and one place a consumer pins
17-# from is also just simpler to reason about than two. This host builds, checks
18-# and hands the tarballs back as run artifacts; `main` on GitLab is what moves
19-# `latest`.
20-#
21-# Lives in .rickub/workflows/ rather than .github/workflows/ because rickub
22-# reads one or the other and never both — see
23-# https://rickub.com/docs/actions and https://rickub.com/docs/migrating-from-github
24-name: build
25-
26-on:
27- push:
28- pull_request:
29- workflow_dispatch:
30-
31-jobs:
32- check:
33- runs-on: ubuntu-latest
34- # A cold run vendors the world and compiles the workspace. The builder does
35- # the compiling, but this side waits on it, and waits on the fetch of what
36- # comes back. GitLab gives the same job 3h.
37- timeout-minutes: 180
38- steps:
39- # The flake is fetched from the checkout, and nix wants the git tree
40- # rather than a shallow single commit to resolve `self` from.
41- - uses: actions/checkout@v4
42- with:
43- fetch-depth: 0
44-
45- - uses: cachix/install-nix-action@v27
46- with:
47- extra_nix_config: |
48- experimental-features = nix-command flakes
49-
50- # Everything the GitLab job's before_script sets up, and for the same
51- # reasons — the comments there are the long version. The short one:
52- #
53- # max-jobs must NOT be zero. At zero the runner refuses to build
54- # anything at all, which sends the fixed-output fetches (rust
55- # toolchain tarballs, every crate source) to nixbuild, where the build
56- # sandbox has no network and they can only fail. nproc keeps those and
57- # crane's hundreds of trivial cargo-src derivations local and parallel;
58- # the expensive builds still go remote.
59- #
60- # The explicit priority on nixbuild matters. nix picks a substituter by
61- # priority rather than by the order listed, and an ssh-ng store
62- # defaults to 0 against cache.nixos.org's 40 — so without it nixbuild
63- # wins even for stock nixpkgs paths and they crawl down one SSH
64- # connection instead of coming off the CDN.
65- #
66- # Keep the builder's job count modest: nixbuild's sshd caps concurrent
67- # sessions and refuses the excess, which nix reports as the thoroughly
68- # misleading "Nix daemon disconnected unexpectedly (maybe it crashed?)".
69- - name: Point nix at eu.nixbuild.net
70- env:
71- NIXBUILD_SSH_KEY: ${{ secrets.NIXBUILD_SSH_KEY }}
72- run: |
73- set -eu
74- # ROOT's ~/.ssh. The GitLab job runs as root in a nixos/nix image and
75- # needs no such care; here the step below decides which install this
76- # is, and root is the answer either way — see the note there.
77- sudo mkdir -p /root/.ssh
78- # base64 because a CI variable can only carry a single line.
79- printf '%s' "$NIXBUILD_SSH_KEY" | base64 -d | sudo tee /root/.ssh/nixbuild >/dev/null
80- sudo chmod 600 /root/.ssh/nixbuild
81- printf 'Host eu.nixbuild.net\n PubkeyAcceptedKeyTypes ssh-ed25519\n IdentityFile /root/.ssh/nixbuild\n IdentitiesOnly yes\n' | sudo tee /root/.ssh/config >/dev/null
82- printf 'eu.nixbuild.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIQCZc54poJ8vqawd8TraNryQeJnvH1eLpIDgbiqymM\n' | sudo tee /root/.ssh/known_hosts >/dev/null
83- # nixbuild's paths are signed, but the key is per-account and only
84- # readable from its web UI, so rather than carry a second secret we
85- # lean on the transport — the store is reached over SSH with our own
86- # key. cache.nixos.org is verified by its own key either way;
87- # require-sigs only relaxes nixbuild.
88- sudo tee -a /etc/nix/nix.conf >/dev/null <<EOF
89- builders = ssh-ng://eu.nixbuild.net x86_64-linux - 16 1 big-parallel,benchmark
90- builders-use-substitutes = true
91- substituters = https://cache.nixos.org ssh-ng://eu.nixbuild.net?priority=50
92- require-sigs = false
93- max-jobs = $(nproc)
94- EOF
95- # Only if there IS a daemon. The runner's installer says
96- # "installing Nix as root is not supported by this script" and falls
97- # back to a SINGLE-USER install, so there is no nix-daemon to
98- # restart and no systemctl in the image to try — an unconditional
99- # restart here exited 127 and took the job with it.
100- #
101- # Which install it is decides two things, and they happen to agree.
102- # A daemon reads nix.conf once at start, so appended settings need
103- # the restart; a single-user client reads it per invocation, so they
104- # are live immediately. And the process opening the SSH connection
105- # is root either way — the daemon in one case, this job in the
106- # other — so the key belongs in /root/.ssh regardless.
107- if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet nix-daemon; then
108- sudo systemctl restart nix-daemon
109- else
110- echo "single-user nix: nix.conf is read per invocation, nothing to restart"
111- fi
112- # Printed rather than assumed. If the builder is not set here, every
113- # derivation below is built on this runner, and the first symptom of
114- # that is not an error — it is three hours of compiling libcosmic.
115- nix config show builders
116- nix config show max-jobs
117-
118- # fmt, clippy and the test suite, plus all four desktop objects — the
119- # checks build them. This is the step that has historically failed, and
120- # it fails fast: fmt costs seconds and runs before anything is compiled.
121- - run: nix flake check -L
122-
123- # Store paths are read-only symlink farms; the runner uploads plain
124- # files, so dereference them into trees it can zip.
125- - name: Stage the objects
126- run: |
127- set -eu
128- nix build -L --no-link --print-out-paths .#libs .#android > /tmp/outs
129- mkdir -p artifacts && xargs -a /tmp/outs -I{} cp -rL {}/. artifacts/
130- # Staged beside artifacts/ and not into it: libsPortable holds the
131- # same four sonames with a different RUNPATH, so merging the two
132- # trees would leave whichever was copied last under both names.
133- nix build -L --no-link --print-out-paths .#libsPortable > /tmp/portable
134- mkdir -p portable && xargs -a /tmp/portable -I{} cp -rL {}/. portable/
135-
136- # The same three tarballs GitLab publishes, rooted at lib/ and include/
137- # so a consumer's `flake = false` input resolves to ${input}/lib/… with
138- # nothing in between. Here they are only artifacts of the run — see the
139- # note at the top about why this host does not upload them anywhere.
140- - name: Tar them the way a consumer takes them
141- run: |
142- set -eu
143- tar czf x86_64-linux.tar.gz -C artifacts include \
144- lib/libvidya.so lib/libjolttui.so lib/libjoltmoq.so lib/libjoltcosmic.so
145- # `-C portable lib include` and not a file list: the point of this one
146- # is the libraries that came along, and naming the four we know about
147- # would drop them.
148- tar czf x86_64-linux-portable.tar.gz -C portable lib include
149- tar czf android-arm64-v8a.tar.gz -C artifacts include lib/arm64-v8a
150-
151- - uses: actions/upload-artifact@v4
152- with:
153- name: jolt-native-${{ github.sha }}
154- path: |
155- x86_64-linux.tar.gz
156- x86_64-linux-portable.tar.gz
157- android-arm64-v8a.tar.gz
158- if-no-files-found: error
deleted file mode 100644
@@ -1,158 +0,0 @@
1-# The build, on rickub. The same `nix flake check` and the same three objects
2-# GitLab builds next door, for the case where a push reaches this host and not
3-# that one.
4-#
5-# It does not compile here, and could not: a rickub runner is a Linux x86-64
6-# container, and this graph is ~800 vendored crates behind libcosmic, iced,
7-# wgpu and aws-lc-sys. What the runner does is evaluate, dispatch and fetch —
8-# eu.nixbuild.net holds every vendor path from previous runs and does the
9-# compiling, exactly as it does for GitLab. So the two hosts share a cache
10-# rather than duplicating an hour of work, and a warm pipeline here is a
11-# pipeline that mostly substitutes.
12-#
13-# What it deliberately does NOT do is publish. The tarballs go to GitLab's
14-# generic package registry, and the token for that is CI_JOB_TOKEN — a GitLab
15-# job's own credential, issued to the job, not something to mint and carry
16-# here as a long-lived secret. One publisher and one place a consumer pins
17-# from is also just simpler to reason about than two. This host builds, checks
18-# and hands the tarballs back as run artifacts; `main` on GitLab is what moves
19-# `latest`.
20-#
21-# Lives in .rickub/workflows/ rather than .github/workflows/ because rickub
22-# reads one or the other and never both — see
23-# https://rickub.com/docs/actions and https://rickub.com/docs/migrating-from-github
24-name: build
25-
26-on:
27- push:
28- pull_request:
29- workflow_dispatch:
30-
31-jobs:
32- check:
33- runs-on: ubuntu-latest
34- # A cold run vendors the world and compiles the workspace. The builder does
35- # the compiling, but this side waits on it, and waits on the fetch of what
36- # comes back. GitLab gives the same job 3h.
37- timeout-minutes: 180
38- steps:
39- # The flake is fetched from the checkout, and nix wants the git tree
40- # rather than a shallow single commit to resolve `self` from.
41- - uses: actions/checkout@v4
42- with:
43- fetch-depth: 0
44-
45- - uses: cachix/install-nix-action@v27
46- with:
47- extra_nix_config: |
48- experimental-features = nix-command flakes
49-
50- # Everything the GitLab job's before_script sets up, and for the same
51- # reasons — the comments there are the long version. The short one:
52- #
53- # max-jobs must NOT be zero. At zero the runner refuses to build
54- # anything at all, which sends the fixed-output fetches (rust
55- # toolchain tarballs, every crate source) to nixbuild, where the build
56- # sandbox has no network and they can only fail. nproc keeps those and
57- # crane's hundreds of trivial cargo-src derivations local and parallel;
58- # the expensive builds still go remote.
59- #
60- # The explicit priority on nixbuild matters. nix picks a substituter by
61- # priority rather than by the order listed, and an ssh-ng store
62- # defaults to 0 against cache.nixos.org's 40 — so without it nixbuild
63- # wins even for stock nixpkgs paths and they crawl down one SSH
64- # connection instead of coming off the CDN.
65- #
66- # Keep the builder's job count modest: nixbuild's sshd caps concurrent
67- # sessions and refuses the excess, which nix reports as the thoroughly
68- # misleading "Nix daemon disconnected unexpectedly (maybe it crashed?)".
69- - name: Point nix at eu.nixbuild.net
70- env:
71- NIXBUILD_SSH_KEY: ${{ secrets.NIXBUILD_SSH_KEY }}
72- run: |
73- set -eu
74- # ROOT's ~/.ssh. The GitLab job runs as root in a nixos/nix image and
75- # needs no such care; here the step below decides which install this
76- # is, and root is the answer either way — see the note there.
77- sudo mkdir -p /root/.ssh
78- # base64 because a CI variable can only carry a single line.
79- printf '%s' "$NIXBUILD_SSH_KEY" | base64 -d | sudo tee /root/.ssh/nixbuild >/dev/null
80- sudo chmod 600 /root/.ssh/nixbuild
81- printf 'Host eu.nixbuild.net\n PubkeyAcceptedKeyTypes ssh-ed25519\n IdentityFile /root/.ssh/nixbuild\n IdentitiesOnly yes\n' | sudo tee /root/.ssh/config >/dev/null
82- printf 'eu.nixbuild.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIQCZc54poJ8vqawd8TraNryQeJnvH1eLpIDgbiqymM\n' | sudo tee /root/.ssh/known_hosts >/dev/null
83- # nixbuild's paths are signed, but the key is per-account and only
84- # readable from its web UI, so rather than carry a second secret we
85- # lean on the transport — the store is reached over SSH with our own
86- # key. cache.nixos.org is verified by its own key either way;
87- # require-sigs only relaxes nixbuild.
88- sudo tee -a /etc/nix/nix.conf >/dev/null <<EOF
89- builders = ssh-ng://eu.nixbuild.net x86_64-linux - 16 1 big-parallel,benchmark
90- builders-use-substitutes = true
91- substituters = https://cache.nixos.org ssh-ng://eu.nixbuild.net?priority=50
92- require-sigs = false
93- max-jobs = $(nproc)
94- EOF
95- # Only if there IS a daemon. The runner's installer says
96- # "installing Nix as root is not supported by this script" and falls
97- # back to a SINGLE-USER install, so there is no nix-daemon to
98- # restart and no systemctl in the image to try — an unconditional
99- # restart here exited 127 and took the job with it.
100- #
101- # Which install it is decides two things, and they happen to agree.
102- # A daemon reads nix.conf once at start, so appended settings need
103- # the restart; a single-user client reads it per invocation, so they
104- # are live immediately. And the process opening the SSH connection
105- # is root either way — the daemon in one case, this job in the
106- # other — so the key belongs in /root/.ssh regardless.
107- if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet nix-daemon; then
108- sudo systemctl restart nix-daemon
109- else
110- echo "single-user nix: nix.conf is read per invocation, nothing to restart"
111- fi
112- # Printed rather than assumed. If the builder is not set here, every
113- # derivation below is built on this runner, and the first symptom of
114- # that is not an error — it is three hours of compiling libcosmic.
115- nix config show builders
116- nix config show max-jobs
117-
118- # fmt, clippy and the test suite, plus all four desktop objects — the
119- # checks build them. This is the step that has historically failed, and
120- # it fails fast: fmt costs seconds and runs before anything is compiled.
121- - run: nix flake check -L
122-
123- # Store paths are read-only symlink farms; the runner uploads plain
124- # files, so dereference them into trees it can zip.
125- - name: Stage the objects
126- run: |
127- set -eu
128- nix build -L --no-link --print-out-paths .#libs .#android > /tmp/outs
129- mkdir -p artifacts && xargs -a /tmp/outs -I{} cp -rL {}/. artifacts/
130- # Staged beside artifacts/ and not into it: libsPortable holds the
131- # same four sonames with a different RUNPATH, so merging the two
132- # trees would leave whichever was copied last under both names.
133- nix build -L --no-link --print-out-paths .#libsPortable > /tmp/portable
134- mkdir -p portable && xargs -a /tmp/portable -I{} cp -rL {}/. portable/
135-
136- # The same three tarballs GitLab publishes, rooted at lib/ and include/
137- # so a consumer's `flake = false` input resolves to ${input}/lib/… with
138- # nothing in between. Here they are only artifacts of the run — see the
139- # note at the top about why this host does not upload them anywhere.
140- - name: Tar them the way a consumer takes them
141- run: |
142- set -eu
143- tar czf x86_64-linux.tar.gz -C artifacts include \
144- lib/libvidya.so lib/libjolttui.so lib/libjoltmoq.so lib/libjoltcosmic.so
145- # `-C portable lib include` and not a file list: the point of this one
146- # is the libraries that came along, and naming the four we know about
147- # would drop them.
148- tar czf x86_64-linux-portable.tar.gz -C portable lib include
149- tar czf android-arm64-v8a.tar.gz -C artifacts include lib/arm64-v8a
150-
151- - uses: actions/upload-artifact@v4
152- with:
153- name: jolt-native-${{ github.sha }}
154- path: |
155- x86_64-linux.tar.gz
156- x86_64-linux-portable.tar.gz
157- android-arm64-v8a.tar.gz
158- if-no-files-found: error