atagen

malice

public
Star0
Watch0
235ce394f90da8ff124691ee4ee2997c979e7d3c
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
flake.nixNix351 lines11.6 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
          npmDeps = webNodeModules pkgs;
90
          disallowedReferences = [
91
            (webNodeModules pkgs)
92
            pkgs.nodejs_22
93
          ];
94
          nativeBuildInputs = [
95
            pkgs.nodejs_22
96
            pkgs.importNpmLock.hooks.linkNodeModulesHook
97
            pkgs.brotli
98
          ];
99
          buildPhase = ''
100
            runHook preBuild
101
            export HOME=$TMPDIR
102
            npm run ${task}
103
            runHook postBuild
104
          '';
105
          installPhase = ''
106
            runHook preInstall
107
            mkdir -p $out/share/malice
108
            cp -R ${outDir}/. $out/share/malice/
109
            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 \
110
              -exec brotli --best --keep {} \; -exec gzip -9 --keep {} \;
111
            runHook postInstall
112
          '';
113
        };
114
    in
115
    {
116
      packages = forAllSystems (
117
        system:
118
        let
119
          pkgs = nixpkgs.legacyPackages.${system};
120
          wasmPlatform = pkgs.makeRustPlatform {
121
            cargo = wasmToolchain system;
122
            rustc = wasmToolchain system;
123
          };
124
          web = buildWeb pkgs {
125
            pname = "malice-web";
126
            task = "build";
127
            outDir = "dist";
128
          };
129
          backend = pkgs.rustPlatform.buildRustPackage {
130
            pname = "malice-server";
131
            version = "0.1.0";
132
            src = cleanSrc ./.;
133
            cargoLock = {
134
              lockFile = ./Cargo.lock;
135
              allowBuiltinFetchGit = true;
136
            };
137
            nativeBuildInputs = [ pkgs.pkg-config ];
138
            buildInputs = [ pkgs.sqlite ];
139
            cargoBuildFlags = [
140
              "-p"
141
              "malice"
142
            ];
143
            cargoTestFlags = [
144
              "-p"
145
              "malice"
146
            ];
147
            # preBuild = "export NIX_BUILD_CORES=2";
148
            preCheck = ''
149
              cargo build --release --bin malice --target ${pkgs.stdenv.hostPlatform.rust.rustcTarget} --offline --locked
150
            '';
151
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
152
          };
153
          staticServer = pkgs.rustPlatform.buildRustPackage {
154
            pname = "malice-static";
155
            version = "0.1.0";
156
            src = cleanSrc ./.;
157
            cargoLock = {
158
              lockFile = ./Cargo.lock;
159
              allowBuiltinFetchGit = true;
160
            };
161
            cargoBuildFlags = [
162
              "-p"
163
              "malice-static"
164
            ];
165
            cargoTestFlags = [
166
              "-p"
167
              "malice-static"
168
            ];
169
            SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
170
            meta.mainProgram = "malice-static";
171
          };
172
          server = pkgs.symlinkJoin {
173
            name = "malice";
174
            paths = [
175
              backend
176
              web
177
            ];
178
            nativeBuildInputs = [ pkgs.makeWrapper ];
179
            postBuild = ''
180
              wrapProgram $out/bin/malice --set MALICE_WEB_DIR ${web}/share/malice
181
            '';
182
          };
183
          # the wasm-bindgen `--target web` glue for malice-worker's `Host`, consumed by
184
          # web/src/worker/pkg (gitignored, worker-web's TS imports it as ./pkg/malice_worker.js)
185
          workerWasm = wasmPlatform.buildRustPackage {
186
            pname = "malice-worker-wasm";
187
            version = "0.1.0";
188
            src = cleanSrc ./.;
189
            cargoRoot = "crates/malice-worker";
190
            cargoLock = {
191
              lockFile = ./crates/malice-worker/Cargo.lock;
192
              allowBuiltinFetchGit = true;
193
            };
194
            nativeBuildInputs = [
195
              (wasmBindgenCli pkgs)
196
              pkgs.removeReferencesTo
197
            ];
198
            buildPhase = ''
199
              runHook preBuild
200
              cd crates/malice-worker
201
              cargo build --offline --frozen --release --lib --target wasm32-unknown-unknown
202
              mkdir -p $out
203
              wasm-bindgen --target web --out-dir $out --out-name malice_worker \
204
                target/wasm32-unknown-unknown/release/malice_worker.wasm
205
              remove-references-to -t ${wasmToolchain system} $out/*.wasm
206
              runHook postBuild
207
            '';
208
            doCheck = false;
209
            installPhase = "true";
210
            disallowedReferences = [ (wasmToolchain system) ];
211
          };
212
          web-device = buildWeb pkgs {
213
            pname = "malice-web-device";
214
            task = "build:device";
215
            outDir = "dist-device";
216
            postPatch = ''
217
              mkdir -p src/worker/pkg
218
              cp -R ${workerWasm}/. src/worker/pkg/
219
            '';
220
          };
221
          local = pkgs.symlinkJoin {
222
            name = "malice-local";
223
            paths = [
224
              staticServer
225
              web-device
226
            ];
227
            nativeBuildInputs = [ pkgs.makeWrapper ];
228
            postBuild = ''
229
              wrapProgram $out/bin/malice-static \
230
                --set MALICE_WEB_DIR ${web-device}/share/malice
231
            '';
232
          };
233
        in
234
        {
235
          inherit
236
            web
237
            server
238
            web-device
239
            local
240
            ;
241
          default = server;
242
        }
243
      );
244
245
      devShells = forAllSystems (
246
        system:
247
        let
248
          pkgs = nixpkgs.legacyPackages.${system};
249
        in
250
        {
251
          default = pkgs.mkShell {
252
            packages = [
253
              (wasmToolchain system)
254
              (wasmBindgenCli pkgs)
255
              pkgs.rust-analyzer
256
              pkgs.nodejs_22
257
              pkgs.importNpmLock.hooks.linkNodeModulesHook
258
              pkgs.pkg-config
259
              pkgs.sqlite
260
              pkgs.firefox
261
              pkgs.geckodriver
262
              pkgs.chromium
263
              pkgs.matrix-continuwuity
264
              pkgs.nushell
265
            ];
266
            CHROMIUM_PATH = nixpkgs.lib.getExe pkgs.chromium;
267
            npmDeps = webNodeModules pkgs;
268
            # the hook's own npmRoot would be a store path, so link into the checkout's web/ instead
269
            shellHook = ''
270
              npmRoot="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/web" linkNodeModulesHook
271
            '';
272
            # fenix's rustc links through its bundled rust-lld, which skips nix's ld-wrapper and so
273
            # the store rpaths, leaving the native server unable to find libsqlite3 at run time
274
            "CARGO_TARGET_${
275
              nixpkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] pkgs.stdenv.hostPlatform.config)
276
            }_RUSTFLAGS" =
277
              "-C linker-features=-lld";
278
          };
279
        }
280
      );
281
282
      nixosModules.malice = import ./nix/module.nix { inherit self; };
283
      nixosModules.default = self.nixosModules.malice;
284
      checks = forAllSystems (
285
        system:
286
        let
287
          pkgs = nixpkgs.legacyPackages.${system};
288
          wasmPlatform = pkgs.makeRustPlatform {
289
            cargo = wasmToolchain system;
290
            rustc = wasmToolchain system;
291
          };
292
          # continuwuity refuses to start without /etc/resolv.conf, which the build sandbox lacks, or with
293
          # stdenv's deliberately bogus SSL_CERT_FILE. no exec, run.nu launches through a shell that exits at
294
          # once and would trip --die-with-parent, so this shell stays as the parent run.nu kills
295
          sandboxedHomeserver = pkgs.writeShellScriptBin "conduwuit" ''
296
            export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
297
            ${pkgs.lib.getExe pkgs.bubblewrap} --die-with-parent --dev-bind / / --tmpfs /etc \
298
              --ro-bind ${pkgs.writeText "resolv.conf" "nameserver 127.0.0.1\n"} /etc/resolv.conf \
299
              ${pkgs.lib.getExe' pkgs.matrix-continuwuity "conduwuit"} "$@"
300
          '';
301
        in
302
        {
303
          default = self.packages.${system}.default;
304
          worker-wasm = self.packages.${system}.web-device;
305
          web = pkgs.stdenvNoCC.mkDerivation {
306
            pname = "malice-web-check";
307
            version = "0.1.0";
308
            src = cleanSrc ./web;
309
            npmDeps = webNodeModules pkgs;
310
            nativeBuildInputs = [
311
              pkgs.nodejs_22
312
              pkgs.importNpmLock.hooks.linkNodeModulesHook
313
            ];
314
            buildPhase = ''
315
              runHook preBuild
316
              export HOME=$TMPDIR
317
              npm run check
318
              npm test
319
              runHook postBuild
320
            '';
321
            installPhase = "touch $out";
322
          };
323
          worker-browser = wasmPlatform.buildRustPackage {
324
            pname = "malice-worker-browser-check";
325
            version = "0.1.0";
326
            src = cleanSrc ./.;
327
            cargoRoot = "crates/malice-worker";
328
            cargoLock = {
329
              lockFile = ./crates/malice-worker/Cargo.lock;
330
              allowBuiltinFetchGit = true;
331
            };
332
            nativeBuildInputs = [
333
              (wasmBindgenCli pkgs)
334
              pkgs.firefox
335
              pkgs.geckodriver
336
              sandboxedHomeserver
337
              pkgs.nushell
338
            ];
339
            buildPhase = ''
340
              runHook preBuild
341
              export HOME=$TMPDIR
342
              nu --no-config-file crates/malice-worker/run.nu
343
              runHook postBuild
344
            '';
345
            doCheck = false;
346
            installPhase = "touch $out";
347
          };
348
        }
349
      );
350
    };
351
}