atagen

malice

public
Star0
Watch0
81d6bf15e59bfcfc57f792500008a796939cdbd5
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
flake.nixNix353 lines11.8 KB
1
{
2
  description = "Malice: a hosted Matrix client backed by macltok";
3
4
  inputs = {
5
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6
    fenix = {
7
      url = "github:nix-community/fenix";
8
      inputs.nixpkgs.follows = "nixpkgs";
9
    };
10
  };
11
12
  outputs =
13
    {
14
      self,
15
      nixpkgs,
16
      fenix,
17
    }:
18
    let
19
      systems = [
20
        "x86_64-linux"
21
        "aarch64-linux"
22
      ];
23
      forAllSystems = nixpkgs.lib.genAttrs systems;
24
      cleanSrc =
25
        root:
26
        nixpkgs.lib.cleanSourceWith {
27
          src = root;
28
          filter =
29
            path: type:
30
            nixpkgs.lib.cleanSourceFilter path type
31
            && !(
32
              type == "directory"
33
              && builtins.elem (baseNameOf path) [
34
                "target"
35
                "node_modules"
36
                "dist"
37
                "dist-device"
38
              ]
39
            );
40
        };
41
      workerLock = builtins.fromTOML (builtins.readFile ./crates/malice-worker/Cargo.lock);
42
      lockedVersion = name: (nixpkgs.lib.findFirst (p: p.name == name) null workerLock.package).version;
43
      # wasm-bindgen-test-runner refuses a module built by any other wasm-bindgen version
44
      wasmBindgenCli =
45
        pkgs:
46
        pkgs.buildWasmBindgenCli rec {
47
          src = pkgs.fetchCrate {
48
            pname = "wasm-bindgen-cli";
49
            version = lockedVersion "wasm-bindgen";
50
            hash = "sha256-a7lcXJnnZkYReja+iUO7NqqrWyv3toxnUgQb8s4IS5s=";
51
          };
52
          cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
53
            inherit src;
54
            inherit (src) pname version;
55
            hash = "sha256-R1Tas33Ursy8kqsxguAkG0ZhNed2n5uFTAhw1l2qlLY=";
56
          };
57
        };
58
      wasmToolchain =
59
        system:
60
        let
61
          toolchains = fenix.packages.${system};
62
        in
63
        toolchains.combine [
64
          toolchains.stable.cargo
65
          toolchains.stable.clippy
66
          toolchains.stable.rustc
67
          toolchains.stable.rustfmt
68
          toolchains.stable.rust-src
69
          toolchains.targets.wasm32-unknown-unknown.stable.rust-std
70
        ];
71
      webNodeModules =
72
        pkgs:
73
        pkgs.importNpmLock.buildNodeModules {
74
          npmRoot = ./web;
75
          nodejs = pkgs.nodejs_22;
76
        };
77
      buildWeb =
78
        pkgs:
79
        {
80
          pname,
81
          task,
82
          outDir,
83
          postPatch ? "",
84
        }:
85
        pkgs.stdenvNoCC.mkDerivation {
86
          inherit pname postPatch;
87
          version = "0.1.0";
88
          src = cleanSrc ./web;
89
          MALICE_BUILD = "${toString self.lastModified}-${self.shortRev or self.dirtyShortRev or "dirty"}";
90
          npmDeps = webNodeModules pkgs;
91
          disallowedReferences = [
92
            (webNodeModules pkgs)
93
            pkgs.nodejs_22
94
          ];
95
          nativeBuildInputs = [
96
            pkgs.nodejs_22
97
            pkgs.importNpmLock.hooks.linkNodeModulesHook
98
            pkgs.brotli
99
          ];
100
          buildPhase = ''
101
            runHook preBuild
102
            export HOME=$TMPDIR
103
            npm run ${task}
104
            runHook postBuild
105
          '';
106
          installPhase = ''
107
            runHook preInstall
108
            mkdir -p $out/share/malice
109
            cp -R ${outDir}/. $out/share/malice/
110
            find $out/share/malice -type f \( -name '*.wasm' -o -name '*.js' -o -name '*.css' -o -name '*.html' -o -name '*.svg' -o -name '*.json' -o -name '*.webmanifest' \) -size +1k \
111
              -exec brotli --best --keep {} \; -exec gzip -9 --keep {} \;
112
            runHook postInstall
113
          '';
114
        };
115
    in
