worklyn / zukapublic
Agent-first git hosting. One Rust binary: git over HTTP and SSH, a REST API, MCP, CI, and multi-tenant isolation.
Get a copy:
git clone https://zuka.worklyn.com/worklyn/zuka.git
| 1 | # zuka builds and deploys itself. |
| 2 | # |
| 3 | # This runs on the build instance — a second zuka on the same host, separate from the |
| 4 | # control plane. That separation is not tidiness: the last step restarts the control |
| 5 | # plane, and a build running inside the thing it restarts would kill itself half way |
| 6 | # through its own deploy. |
| 7 | |
| 8 | [run] |
| 9 | # A cold Rust build plus the live suite on two cores. The default 600s is not close |
| 10 | # to enough, and a timeout that trips on a clean build teaches everyone to ignore red. |
| 11 | timeout_secs = 2400 |
| 12 | |
| 13 | steps = [ |
| 14 | # Cheapest first: formatting and lints fail in seconds, so a badly formatted commit |
| 15 | # does not occupy the host for twenty minutes before saying so. |
| 16 | "cargo fmt --check", |
| 17 | |
| 18 | # CARGO_TARGET_DIR on every cargo step, because each run gets a fresh workspace and |
| 19 | # a target directory inside it would be thrown away — making every build a cold |
| 20 | # twenty-five minute one. Cargo locks this directory, so concurrent runs queue |
| 21 | # rather than corrupt each other. |
| 22 | "CARGO_TARGET_DIR=/var/lib/zuka-build/target cargo clippy --all-targets -- -D warnings", |
| 23 | "CARGO_TARGET_DIR=/var/lib/zuka-build/target cargo test", |
| 24 | |
| 25 | # musl, statically linked. The host runs glibc 2.39 and the tenant containers 2.36, |
| 26 | # so a glibc build made here will not start in a container. One static binary runs |
| 27 | # in both places, which is what lets the control plane and its tenants be the same |
| 28 | # build. |
| 29 | "CARGO_TARGET_DIR=/var/lib/zuka-build/target cargo build --release --target x86_64-unknown-linux-musl", |
| 30 | |
| 31 | # The live suite is where the wire protocol and the REST contract are actually |
| 32 | # proven. It self-skips without ZUKA_LIVE_TEST, which the task sets, and a proof |
| 33 | # that never runs is not one. |
| 34 | # |
| 35 | # Pointed at the musl binary built above, because that is the exact file the deploy |
| 36 | # step ships. Exercising a separate glibc build and then shipping this one would |
| 37 | # prove nothing about what actually runs. |
| 38 | "ZUKA_TEST_BINARY=/var/lib/zuka-build/target/x86_64-unknown-linux-musl/release/zuka deno task test:live", |
| 39 | |
| 40 | # Hand the binary to root and ask for a deploy, but only from main. |
| 41 | # |
| 42 | # The guard and the deploy are one step on purpose: `exit 0` only ends its own |
| 43 | # step, so a guard in a step of its own would skip nothing and every branch would |
| 44 | # deploy. |
| 45 | # |
| 46 | # CI holds no privilege and cannot deploy by itself. It writes the binary and a |
| 47 | # request file; a root systemd.path unit notices the request and runs the deploy, |
| 48 | # which restarts the service, checks that the new build is the one answering, and |
| 49 | # puts the old binary back if it is not. The result comes back through a file so a |
| 50 | # failed deploy still turns this run red — a build that goes green while the deploy |
| 51 | # quietly failed is worse than not deploying at all. |
| 52 | ''' |
| 53 | set -eu |
| 54 | BIN=/var/lib/zuka-build/target/x86_64-unknown-linux-musl/release/zuka |
| 55 | BUILD=$("$BIN" version | awk '{print $NF}') |
| 56 | |
| 57 | if [ "$ZUKA_REF" != refs/heads/main ]; then |
| 58 | echo "$ZUKA_REF is not main - built and tested $BUILD, not deploying" |
| 59 | exit 0 |
| 60 | fi |
| 61 | |
| 62 | S=/var/lib/zuka-build/staging |
| 63 | mkdir -p "$S" |
| 64 | # Clear the previous run's answer first, or a stale OK would be read as this |
| 65 | # deploy succeeding before root has even started. |
| 66 | rm -f "$S/deploy.result" |
| 67 | cp "$BIN" "$S/zuka" |
| 68 | echo "$BUILD" > "$S/deploy.request" |
| 69 | echo "requested deploy of $BUILD" |
| 70 | |
| 71 | n=0 |
| 72 | while [ "$n" -lt 180 ]; do |
| 73 | if [ -f "$S/deploy.result" ]; then |
| 74 | R=$(cat "$S/deploy.result") |
| 75 | echo "$R" |
| 76 | case "$R" in |
| 77 | "OK $BUILD"*) exit 0 ;; |
| 78 | OK*) echo "a different build was deployed; expected $BUILD"; exit 1 ;; |
| 79 | *) exit 1 ;; |
| 80 | esac |
| 81 | fi |
| 82 | sleep 2 |
| 83 | n=$((n + 2)) |
| 84 | done |
| 85 | echo "no deploy result after 180s" |
| 86 | exit 1 |
| 87 | ''', |
| 88 | ] |