From f8b49b2a93f08dbf90451d7e11e233c0bffb6b0d Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 20 Jul 2026 16:13:41 +0100 Subject: [PATCH 01/19] workflows use new runner --- .github/workflows/check.yml | 101 ++----- .github/workflows/deploy.yml | 29 +- .github/workflows/extension.yml | 15 +- flake.lock | 131 ++++++++- flake.nix | 77 +++-- nix/README.md | 107 +++++++ nix/runner/age.nix | 21 ++ nix/runner/default.nix | 48 +++ nix/runner/disko.nix | 37 +++ nix/runner/github.nix | 66 +++++ nix/runner/hardware-configuration.nix | 3 + nix/runner/secrets/secrets.nix | 21 ++ packages/coln-js-runtime/justfile | 4 +- packages/coln-js-runtime/package.json | 6 +- packages/coln-js-runtime/pnpm-lock.yaml | 293 +++++++++++++++++++ packages/coln-js-runtime/pnpm-workspace.yaml | 2 + 16 files changed, 812 insertions(+), 149 deletions(-) create mode 100644 nix/README.md create mode 100644 nix/runner/age.nix create mode 100644 nix/runner/default.nix create mode 100644 nix/runner/disko.nix create mode 100644 nix/runner/github.nix create mode 100644 nix/runner/hardware-configuration.nix create mode 100644 nix/runner/secrets/secrets.nix create mode 100644 packages/coln-js-runtime/pnpm-workspace.yaml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a2d0039f..1c347b49 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,3 +1,4 @@ + on: pull_request: merge_group: @@ -8,131 +9,71 @@ name: Check jobs: license-check: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Nix ❄️ - uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-26.05 - - name: Check licenses - run: | - nix-env -i just reuse -f '' - just check-licenses + run: just check-licenses rust-fmt: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - components: rustfmt - - name: Check formatting run: cargo fmt --check rust-clippy: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - components: clippy - - name: Run Clippy run: cargo clippy --all-targets -- -D warnings rust-tests: - runs-on: ubuntu-latest - needs: [rust-fmt, rust-clippy] + runs-on: coln-runner + # needs: [rust-fmt, rust-clippy] steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - - - name: Install nextest - uses: taiki-e/install-action@nextest - - - name: Install just - uses: extractions/setup-just@v3 - - name: Run tests run: just check-rust coln-js-runtime-check: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - target: wasm32-unknown-unknown - - - name: Install nextest - uses: taiki-e/install-action@nextest - - - name: Install wasm-bindgen-cli - run: | - VERSION="0.2.123" - curl -sSL "https://github.com/wasm-bindgen/wasm-bindgen/releases/download/$VERSION/wasm-bindgen-$VERSION-x86_64-unknown-linux-musl.tar.gz" | tar xz - sudo mv "wasm-bindgen-$VERSION-x86_64-unknown-linux-musl/wasm-bindgen" /usr/local/bin/ - wasm-bindgen --version - - - name: Install wasm-opt - run: | - VERSION="version_124" - curl -sSL "https://github.com/WebAssembly/binaryen/releases/download/$VERSION/binaryen-$VERSION-x86_64-linux.tar.gz" | tar xz - sudo mv "binaryen-$VERSION/bin/wasm-opt" /usr/local/bin/ - wasm-opt --version - - - name: Install wasm-bodge - run: cargo install wasm-bodge --locked - - - name: Install just - uses: extractions/setup-just@v3 - - - name: Install Node - uses: actions/setup-node@v4 - with: - node-version: 24 - cache: npm - cache-dependency-path: packages/coln-js-runtime/package-lock.json - - name: Install npm dependencies working-directory: packages/coln-js-runtime - run: npm ci + run: pnpm ci - - name: Run checks + - name: Rust Checks working-directory: packages/coln-js-runtime - run: just check + run: just test-rust + + - name: JS Checks + working-directory: packages/coln-js-runtime + run: just test-npm haskell-tests: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Nix ❄️ - uses: cachix/install-nix-action@v31 - - - name: Set up Cachix ♻️ - uses: cachix/cachix-action@v17 - with: - name: coln - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + # - name: Set up Cachix ♻️ + # uses: cachix/cachix-action@v17 + # with: + # name: coln + # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - name: Formatting (.hs) run: nix build .#format-hs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 70ecd16c..57cc5dd6 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,28 +7,25 @@ name: Deploy jobs: deploy-manual: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Nix ❄️ - uses: cachix/install-nix-action@v31 - - - name: Set up Cachix ♻️ - uses: cachix/cachix-action@v17 - with: - name: coln - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + # - name: Set up Cachix ♻️ + # uses: cachix/cachix-action@v17 + # with: + # name: coln + # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - name: Build manual run: nix build .#manual - - name: Deploy manual - uses: peaceiris/actions-gh-pages@v4 - with: - deploy_key: ${{ secrets.COLN_WEBSITE_DEPLOY_KEY }} - external_repository: coln-project/coln-project.github.io - publish_branch: main - publish_dir: ./result + # - name: Deploy manual + # uses: peaceiris/actions-gh-pages@v4 + # with: + # deploy_key: ${{ secrets.COLN_WEBSITE_DEPLOY_KEY }} + # external_repository: coln-project/coln-project.github.io + # publish_branch: main + # publish_dir: ./result diff --git a/.github/workflows/extension.yml b/.github/workflows/extension.yml index 8eb3b022..0dad0998 100644 --- a/.github/workflows/extension.yml +++ b/.github/workflows/extension.yml @@ -7,20 +7,17 @@ name: VSCode Extension jobs: vscode-extension: - runs-on: ubuntu-latest + runs-on: coln-runner steps: - name: Checkout ⬇️ uses: actions/checkout@v6 - - name: Install Nix ❄️ - uses: cachix/install-nix-action@v31 - - - name: Set up Cachix ♻️ - uses: cachix/cachix-action@v17 - with: - name: coln - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + # - name: Set up Cachix ♻️ + # uses: cachix/cachix-action@v17 + # with: + # name: coln + # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - name: Build extension run: | diff --git a/flake.lock b/flake.lock index 145fa01a..9b311f65 100644 --- a/flake.lock +++ b/flake.lock @@ -1,9 +1,72 @@ { "nodes": { - "flake-utils": { + "agenix": { "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": "nixpkgs", "systems": "systems" }, + "locked": { + "lastModified": 1770165109, + "narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=", + "owner": "ryantm", + "repo": "agenix", + "rev": "b027ee29d959fda4b60b57566d64c98a202e0feb", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1781152676, + "narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=", + "owner": "nix-community", + "repo": "disko", + "rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_2" + }, "locked": { "lastModified": 1731533236, "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", @@ -20,7 +83,7 @@ }, "flake-utils_2": { "inputs": { - "systems": "systems_2" + "systems": "systems_3" }, "locked": { "lastModified": 1731533236, @@ -39,7 +102,7 @@ "ghc-wasm-meta": { "inputs": { "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2" }, "locked": { "host": "gitlab.haskell.org", @@ -57,7 +120,44 @@ "type": "gitlab" } }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, "nixpkgs": { + "locked": { + "lastModified": 1754028485, + "narHash": "sha256-IiiXB3BDTi6UqzAZcf2S797hWEPCRZOwyNThJIYhUfk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "59e69648d345d6e8fef86158c555730fa12af9de", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1781472460, "narHash": "sha256-dqwpb1o0xIwb1rv3PPbpY7RBm8heFiOLAubszNLBefc=", @@ -73,7 +173,7 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs_3": { "locked": { "lastModified": 1780145889, "narHash": "sha256-md0zn0RnwNvPyASas1yG5YUuwQ4ALA6ucL50l0DvqCo=", @@ -89,7 +189,7 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_4": { "locked": { "lastModified": 1744536153, "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", @@ -107,15 +207,17 @@ }, "root": { "inputs": { + "agenix": "agenix", + "disko": "disko", "flake-utils": "flake-utils", "ghc-wasm-meta": "ghc-wasm-meta", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "rust-overlay": "rust-overlay" } }, "rust-overlay": { "inputs": { - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1782184651, @@ -160,6 +262,21 @@ "repo": "default", "type": "github" } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 860d0be0..0220d0c5 100644 --- a/flake.nix +++ b/flake.nix @@ -1,9 +1,15 @@ +# trivial { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; flake-utils.url = "github:numtide/flake-utils"; rust-overlay.url = "github:oxalica/rust-overlay"; ghc-wasm-meta.url = "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org"; + agenix.url = "github:ryantm/agenix"; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs@{ @@ -139,6 +145,11 @@ format-hs = nuShellCheck [pkgs.fourmolu] ./nix/checks/format-hs.nu; format-cabal = nuShellCheck [pkgs.haskellPackages.cabal-gild] ./nix/checks/format-cabal.nu; + nixosConfigurations.github-runner = inputs.nixpkgs.lib.nixosSystem { + modules = [./nix/runner]; + specialArgs = {agenix = inputs.agenix; disko = inputs.disko; inherit shellInputs; }; + }; + manual = pkgs.stdenv.mkDerivation { name = "coln-manual"; @@ -199,6 +210,39 @@ npmRoot = lsTsDir; nodejs = pkgs.nodejs_24; }; + + shellInputs = with pkgs; [ + inputs.agenix.packages.${system}.agenix + cabal-install + cabal2nix + cargo-llvm-cov + coln-manual-dev + forester + fourmolu + esbuild + haskell-wasm.wasm32-wasi-ghc-9_14 + haskell-wasm.wasm32-wasi-cabal-9_14 + haskell.compiler.ghc912 + haskell.packages.ghc912.haskell-language-server + haskellPackages.cabal-gild + jq + just + nodejs_24 + pnpm + packages.wasm-bodge + rustToolchain + packages.wasm-bindgen-cli + binaryen + openssl + pkg-config + reuse + simple-http-server + tectonic + typescript + vtsls + zlib + zlib.dev + ]; in { inherit packages; @@ -213,38 +257,7 @@ }; devShells.default = pkgs.mkShell { name = "coln"; - buildInputs = with pkgs; [ - cabal-install - cabal2nix - cargo-llvm-cov - cargo-nextest - coln-manual-dev - forester - fourmolu - esbuild - haskell-wasm.wasm32-wasi-ghc-9_14 - haskell-wasm.wasm32-wasi-cabal-9_14 - haskell.compiler.ghc912 - haskell.packages.ghc912.haskell-language-server - haskellPackages.cabal-gild - jq - just - nodejs_24 - pnpm - packages.wasm-bodge - rustToolchain - packages.wasm-bindgen-cli - binaryen - openssl - pkg-config - reuse - simple-http-server - tectonic - typescript - vtsls - zlib - zlib.dev - ]; + buildInputs = shellInputs; shellHook = '' # GCC 15 (nixos-26.05) defaults to -std=gnu23 which removed ATOMIC_VAR_INIT. # This breaks mimalloc-rust-sys, which is a dependency of dbsp. diff --git a/nix/README.md b/nix/README.md new file mode 100644 index 00000000..b0088ce6 --- /dev/null +++ b/nix/README.md @@ -0,0 +1,107 @@ +# Coln NixOS Runner +A NixOS configuration for a self-hosted github server for the Coln repo. The configuration supports spawning $n$ workers. + +# Setup +The configuration uses `agenix` to provision secrets. The configuration provision s the following: + +- *PAT Token* : For github. Provides read/write access to the Coln repository and the ability to run actions. Stored in `runner-token.age`. +- *Wifi Passwords* : Wifi is managed declaratively, with wifi ssid/password in `wifi.age` +- **[OPTIONAL]** *Root user password* : Set in `root-pass.age` +- **[OPTIONAL]** *Root user ssh key* : Set in `root-user-ssh.age` + +The runner won't be functional without the first two of these. + +## `agenix` Setup +Additionally before we can even think about secrets we need to make sure that agenix can decrypt them on the target. This requires knowing both: + +- *Host user ssh public key* (`~/.ssh/.pub`) : So that we can read/write secrets on the host. +- *Target host ssh public key* (`/etc/ssh/ssh_host_ed25519_key.pub`) : So that the target can decrypt secrets on boot. + +Once knowing these we can add these public keys to `secrets.nix` so that they can read/written to by those users: + +```nix +let + + # users + host-user = ""; + users = [host-user]; + + # systems + target-system = ""; + systems = [target-system]; + + all = users ++ systems; + +in +{ + ... +} +``` + +Which will then allow us to create files via `agenix -e `. + +## PAT Token +After generating a classic github PAT token via [this](https://github.com/settings/tokens) link and entitling it to repo permissions (only this is necessary), the token can be encrypted to a file via `agenix -e runner-token.age` in the `secrets` directory. Paste the token into the file. + +## Wifi Passwords +Wifi management is declarative. Adding a network consists of two parts: + +1. Adding the SSID to the expression in `networking.wireless.networks` in `default.nix`: + ```nix + networks = builtins.listToAttrs + (map (name: { inherit name; value.pskRaw = "ext:PSK_${name}"; }) + [""]); + ``` +2. Adding the SSID:Password pair to `secrets/wifi.age`. Run `agenix -e wifi.age` in `secrets` and add a single line: + ```txt + PSK_= + ``` + So a network with SSID `mynetwork` and password `mypassword` would correspond to a line: + ```txt + PSK_mynetwork=mypassword + ``` + +## Root user +Additionally the machine currently sets up only one user, the `root` user. The password and user ssh keys for this are managed declaratively. + +### Root user password +If you wish to declaratively configure a root password you can do so by generating a hashed password via `mkpasswd`: +```sh +mkpasswd -m sha-512 | wl-copy # generate a hashed password +cd secrets +agenix -e root-pass.age # paste hashed password +``` +### Root ssh key +Additionally if you want to provision the root user with an ssh key you can do so by generating a pair of keys and copying the following files: + +- *Public Key* to `secrets/root-user-ssh.pub` +- *Private Key* to `secrets/root-user-ssh.age` via `agenix -e root-user-ssh.age` + +# Execution +> [!NOTE] +> Text of the form `$` points to a configurable variable in `github.nix` + +The configuration spawns $n =$`$workers` runners on startup. These are each run in their own directory under the root `$dirRoot`, with name `coln-runner-` where $x \in \{1, \cdots , n\}$. Each of these runners share a cache directory `.cache` living under `$dirRoot`. Cargo build artefacts are stored here. + +```txt +dirRoot/ +├── cache/ +│ ├── .cache/ +│ │ └── nix/ (XDG_CACHE_HOME - nix cache) +│ ├── cargo-home/ (CARGO_HOME - crate registry/downloads) +│ └── cargo-target/ (CARGO_TARGET_DIR - compiled artifacts) +├── coln-runner-1/ +│ └── (workDir - job checkout and execution) +├── coln-runner-2/ +│ └── (workDir - job checkout and execution) +├── coln-runner-3/ +│ └── (workDir - job checkout and execution) +│ ... +└── coln-runner-N/ + └── (workDir - job checkout and execution) +``` + +## Configurable Variables +- `workers` : The number of runners to spawn +- `rootDir` : The directory in which to store cache/workers + diff --git a/nix/runner/age.nix b/nix/runner/age.nix new file mode 100644 index 00000000..614db6b9 --- /dev/null +++ b/nix/runner/age.nix @@ -0,0 +1,21 @@ +{agenix, ...}:{ + imports = [agenix.nixosModules.default]; + + config = { + age.secrets = { + wifi = { + file = ./secrets/wifi.age; + mode = "0440"; + group = "wpa_supplicant"; + }; + root-pass.file = ./secrets/root-pass.age; + runner-token.file = ./secrets/runner-token.age; + root-user-ssh = { + file = ./secrets/root-user-ssh.age; + path = "/root/.ssh/id_ed25519"; + owner = "root"; + mode = "0600"; + }; + }; + }; +} diff --git a/nix/runner/default.nix b/nix/runner/default.nix new file mode 100644 index 00000000..a4d99efd --- /dev/null +++ b/nix/runner/default.nix @@ -0,0 +1,48 @@ +{config, ...}:{ + imports = [ + ./hardware-configuration.nix + ./age.nix + ./disko.nix + ./github.nix + ]; + + config = { + nixpkgs.hostPlatform = "x86_64-linux"; + system.stateVersion = "25.05"; + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + nix.settings.experimental-features = ["nix-command" "flakes"]; + system.activationScripts.rootSshPubKey = '' + install -d -m 700 -o root -g root /root/.ssh + install -m 644 -o root -g root ${./secrets/root-user-ssh.pub} /root/.ssh/id_ed25519.pub + ''; + services.openssh.settings.PermitRootLogin = "yes"; + networking.hostName = "runner-server"; + services.avahi = { + enable = true; + publish = { + enable = true; + addresses = true; + }; + }; + users.users.root = { + hashedPasswordFile = config.age.secrets.root-pass.path; + }; + users.mutableUsers = false; + networking.wireless = { + enable = true; + interfaces = [ "wlp58s0" ]; + secretsFile = config.age.secrets.wifi.path; + networks = builtins.listToAttrs + (map (name: { inherit name; value.pskRaw = "ext:PSK_${name}"; }) + [""]); + }; + services.openssh.enable = true; + virtualisation.vmVariant = { + virtualisation = { + memorySize = 20000; # use 2048MiB memory + cores = 8; # use 3 cpu cores + }; + }; + }; +} diff --git a/nix/runner/disko.nix b/nix/runner/disko.nix new file mode 100644 index 00000000..763dea90 --- /dev/null +++ b/nix/runner/disko.nix @@ -0,0 +1,37 @@ +{disko, ...}:{ + imports = [disko.nixosModules.disko]; + config = { + disko.devices = { + disk = { + main = { + imageSize = "10G"; + device = "/dev/disk/by-id/ata-SK_hynix_SC311_SATA_256GB_MS82N176810802R0S"; + type = "disk"; + content = { + type = "gpt"; + partitions = { + ESP = { + type = "EF00"; + size = "500M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/nix/runner/github.nix b/nix/runner/github.nix new file mode 100644 index 00000000..ba4fe73b --- /dev/null +++ b/nix/runner/github.nix @@ -0,0 +1,66 @@ +{ + config, + pkgs, + lib, + shellInputs, + ... +}: +let + workers = 10; + rootDir = "/var/lib/coln-runner"; + cacheDir = "${rootDir}/cache"; + mkRunner = + name: + let + workDir = "${rootDir}/${name}"; + in + { + services.github-runners = { + ${name} = { + enable = true; + name = name; + replace = true; + tokenFile = config.age.secrets.runner-token.path; + tokenType = "access"; + url = "https://github.com/coln-project/Coln"; + extraPackages = with pkgs; [ curl git gcc openssl.dev ] ++ shellInputs; + extraEnvironment = { + OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib"; + OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include"; + CFLAGS = "-std=gnu17"; + XDG_CACHE_HOME = "${cacheDir}/.cache"; + CARGO_HOME = "${cacheDir}/cargo-home"; + CARGO_TARGET_DIR = "${cacheDir}/cargo-target"; + }; + serviceOverrides = { + ReadWritePaths = [ rootDir ]; + }; + workDir = "${workDir}"; + user = "coln-runner"; + noDefaultLabels = true; + extraLabels = [ "coln-runner" ]; + }; + }; + systemd.tmpfiles.rules = [ + "d ${workDir} 0755 coln-runner coln-runner -" + ]; + }; + runners = lib.mkMerge ( + map (n: mkRunner "coln-runner-${builtins.toString n}") (lib.range 1 workers) + ); +in +{ + config = lib.mkMerge [ + { + users.users.coln-runner = { + isSystemUser = true; + group = "coln-runner"; + }; + users.groups.coln-runner = { }; + systemd.tmpfiles.rules = [ + "d ${cacheDir} 0755 coln-runner coln-runner -" + ]; + } + runners + ]; +} diff --git a/nix/runner/hardware-configuration.nix b/nix/runner/hardware-configuration.nix new file mode 100644 index 00000000..6aa2eac1 --- /dev/null +++ b/nix/runner/hardware-configuration.nix @@ -0,0 +1,3 @@ +{ +# Generate me!!! +} diff --git a/nix/runner/secrets/secrets.nix b/nix/runner/secrets/secrets.nix new file mode 100644 index 00000000..4f3f35ad --- /dev/null +++ b/nix/runner/secrets/secrets.nix @@ -0,0 +1,21 @@ +let + + # users + host-user = ""; + users = [host-user]; + + # systems + target-system = ""; + systems = [target-system]; + + all = users ++ systems; + +in +{ + "root-pass.age".publicKeys = all; + "runner-token.age".publicKeys = all; + "wifi.age".publicKeys = all; + + # ssh user keys + "root-user-ssh.age".publicKeys = all; +} diff --git a/packages/coln-js-runtime/justfile b/packages/coln-js-runtime/justfile index 06952e81..103fbd70 100644 --- a/packages/coln-js-runtime/justfile +++ b/packages/coln-js-runtime/justfile @@ -15,10 +15,10 @@ test-rust: cargo test --doc -p {{crate}} build: - npm run build + pnpm run build test-npm: build - npm test + pnpm test test: test-rust test-npm diff --git a/packages/coln-js-runtime/package.json b/packages/coln-js-runtime/package.json index 1aff7990..5491dca5 100644 --- a/packages/coln-js-runtime/package.json +++ b/packages/coln-js-runtime/package.json @@ -15,9 +15,9 @@ "scripts": { "copy-license": "cp -r ../../LICENSES LICENSES", "build": "wasm-bodge build", - "test": "npm run test:unit && npm run test:basic-ir", + "test": "pnpm run test:unit && pnpm run test:basic-ir", "test:unit": "tsx --test tests/id-resolution.test.ts", - "test:basic-ir": "npm run typecheck:basic-ir && npm run test:basic-ir:runtime", + "test:basic-ir": "pnpm run typecheck:basic-ir && pnpm run test:basic-ir:runtime", "typecheck:basic-ir": "tsx --tsconfig tests/basic-ir/tsconfig.json --test tests/basic-ir/typecheck.ts", "test:basic-ir:runtime": "tsx --tsconfig tests/basic-ir/tsconfig.json --test \"tests/basic-ir/*.test.ts\"" }, @@ -121,4 +121,4 @@ "require": "./dist/cjs/slim.cjs" } } -} +} \ No newline at end of file diff --git a/packages/coln-js-runtime/pnpm-lock.yaml b/packages/coln-js-runtime/pnpm-lock.yaml index 1cc1be34..34df119d 100644 --- a/packages/coln-js-runtime/pnpm-lock.yaml +++ b/packages/coln-js-runtime/pnpm-lock.yaml @@ -11,15 +11,192 @@ importers: '@types/node': specifier: ^25.9.3 version: 25.9.3 + esbuild: + specifier: ^0.28.1 + version: 0.28.1 + tsx: + specifier: ^4.23.1 + version: 4.23.1 typescript: specifier: ^5.0.0 version: 5.9.3 packages: + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@types/node@25.9.3': resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + tsx@4.23.1: + resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} + engines: {node: '>=18.0.0'} + hasBin: true + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -30,10 +207,126 @@ packages: snapshots: + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + '@types/node@25.9.3': dependencies: undici-types: 7.24.6 + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + fsevents@2.3.3: + optional: true + + tsx@4.23.1: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + typescript@5.9.3: {} undici-types@7.24.6: {} diff --git a/packages/coln-js-runtime/pnpm-workspace.yaml b/packages/coln-js-runtime/pnpm-workspace.yaml new file mode 100644 index 00000000..49c0ad74 --- /dev/null +++ b/packages/coln-js-runtime/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +allowBuilds: + esbuild: false From 223cc3f28322f5b6459c597bc365bf811bacca28 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 27 Jul 2026 16:33:17 +0100 Subject: [PATCH 02/19] remove user setting config --- nix/runner/age.nix | 7 ------- nix/runner/default.nix | 9 --------- nix/runner/secrets/secrets.nix | 4 ---- 3 files changed, 20 deletions(-) diff --git a/nix/runner/age.nix b/nix/runner/age.nix index 614db6b9..f82ecc63 100644 --- a/nix/runner/age.nix +++ b/nix/runner/age.nix @@ -8,14 +8,7 @@ mode = "0440"; group = "wpa_supplicant"; }; - root-pass.file = ./secrets/root-pass.age; runner-token.file = ./secrets/runner-token.age; - root-user-ssh = { - file = ./secrets/root-user-ssh.age; - path = "/root/.ssh/id_ed25519"; - owner = "root"; - mode = "0600"; - }; }; }; } diff --git a/nix/runner/default.nix b/nix/runner/default.nix index a4d99efd..0efa2df2 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -12,11 +12,6 @@ boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; nix.settings.experimental-features = ["nix-command" "flakes"]; - system.activationScripts.rootSshPubKey = '' - install -d -m 700 -o root -g root /root/.ssh - install -m 644 -o root -g root ${./secrets/root-user-ssh.pub} /root/.ssh/id_ed25519.pub - ''; - services.openssh.settings.PermitRootLogin = "yes"; networking.hostName = "runner-server"; services.avahi = { enable = true; @@ -25,10 +20,6 @@ addresses = true; }; }; - users.users.root = { - hashedPasswordFile = config.age.secrets.root-pass.path; - }; - users.mutableUsers = false; networking.wireless = { enable = true; interfaces = [ "wlp58s0" ]; diff --git a/nix/runner/secrets/secrets.nix b/nix/runner/secrets/secrets.nix index 4f3f35ad..32236bd2 100644 --- a/nix/runner/secrets/secrets.nix +++ b/nix/runner/secrets/secrets.nix @@ -12,10 +12,6 @@ let in { - "root-pass.age".publicKeys = all; "runner-token.age".publicKeys = all; "wifi.age".publicKeys = all; - - # ssh user keys - "root-user-ssh.age".publicKeys = all; } From 3044ca3b52a9237e45f65e41bf1c6f6bf975eb95 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 27 Jul 2026 16:54:37 +0100 Subject: [PATCH 03/19] remove networking from default.nix --- nix/runner/default.nix | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/nix/runner/default.nix b/nix/runner/default.nix index 0efa2df2..e7d1c653 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -12,22 +12,6 @@ boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; nix.settings.experimental-features = ["nix-command" "flakes"]; - networking.hostName = "runner-server"; - services.avahi = { - enable = true; - publish = { - enable = true; - addresses = true; - }; - }; - networking.wireless = { - enable = true; - interfaces = [ "wlp58s0" ]; - secretsFile = config.age.secrets.wifi.path; - networks = builtins.listToAttrs - (map (name: { inherit name; value.pskRaw = "ext:PSK_${name}"; }) - [""]); - }; services.openssh.enable = true; virtualisation.vmVariant = { virtualisation = { From 83c07910a2515e94daa22654c4f0a8678033952f Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 27 Jul 2026 16:54:43 +0100 Subject: [PATCH 04/19] add wifi.nix --- nix/runner/wifi.nix | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 nix/runner/wifi.nix diff --git a/nix/runner/wifi.nix b/nix/runner/wifi.nix new file mode 100644 index 00000000..5a550599 --- /dev/null +++ b/nix/runner/wifi.nix @@ -0,0 +1,31 @@ +{ config, ... }: +{ + age.secrets.wifi = { + file = ./secrets/wifi.age; + mode = "0440"; + group = "wpa_supplicant"; + }; + networking.hostName = "runner-server"; + services.avahi = { + enable = true; + publish = { + enable = true; + addresses = true; + }; + }; + networking.wireless = { + enable = true; + interfaces = [ "wlp58s0" ]; + secretsFile = config.age.secrets.wifi.path; + networks = builtins.listToAttrs ( + map + (name: { + inherit name; + value.pskRaw = "ext:PSK_${name}"; + }) + [ + "" + ] + ); + }; +} From 60e462a76b24f54234565fd39d71965c63978af0 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 10:47:57 +0100 Subject: [PATCH 05/19] remove disk.nix --- nix/runner/default.nix | 1 - nix/runner/disko.nix | 37 ------------------------------------- 2 files changed, 38 deletions(-) delete mode 100644 nix/runner/disko.nix diff --git a/nix/runner/default.nix b/nix/runner/default.nix index e7d1c653..f99c7d3a 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -2,7 +2,6 @@ imports = [ ./hardware-configuration.nix ./age.nix - ./disko.nix ./github.nix ]; diff --git a/nix/runner/disko.nix b/nix/runner/disko.nix deleted file mode 100644 index 763dea90..00000000 --- a/nix/runner/disko.nix +++ /dev/null @@ -1,37 +0,0 @@ -{disko, ...}:{ - imports = [disko.nixosModules.disko]; - config = { - disko.devices = { - disk = { - main = { - imageSize = "10G"; - device = "/dev/disk/by-id/ata-SK_hynix_SC311_SATA_256GB_MS82N176810802R0S"; - type = "disk"; - content = { - type = "gpt"; - partitions = { - ESP = { - type = "EF00"; - size = "500M"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "umask=0077" ]; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; - }; - }; -} From 4729266034dfef1fda78d82d7a53e807ea0e226d Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 10:52:04 +0100 Subject: [PATCH 06/19] remove agenix module --- nix/runner/age.nix | 14 -------------- nix/runner/default.nix | 4 ++-- nix/runner/github.nix | 1 + 3 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 nix/runner/age.nix diff --git a/nix/runner/age.nix b/nix/runner/age.nix deleted file mode 100644 index f82ecc63..00000000 --- a/nix/runner/age.nix +++ /dev/null @@ -1,14 +0,0 @@ -{agenix, ...}:{ - imports = [agenix.nixosModules.default]; - - config = { - age.secrets = { - wifi = { - file = ./secrets/wifi.age; - mode = "0440"; - group = "wpa_supplicant"; - }; - runner-token.file = ./secrets/runner-token.age; - }; - }; -} diff --git a/nix/runner/default.nix b/nix/runner/default.nix index f99c7d3a..7bc364f9 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -1,7 +1,7 @@ -{config, ...}:{ +{agenix, ...}:{ imports = [ + agenix.nixosModules.default ./hardware-configuration.nix - ./age.nix ./github.nix ]; diff --git a/nix/runner/github.nix b/nix/runner/github.nix index ba4fe73b..a47e9d09 100644 --- a/nix/runner/github.nix +++ b/nix/runner/github.nix @@ -52,6 +52,7 @@ in { config = lib.mkMerge [ { + age.secrets.runner-token.file = ./secrets/runner-token.age; users.users.coln-runner = { isSystemUser = true; group = "coln-runner"; From 9bb04eb36636d28099d822d9763f18e2496169e4 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 10:55:38 +0100 Subject: [PATCH 07/19] remove hardware-configuration --- nix/runner/default.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/nix/runner/default.nix b/nix/runner/default.nix index 7bc364f9..6fe86637 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -1,7 +1,6 @@ {agenix, ...}:{ imports = [ agenix.nixosModules.default - ./hardware-configuration.nix ./github.nix ]; From 32f1efd0f34020d6a6b0ab709c275be454a01d48 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 10:56:26 +0100 Subject: [PATCH 08/19] add vm settings --- nix/runner/default.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nix/runner/default.nix b/nix/runner/default.nix index 6fe86637..f67c3597 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -11,10 +11,12 @@ boot.loader.efi.canTouchEfiVariables = true; nix.settings.experimental-features = ["nix-command" "flakes"]; services.openssh.enable = true; + + # VM Settings virtualisation.vmVariant = { virtualisation = { - memorySize = 20000; # use 2048MiB memory - cores = 8; # use 3 cpu cores + memorySize = 8000; + cores = 8; }; }; }; From 46d21f5cfd8fd6a7f87ded0d13b9df44f5cd2253 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 12:50:53 +0100 Subject: [PATCH 09/19] add README --- nix/README.md | 56 +++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/nix/README.md b/nix/README.md index b0088ce6..9423c1b9 100644 --- a/nix/README.md +++ b/nix/README.md @@ -1,18 +1,28 @@ # Coln NixOS Runner A NixOS configuration for a self-hosted github server for the Coln repo. The configuration supports spawning $n$ workers. +## What's included +This nix flake provides a nixos configuration with: + +- Secrets managed by [`agenix`](https://github.com/ryantm/agenix) +- A configurable expression to launch $n$ sandboxed github runners pointing to the `Coln` github repository + +## What isn't included +The nix flake doesn't: + +- Provide a `hardware-configuration.nix` +- Configure users +- Configure wifi (however an example `wifi.nix` is provided, with wifi secrets provisioned by `agenix`) + # Setup -The configuration uses `agenix` to provision secrets. The configuration provision s the following: +As mentioned above, the configuration uses `agenix` to provision secrets. As a minimum, the following need to be configured: - *PAT Token* : For github. Provides read/write access to the Coln repository and the ability to run actions. Stored in `runner-token.age`. -- *Wifi Passwords* : Wifi is managed declaratively, with wifi ssid/password in `wifi.age` -- **[OPTIONAL]** *Root user password* : Set in `root-pass.age` -- **[OPTIONAL]** *Root user ssh key* : Set in `root-user-ssh.age` -The runner won't be functional without the first two of these. +The runner won't be functional without this. ## `agenix` Setup -Additionally before we can even think about secrets we need to make sure that agenix can decrypt them on the target. This requires knowing both: +Agenix needs to be able to decrypt secrets on the target machine. This requires knowing the following before installation: - *Host user ssh public key* (`~/.ssh/.pub`) : So that we can read/write secrets on the host. - *Target host ssh public key* (`/etc/ssh/ssh_host_ed25519_key.pub`) : So that the target can decrypt secrets on boot. @@ -38,13 +48,20 @@ in } ``` -Which will then allow us to create files via `agenix -e `. +Which will then allow us to create encrypted files via `agenix -e `. ## PAT Token After generating a classic github PAT token via [this](https://github.com/settings/tokens) link and entitling it to repo permissions (only this is necessary), the token can be encrypted to a file via `agenix -e runner-token.age` in the `secrets` directory. Paste the token into the file. -## Wifi Passwords -Wifi management is declarative. Adding a network consists of two parts: +## Extras +As mentioned above. The configuration doesn't provide: + +- **Hardware Configuration** : This has to be generated by `nixos-generate-config` +- **User Config** : This needs to be configured manually +- **Wifi** : This needs to be configured manually + +### Wifi +For those interested in declarative Wifi management, a file `wifi.nix` is provided. SSID/passcode is stored in Adding a network consists of two parts: 1. Adding the SSID to the expression in `networking.wireless.networks` in `default.nix`: ```nix @@ -61,27 +78,11 @@ Wifi management is declarative. Adding a network consists of two parts: PSK_mynetwork=mypassword ``` -## Root user -Additionally the machine currently sets up only one user, the `root` user. The password and user ssh keys for this are managed declaratively. - -### Root user password -If you wish to declaratively configure a root password you can do so by generating a hashed password via `mkpasswd`: -```sh -mkpasswd -m sha-512 | wl-copy # generate a hashed password -cd secrets -agenix -e root-pass.age # paste hashed password -``` -### Root ssh key -Additionally if you want to provision the root user with an ssh key you can do so by generating a pair of keys and copying the following files: - -- *Public Key* to `secrets/root-user-ssh.pub` -- *Private Key* to `secrets/root-user-ssh.age` via `agenix -e root-user-ssh.age` - -# Execution +# Configuration > [!NOTE] > Text of the form `$` points to a configurable variable in `github.nix` -The configuration spawns $n =$`$workers` runners on startup. These are each run in their own directory under the root `$dirRoot`, with name `coln-runner-` where $x \in \{1, \cdots , n\}$. Each of these runners share a cache directory `.cache` living under `$dirRoot`. Cargo build artefacts are stored here. +The configuration provides an expression that spawns $n =$`$workers` runners on startup. These are each run in their own directory under the root `$dirRoot`, with name `coln-runner-` where $x \in \{1, \cdots , n\}$. Each of these runners share a cache directory `.cache` living under `$dirRoot`. Cargo build artefacts are stored here. ```txt dirRoot/ @@ -104,4 +105,3 @@ dirRoot/ ## Configurable Variables - `workers` : The number of runners to spawn - `rootDir` : The directory in which to store cache/workers - From ae1ca8e55c1897f17285bf8e2e25a6e85e7eefef Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 13:06:09 +0100 Subject: [PATCH 10/19] add coln cachix to trusted substituers --- .github/workflows/check.yml | 6 +++--- .github/workflows/deploy.yml | 2 +- .github/workflows/extension.yml | 2 +- nix/runner/default.nix | 6 +++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 1c347b49..95a0a2af 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -76,12 +76,12 @@ jobs: # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - name: Formatting (.hs) - run: nix build .#format-hs + run: nix build .#format-hs --accept-flake-config - name: Formatting (.cabal) - run: nix build .#format-cabal + run: nix build .#format-cabal --accept-flake-config - name: Haskell Tests run: | - RUN_CHECKS=$(nix build .#haskell-tests --no-link --print-out-paths) + RUN_CHECKS=$(nix build .#haskell-tests --no-link --print-out-paths --accept-flake-config) $RUN_CHECKS diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 57cc5dd6..3f967b51 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,7 +20,7 @@ jobs: # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - name: Build manual - run: nix build .#manual + run: nix build .#manual --accept-flake-config # - name: Deploy manual # uses: peaceiris/actions-gh-pages@v4 diff --git a/.github/workflows/extension.yml b/.github/workflows/extension.yml index 0dad0998..1b80ea3c 100644 --- a/.github/workflows/extension.yml +++ b/.github/workflows/extension.yml @@ -21,7 +21,7 @@ jobs: - name: Build extension run: | - nix build .#vscode-extension + nix build .#vscode-extension --accept-flake-config mv result coln-vscode-extension.vsix - name: Upload artefact diff --git a/nix/runner/default.nix b/nix/runner/default.nix index f67c3597..b68af853 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -9,7 +9,11 @@ system.stateVersion = "25.05"; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - nix.settings.experimental-features = ["nix-command" "flakes"]; + nix.settings = { + experimental-features = ["nix-command" "flakes"]; + trusted-substituters = [ "https://coln.cachix.org" ]; + trusted-public-keys = [ "coln.cachix.org-1:xplHZrvUVve3NSquwwW5QRl6MYbDBHx3rw3Np69kjw4=" ]; + }; services.openssh.enable = true; # VM Settings From d789f43e2a557d09aa8dc301c02feb1f0385e408 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Tue, 28 Jul 2026 13:14:05 +0100 Subject: [PATCH 11/19] Tidy up workflows --- .github/workflows/check.yml | 8 +------- .github/workflows/deploy.yml | 20 +++++++------------- .github/workflows/extension.yml | 6 ------ 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 95a0a2af..eff2e78f 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -36,7 +36,7 @@ jobs: rust-tests: runs-on: coln-runner - # needs: [rust-fmt, rust-clippy] + needs: [rust-fmt, rust-clippy] steps: - name: Checkout ⬇️ uses: actions/checkout@v6 @@ -69,12 +69,6 @@ jobs: - name: Checkout ⬇️ uses: actions/checkout@v6 - # - name: Set up Cachix ♻️ - # uses: cachix/cachix-action@v17 - # with: - # name: coln - # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - name: Formatting (.hs) run: nix build .#format-hs --accept-flake-config diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3f967b51..3daea2fc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -13,19 +13,13 @@ jobs: - name: Checkout ⬇️ uses: actions/checkout@v6 - # - name: Set up Cachix ♻️ - # uses: cachix/cachix-action@v17 - # with: - # name: coln - # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - name: Build manual run: nix build .#manual --accept-flake-config - # - name: Deploy manual - # uses: peaceiris/actions-gh-pages@v4 - # with: - # deploy_key: ${{ secrets.COLN_WEBSITE_DEPLOY_KEY }} - # external_repository: coln-project/coln-project.github.io - # publish_branch: main - # publish_dir: ./result + - name: Deploy manual + uses: peaceiris/actions-gh-pages@v4 + with: + deploy_key: ${{ secrets.COLN_WEBSITE_DEPLOY_KEY }} + external_repository: coln-project/coln-project.github.io + publish_branch: main + publish_dir: ./result diff --git a/.github/workflows/extension.yml b/.github/workflows/extension.yml index 1b80ea3c..59b99c84 100644 --- a/.github/workflows/extension.yml +++ b/.github/workflows/extension.yml @@ -13,12 +13,6 @@ jobs: - name: Checkout ⬇️ uses: actions/checkout@v6 - # - name: Set up Cachix ♻️ - # uses: cachix/cachix-action@v17 - # with: - # name: coln - # authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - name: Build extension run: | nix build .#vscode-extension --accept-flake-config From febe6d6ef435a279b5caf59f86bd1087440dcd95 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 3 Aug 2026 10:35:28 +0100 Subject: [PATCH 12/19] remove wifi.nix --- nix/README.md | 21 +-------------------- nix/runner/wifi.nix | 31 ------------------------------- 2 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 nix/runner/wifi.nix diff --git a/nix/README.md b/nix/README.md index 9423c1b9..bc434b53 100644 --- a/nix/README.md +++ b/nix/README.md @@ -12,7 +12,6 @@ The nix flake doesn't: - Provide a `hardware-configuration.nix` - Configure users -- Configure wifi (however an example `wifi.nix` is provided, with wifi secrets provisioned by `agenix`) # Setup As mentioned above, the configuration uses `agenix` to provision secrets. As a minimum, the following need to be configured: @@ -58,25 +57,7 @@ As mentioned above. The configuration doesn't provide: - **Hardware Configuration** : This has to be generated by `nixos-generate-config` - **User Config** : This needs to be configured manually -- **Wifi** : This needs to be configured manually - -### Wifi -For those interested in declarative Wifi management, a file `wifi.nix` is provided. SSID/passcode is stored in Adding a network consists of two parts: - -1. Adding the SSID to the expression in `networking.wireless.networks` in `default.nix`: - ```nix - networks = builtins.listToAttrs - (map (name: { inherit name; value.pskRaw = "ext:PSK_${name}"; }) - [""]); - ``` -2. Adding the SSID:Password pair to `secrets/wifi.age`. Run `agenix -e wifi.age` in `secrets` and add a single line: - ```txt - PSK_= - ``` - So a network with SSID `mynetwork` and password `mypassword` would correspond to a line: - ```txt - PSK_mynetwork=mypassword - ``` +- **Networking** : This needs to be configured manually # Configuration > [!NOTE] diff --git a/nix/runner/wifi.nix b/nix/runner/wifi.nix deleted file mode 100644 index 5a550599..00000000 --- a/nix/runner/wifi.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, ... }: -{ - age.secrets.wifi = { - file = ./secrets/wifi.age; - mode = "0440"; - group = "wpa_supplicant"; - }; - networking.hostName = "runner-server"; - services.avahi = { - enable = true; - publish = { - enable = true; - addresses = true; - }; - }; - networking.wireless = { - enable = true; - interfaces = [ "wlp58s0" ]; - secretsFile = config.age.secrets.wifi.path; - networks = builtins.listToAttrs ( - map - (name: { - inherit name; - value.pskRaw = "ext:PSK_${name}"; - }) - [ - "" - ] - ); - }; -} From ff06912ad95f0d72120b1afbaa618b23b0c9610c Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 3 Aug 2026 10:35:50 +0100 Subject: [PATCH 13/19] move README.md to correct directory --- nix/{ => runner}/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename nix/{ => runner}/README.md (100%) diff --git a/nix/README.md b/nix/runner/README.md similarity index 100% rename from nix/README.md rename to nix/runner/README.md From 1b3c22b7197b85ea8cf15d8adca3ab886b0dfd81 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 3 Aug 2026 10:36:17 +0100 Subject: [PATCH 14/19] stateVersion is 26.05 --- nix/runner/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/runner/default.nix b/nix/runner/default.nix index b68af853..1842d9cd 100644 --- a/nix/runner/default.nix +++ b/nix/runner/default.nix @@ -6,7 +6,7 @@ config = { nixpkgs.hostPlatform = "x86_64-linux"; - system.stateVersion = "25.05"; + system.stateVersion = "26.05"; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; nix.settings = { From d29dc74899dd68526fda8d2680bd6d4f9f78e7f7 Mon Sep 17 00:00:00 2001 From: Patrick Aldis Date: Mon, 3 Aug 2026 10:36:43 +0100 Subject: [PATCH 15/19] remove disko --- flake.lock | 21 --------------------- flake.nix | 4 ---- 2 files changed, 25 deletions(-) diff --git a/flake.lock b/flake.lock index 9b311f65..b0641ce9 100644 --- a/flake.lock +++ b/flake.lock @@ -43,26 +43,6 @@ "type": "github" } }, - "disko": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1781152676, - "narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=", - "owner": "nix-community", - "repo": "disko", - "rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "disko", - "type": "github" - } - }, "flake-utils": { "inputs": { "systems": "systems_2" @@ -208,7 +188,6 @@ "root": { "inputs": { "agenix": "agenix", - "disko": "disko", "flake-utils": "flake-utils", "ghc-wasm-meta": "ghc-wasm-meta", "nixpkgs": "nixpkgs_3", diff --git a/flake.nix b/flake.nix index 0220d0c5..14922e73 100644 --- a/flake.nix +++ b/flake.nix @@ -6,10 +6,6 @@ rust-overlay.url = "github:oxalica/rust-overlay"; ghc-wasm-meta.url = "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org"; agenix.url = "github:ryantm/agenix"; - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; outputs = inputs@{ From 17b4d3020bc6bd61ae03f81240365e8b08d4a810 Mon Sep 17 00:00:00 2001 From: Owen Lynch Date: Tue, 4 Aug 2026 19:07:07 +0100 Subject: [PATCH 16/19] check for esbuild --- .github/workflows/check.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index eff2e78f..3b7e862a 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -58,6 +58,9 @@ jobs: working-directory: packages/coln-js-runtime run: just test-rust + - name: Check for esbuild + run: esbuild --version + - name: JS Checks working-directory: packages/coln-js-runtime run: just test-npm From 39d964dd7851534c2e4e51c1619c2728a417a6c4 Mon Sep 17 00:00:00 2001 From: Owen Lynch Date: Tue, 4 Aug 2026 19:11:38 +0100 Subject: [PATCH 17/19] try running in nix shell from flake --- .github/workflows/check.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3b7e862a..cac5a302 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -58,12 +58,9 @@ jobs: working-directory: packages/coln-js-runtime run: just test-rust - - name: Check for esbuild - run: esbuild --version - - name: JS Checks working-directory: packages/coln-js-runtime - run: just test-npm + run: nix develop --command just test-npm haskell-tests: runs-on: coln-runner From 60c40a19fd611fc296ac7b4d1da99b61b377def9 Mon Sep 17 00:00:00 2001 From: Owen Lynch Date: Tue, 4 Aug 2026 19:13:16 +0100 Subject: [PATCH 18/19] accept flake config --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cac5a302..aa59b2b7 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -60,7 +60,7 @@ jobs: - name: JS Checks working-directory: packages/coln-js-runtime - run: nix develop --command just test-npm + run: nix develop --accept-flake-config --command just test-npm haskell-tests: runs-on: coln-runner From 6832ae2ad78eda4b793b895b0cbb24b86dea611a Mon Sep 17 00:00:00 2001 From: Owen Lynch Date: Tue, 4 Aug 2026 19:18:34 +0100 Subject: [PATCH 19/19] add cachix to nix config, so don't need it from flake --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index aa59b2b7..cac5a302 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -60,7 +60,7 @@ jobs: - name: JS Checks working-directory: packages/coln-js-runtime - run: nix develop --accept-flake-config --command just test-npm + run: nix develop --command just test-npm haskell-tests: runs-on: coln-runner