116
    {
117
      packages = forAllSystems (
118
        system:
119
        let
120
          pkgs = nixpkgs.legacyPackages.${system};
121
          wasmPlatform = pkgs.makeRustPlatform {
122
            cargo = wasmToolchain system;
123
            rustc = wasmToolchain system;
124
          };
125
          web = buildWeb pkgs {
126
            pname = "malice-web";
127
            task = "build";
128
            outDir = "dist";
129
          };
130
          backend = pkgs.rustPlatform.buildRustPackage {
131
            pname = "malice-server";
132
            version = "0.1.0";
133
            src = cleanSrc ./.;
134
            cargoLock = {
135
              lockFile = ./Cargo.lock;
136
              allowBuiltinFetchGit = true;
137
            };
138
            nativeBuildInputs = [ pkgs.pkg-config ];
139
            buildInputs = [ pkgs.sqlite ];
140
            cargoBuildFlags = [
141
              "-p"
142
              "malice"
143
            ];
144
            cargoTestFlags = [
145
              "-p"
146
              "malice"
147
            ];
148
            # preBuild = "export NIX_BUILD_CORES=2";
149
            preCheck = ''
150
              cargo build --release --bin malice --target ${pkgs.stdenv.hostPlatform.rust.rustcTarget} --offline --locked
151
            '';
152
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
153
          };
154
          staticServer = pkgs.rustPlatform.buildRustPackage {
155
            pname = "malice-static";
156
            version = "0.1.0";
157
            src = cleanSrc ./.;
158
            cargoLock = {
159
              lockFile = ./Cargo.lock;
160
              allowBuiltinFetchGit = true;
161
            };
162
            cargoBuildFlags = [
163
              "-p"
164
              "malice-static"
165
            ];
166
            cargoTestFlags = [
167
              "-p"
168
              "malice-static"
169
            ];
170
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
171
            meta.mainProgram = "malice-static";
172
          };
173
          server = pkgs.symlinkJoin {
174
            name = "malice";
175
            paths = [
176
              backend
177
              web
178
            ];
179
            nativeBuildInputs = [ pkgs.makeWrapper ];
180
            postBuild = ''
181
              wrapProgram $out/bin/malice --set MALICE_WEB_DIR ${web}/share/malice
182
            '';
183
          };
184
          # the wasm-bindgen `--target web` glue for malice-worker's `Host`, consumed by
185
          # web/src/worker/pkg (gitignored, worker-web's TS imports it as ./pkg/malice_worker.js)
186
          workerWasm = wasmPlatform.buildRustPackage {
187
            pname = "malice-worker-wasm";
188
            version = "0.1.0";
189
            src = cleanSrc ./.;
190
            cargoRoot = "crates/malice-worker";
191
            cargoLock = {
192
              lockFile = ./crates/malice-worker/Cargo.lock;
193
              allowBuiltinFetchGit = true;
194
            };
195
            nativeBuildInputs = [
196
              (wasmBindgenCli pkgs)
197
              pkgs.removeReferencesTo
198
            ];
199
            buildPhase = ''
200
              runHook preBuild
201
              cd crates/malice-worker
202
              cargo build --offline --frozen --release --lib --target wasm32-unknown-unknown
203
              mkdir -p $out
204
              wasm-bindgen --target web --out-dir $out --out-name malice_worker \
205
                target/wasm32-unknown-unknown/release/malice_worker.wasm
206
              remove-references-to -t ${wasmToolchain system} $out/*.wasm
207
              runHook postBuild
208
            '';
209
            doCheck = false;
210
            installPhase = "true";
211
            disallowedReferences = [ (wasmToolchain system) ];
212
          };
213
          web-device = buildWeb pkgs {
214
            pname = "malice-web-device";
215
            task = "build:device";
216
            outDir = "dist-device";
217
            postPatch = ''
218
              mkdir -p src/worker/pkg
219
              cp -R ${workerWasm}/. src/worker/pkg/
220
            '';
221
          };
222
          local = pkgs.symlinkJoin {
223
            name = "malice-local";
224
            meta.mainProgram = "malice-static";
225
            paths = [
226
              staticServer
227
              web-device
228
            ];
229
            nativeBuildInputs = [ pkgs.makeWrapper ];
230
            postBuild = ''
231
              wrapProgram $out/bin/malice-static \
232
                --set MALICE_WEB_DIR ${web-device}/share/malice
233
            '';
234
          };
235
        in
236
        {
237
          inherit
238
            web
239
            server
240
            web-device
241
            local
242
            ;
243
          default = server;
244
        }
245
      );
246
247
      devShells = forAllSystems (
248
        system:
249
        let
250
          pkgs = nixpkgs.legacyPackages.${system};
251
        in
252
        {
253
          default = pkgs.mkShell {
254
            packages = [
255
              (wasmToolchain system)
256
              (wasmBindgenCli pkgs)
257
              pkgs.rust-analyzer
258
              pkgs.nodejs_22
259
              pkgs.importNpmLock.hooks.linkNodeModulesHook
260
              pkgs.pkg-config
261
              pkgs.sqlite
262
              pkgs.firefox
263
              pkgs.geckodriver
264
              pkgs.chromium
265
              pkgs.matrix-continuwuity
266
              pkgs.nushell
267
            ];
268
            CHROMIUM_PATH = nixpkgs.lib.getExe pkgs.chromium;
269
            npmDeps = webNodeModules pkgs;
270
            # the hook's own npmRoot would be a store path, so link into the checkout's web/ instead
271
            shellHook = ''
272
              npmRoot="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/web" linkNodeModulesHook
273
            '';
274
            # fenix's rustc links through its bundled rust-lld, which skips nix's ld-wrapper and so
275
            # the store rpaths, leaving the native server unable to find libsqlite3 at run time
276
            "CARGO_TARGET_${
277
              nixpkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] pkgs.stdenv.hostPlatform.config)
278
            }_RUSTFLAGS" =
279
              "-C linker-features=-lld";
280
          };
281
        }
282
      );
283
284
      nixosModules.malice = import ./nix/module.nix { inherit self; };
285
      nixosModules.default = self.nixosModules.malice;
286
      checks = forAllSystems (
287
        system:
288
        let
289
          pkgs = nixpkgs.legacyPackages.${system};
290
          wasmPlatform = pkgs.makeRustPlatform {
291
            cargo = wasmToolchain system;
292
            rustc = wasmToolchain system;
293
          };
294
          # continuwuity refuses to start without /etc/resolv.conf, which the build sandbox lacks, or with
295
          # stdenv's deliberately bogus SSL_CERT_FILE. no exec, run.nu launches through a shell that exits at
296
          # once and would trip --die-with-parent, so this shell stays as the parent run.nu kills
297
          sandboxedHomeserver = pkgs.writeShellScriptBin "conduwuit" ''
298
            export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
299
            ${pkgs.lib.getExe pkgs.bubblewrap} --die-with-parent --dev-bind / / --tmpfs /etc \
300
              --ro-bind ${pkgs.writeText "resolv.conf" "nameserver 127.0.0.1\n"} /etc/resolv.conf \
301
              ${pkgs.lib.getExe' pkgs.matrix-continuwuity "conduwuit"} "$@"
302
          '';
303
        in
304
        {
305
          default = self.packages.${system}.default;
306
          worker-wasm = self.packages.${system}.web-device;
307
          web = pkgs.stdenvNoCC.mkDerivation {
308
            pname = "malice-web-check";
309
            version = "0.1.0";
310
            src = cleanSrc ./web;
311
            npmDeps = webNodeModules pkgs;
312
            nativeBuildInputs = [
313
              pkgs.nodejs_22
314
              pkgs.importNpmLock.hooks.linkNodeModulesHook
315
            ];
316
            buildPhase = ''
317
              runHook preBuild
318
              export HOME=$TMPDIR
319
              npm run check
320
              npm test
321
              runHook postBuild
322
            '';
323
            installPhase = "touch $out";
324
          };
325
          worker-browser = wasmPlatform.buildRustPackage {
326
            pname = "malice-worker-browser-check";
327
            version = "0.1.0";
328
            src = cleanSrc ./.;
329
            cargoRoot = "crates/malice-worker";
330
            cargoLock = {
331
              lockFile = ./crates/malice-worker/Cargo.lock;
332
              allowBuiltinFetchGit = true;
333
            };
334
            nativeBuildInputs = [
335
              (wasmBindgenCli pkgs)
336
              pkgs.firefox
337
              pkgs.geckodriver
338
              sandboxedHomeserver
339
              pkgs.nushell
340
            ];
341
            buildPhase = ''
342
              runHook preBuild
343
              export HOME=$TMPDIR
344
              nu --no-config-file crates/malice-worker/run.nu
345
              runHook postBuild
346
            '';
347
            doCheck = false;
348
            installPhase = "touch $out";
349
          };
350
        }
351
      );
352
    };
353
}