···165165166166- [PDS](https://github.com/bluesky-social/pds), Personal Data Server for [bsky](https://bsky.social/). Available as [services.pds](option.html#opt-services.pds).
167167168168+- [Anubis](https://github.com/TecharoHQ/anubis), a scraper defense software. Available as [services.anubis](options.html#opt-services.anubis).
169169+168170- [synapse-auto-compressor](https://github.com/matrix-org/rust-synapse-compress-state?tab=readme-ov-file#automated-tool-synapse_auto_compressor), a rust-based matrix-synapse state compressor for postgresql. Available as [services.synapse-auto-compressor](#opt-services.synapse-auto-compressor.enable).
169171170172- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).
···172174- [pocket-id](https://pocket-id.org/), an OIDC provider with passkeys support. Available as [services.pocket-id](#opt-services.pocket-id.enable).
173175174176- [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable).
177177+178178+- [Lavalink](https://github.com/lavalink-devs/Lavalink), a standalone audio sending node based on Lavaplayer and Koe. Availble as [services.lavalink](#opt-services.lavalink.enable).
175179176180- [OpenGamepadUI](https://github.com/ShadowBlip/OpenGamepadUI/), an open source gamepad-native game launcher and overlay for Linux. Available as [programs.opengamepadui](#opt-programs.opengamepadui.enable).
177181
···11+{
22+ config,
33+ pkgs,
44+ lib,
55+ ...
66+}:
77+88+let
99+ inherit (lib)
1010+ mkOption
1111+ mkEnableOption
1212+ mkIf
1313+ types
1414+ ;
1515+1616+ cfg = config.services.lavalink;
1717+1818+ format = pkgs.formats.yaml { };
1919+in
2020+2121+{
2222+ options.services.lavalink = {
2323+ enable = mkEnableOption "Lavalink";
2424+2525+ package = lib.mkPackageOption pkgs "lavalink" { };
2626+2727+ password = mkOption {
2828+ type = types.nullOr types.str;
2929+ default = null;
3030+ example = "s3cRe!p4SsW0rD";
3131+ description = ''
3232+ The password for Lavalink's authentication in plain text.
3333+ '';
3434+ };
3535+3636+ port = mkOption {
3737+ type = types.port;
3838+ default = 2333;
3939+ example = 4567;
4040+ description = ''
4141+ The port that Lavalink will use.
4242+ '';
4343+ };
4444+4545+ address = mkOption {
4646+ type = types.str;
4747+ default = "0.0.0.0";
4848+ example = "127.0.0.1";
4949+ description = ''
5050+ The network address to bind to.
5151+ '';
5252+ };
5353+5454+ openFirewall = mkOption {
5555+ type = types.bool;
5656+ default = false;
5757+ example = true;
5858+ description = ''
5959+ Whether to expose the port to the network.
6060+ '';
6161+ };
6262+6363+ user = mkOption {
6464+ type = types.str;
6565+ default = "lavalink";
6666+ example = "root";
6767+ description = ''
6868+ The user of the service.
6969+ '';
7070+ };
7171+7272+ group = mkOption {
7373+ type = types.str;
7474+ default = "lavalink";
7575+ example = "medias";
7676+ description = ''
7777+ The group of the service.
7878+ '';
7979+ };
8080+8181+ home = mkOption {
8282+ type = types.str;
8383+ default = "/var/lib/lavalink";
8484+ example = "/home/lavalink";
8585+ description = ''
8686+ The home directory for lavalink.
8787+ '';
8888+ };
8989+9090+ enableHttp2 = mkEnableOption "HTTP/2 support";
9191+9292+ jvmArgs = mkOption {
9393+ type = types.str;
9494+ default = "-Xmx4G";
9595+ example = "-Djava.io.tmpdir=/var/lib/lavalink/tmp -Xmx6G";
9696+ description = ''
9797+ Set custom JVM arguments.
9898+ '';
9999+ };
100100+101101+ environmentFile = mkOption {
102102+ type = types.nullOr types.str;
103103+ default = null;
104104+ example = "/run/secrets/lavalink/passwordEnvFile";
105105+ description = ''
106106+ Add custom environment variables from a file.
107107+ See <https://lavalink.dev/configuration/index.html#example-environment-variables> for the full documentation.
108108+ '';
109109+ };
110110+111111+ plugins = mkOption {
112112+ type = types.listOf (
113113+ types.submodule {
114114+ options = {
115115+ dependency = mkOption {
116116+ type = types.str;
117117+ example = "dev.lavalink.youtube:youtube-plugin:1.8.0";
118118+ description = ''
119119+ The coordinates of the plugin.
120120+ '';
121121+ };
122122+123123+ repository = mkOption {
124124+ type = types.str;
125125+ example = "https://maven.example.com/releases";
126126+ default = "https://maven.lavalink.dev/releases";
127127+ description = ''
128128+ The plugin repository. Defaults to the lavalink releases repository.
129129+130130+ To use the snapshots repository, use <https://maven.lavalink.dev/snapshots> instead
131131+ '';
132132+ };
133133+134134+ hash = mkOption {
135135+ type = types.str;
136136+ example = lib.fakeHash;
137137+ description = ''
138138+ The hash of the plugin.
139139+ '';
140140+ };
141141+142142+ configName = mkOption {
143143+ type = types.nullOr types.str;
144144+ example = "youtube";
145145+ default = null;
146146+ description = ''
147147+ The name of the plugin to use as the key for the plugin configuration.
148148+ '';
149149+ };
150150+151151+ extraConfig = mkOption {
152152+ type = types.submodule { freeformType = format.type; };
153153+ default = { };
154154+ description = ''
155155+ The configuration for the plugin.
156156+157157+ The {option}`services.lavalink.plugins.*.configName` option must be set.
158158+ '';
159159+ };
160160+ };
161161+ }
162162+ );
163163+ default = [ ];
164164+165165+ example = lib.literalExpression ''
166166+ [
167167+ {
168168+ dependency = "dev.lavalink.youtube:youtube-plugin:1.8.0";
169169+ repository = "https://maven.lavalink.dev/snapshots";
170170+ hash = lib.fakeHash;
171171+ configName = "youtube";
172172+ extraConfig = {
173173+ enabled = true;
174174+ allowSearch = true;
175175+ allowDirectVideoIds = true;
176176+ allowDirectPlaylistIds = true;
177177+ };
178178+ }
179179+ ]
180180+ '';
181181+182182+ description = ''
183183+ A list of plugins for lavalink.
184184+ '';
185185+ };
186186+187187+ extraConfig = mkOption {
188188+ type = types.submodule { freeformType = format.type; };
189189+190190+ description = ''
191191+ Configuration to write to {file}`application.yml`.
192192+ See <https://lavalink.dev/configuration/#example-applicationyml> for the full documentation.
193193+194194+ Individual configuration parameters can be overwritten using environment variables.
195195+ See <https://lavalink.dev/configuration/#example-environment-variables> for more information.
196196+ '';
197197+198198+ default = { };
199199+200200+ example = lib.literalExpression ''
201201+ {
202202+ lavalink.server = {
203203+ sources.twitch = true;
204204+205205+ filters.volume = true;
206206+ };
207207+208208+ logging.file.path = "./logs/";
209209+ }
210210+ '';
211211+ };
212212+ };
213213+214214+ config =
215215+ let
216216+ pluginSymlinks = lib.concatStringsSep "\n" (
217217+ map (
218218+ pluginCfg:
219219+ let
220220+ pluginParts = lib.match ''^(.*?:(.*?):)([0-9]+\.[0-9]+\.[0-9]+)$'' pluginCfg.dependency;
221221+222222+ pluginWebPath = lib.replaceStrings [ "." ":" ] [ "/" "/" ] (lib.elemAt pluginParts 0);
223223+224224+ pluginFileName = lib.elemAt pluginParts 1;
225225+ pluginVersion = lib.elemAt pluginParts 2;
226226+227227+ pluginFile = "${pluginFileName}-${pluginVersion}.jar";
228228+ pluginUrl = "${pluginCfg.repository}/${pluginWebPath}${pluginVersion}/${pluginFile}";
229229+230230+ plugin = pkgs.fetchurl {
231231+ url = pluginUrl;
232232+ inherit (pluginCfg) hash;
233233+ };
234234+ in
235235+ "ln -sf ${plugin} ${cfg.home}/plugins/${pluginFile}"
236236+ ) cfg.plugins
237237+ );
238238+239239+ pluginExtraConfigs = builtins.listToAttrs (
240240+ builtins.map (
241241+ pluginConfig: lib.attrsets.nameValuePair pluginConfig.configName pluginConfig.extraConfig
242242+ ) (lib.lists.filter (pluginCfg: pluginCfg.configName != null) cfg.plugins)
243243+ );
244244+245245+ config = lib.attrsets.recursiveUpdate cfg.extraConfig {
246246+ server = {
247247+ inherit (cfg) port address;
248248+ http2.enabled = cfg.enableHttp2;
249249+ };
250250+251251+ plugins = pluginExtraConfigs;
252252+ lavalink.plugins = (
253253+ builtins.map (
254254+ pluginConfig:
255255+ builtins.removeAttrs pluginConfig [
256256+ "name"
257257+ "extraConfig"
258258+ "hash"
259259+ ]
260260+ ) cfg.plugins
261261+ );
262262+ };
263263+264264+ configWithPassword = lib.attrsets.recursiveUpdate config (
265265+ lib.attrsets.optionalAttrs (cfg.password != null) { lavalink.server.password = cfg.password; }
266266+ );
267267+268268+ configFile = format.generate "application.yml" configWithPassword;
269269+ in
270270+ mkIf cfg.enable {
271271+ assertions = [
272272+ {
273273+ assertion =
274274+ !(lib.lists.any (
275275+ pluginCfg: pluginCfg.extraConfig != { } && pluginCfg.configName == null
276276+ ) cfg.plugins);
277277+ message = "Plugins with extra configuration need to have the `configName` attribute defined";
278278+ }
279279+ ];
280280+281281+ networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
282282+283283+ users.groups = mkIf (cfg.group == "lavalink") { lavalink = { }; };
284284+ users.users = mkIf (cfg.user == "lavalink") {
285285+ lavalink = {
286286+ inherit (cfg) home;
287287+ group = "lavalink";
288288+ description = "The user for the Lavalink server";
289289+ isSystemUser = true;
290290+ };
291291+ };
292292+293293+ systemd.tmpfiles.settings."10-lavalink" =
294294+ let
295295+ dirConfig = {
296296+ inherit (cfg) user group;
297297+ mode = "0700";
298298+ };
299299+ in
300300+ {
301301+ "${cfg.home}/plugins".d = mkIf (cfg.plugins != [ ]) dirConfig;
302302+ ${cfg.home}.d = dirConfig;
303303+ };
304304+305305+ systemd.services.lavalink = {
306306+ description = "Lavalink Service";
307307+308308+ wantedBy = [ "multi-user.target" ];
309309+ after = [
310310+ "syslog.target"
311311+ "network.target"
312312+ ];
313313+314314+ script = ''
315315+ ${pluginSymlinks}
316316+317317+ ln -sf ${configFile} ${cfg.home}/application.yml
318318+ export _JAVA_OPTIONS="${cfg.jvmArgs}"
319319+320320+ ${lib.getExe cfg.package}
321321+ '';
322322+323323+ serviceConfig = {
324324+ User = cfg.user;
325325+ Group = cfg.group;
326326+327327+ Type = "simple";
328328+ Restart = "on-failure";
329329+330330+ EnvironmentFile = cfg.environmentFile;
331331+ WorkingDirectory = cfg.home;
332332+ };
333333+ };
334334+ };
335335+}
+61
nixos/modules/services/networking/anubis.md
···11+# Anubis {#module-services-anubis}
22+33+[Anubis](https://anubis.techaro.lol) is a scraper defense software that blocks AI scrapers. It is designed to sit
44+between a reverse proxy and the service to be protected.
55+66+## Quickstart {#module-services-anubis-quickstart}
77+88+This module is designed to use Unix domain sockets as the socket paths can be automatically configured for multiple
99+instances, but TCP sockets are also supported.
1010+1111+A minimal configuration with [nginx](#opt-services.nginx.enable) may look like the following:
1212+1313+```nix
1414+{ config, ... }: {
1515+ services.anubis.instances.default.settings.TARGET = "http://localhost:8000";
1616+1717+ # required due to unix socket permissions
1818+ users.users.nginx.extraGroups = [ config.users.groups.anubis.name ];
1919+ services.nginx.virtualHosts."example.com" = {
2020+ locations = {
2121+ "/".proxyPass = "http://unix:${config.services.anubis.instances.default.settings.BIND}";
2222+ };
2323+ };
2424+}
2525+```
2626+2727+If Unix domain sockets are not needed or desired, this module supports operating with only TCP sockets.
2828+2929+```nix
3030+{
3131+ services.anubis = {
3232+ instances.default = {
3333+ settings = {
3434+ TARGET = "http://localhost:8080";
3535+ BIND = ":9000";
3636+ BIND_NETWORK = "tcp";
3737+ METRICS_BIND = "127.0.0.1:9001";
3838+ METRICS_BIND_NETWORK = "tcp";
3939+ };
4040+ };
4141+ };
4242+}
4343+```
4444+4545+## Configuration {#module-services-anubis-configuration}
4646+4747+It is possible to configure default settings for all instances of Anubis, via {option}`services.anubis.defaultOptions`.
4848+4949+```nix
5050+{
5151+ services.anubis.defaultOptions = {
5252+ botPolicy = { dnsbl = false; };
5353+ settings.DIFFICULTY = 3;
5454+ };
5555+}
5656+```
5757+5858+Note that at the moment, a custom bot policy is not merged with the baked-in one. That means to only override a setting
5959+like `dnsbl`, copying the entire bot policy is required. Check
6060+[the upstream repository](https://github.com/TecharoHQ/anubis/blob/1509b06cb921aff842e71fbb6636646be6ed5b46/cmd/anubis/botPolicies.json)
6161+for the policy.
+314
nixos/modules/services/networking/anubis.nix
···11+{
22+ config,
33+ lib,
44+ pkgs,
55+ ...
66+}:
77+let
88+ inherit (lib) types;
99+ jsonFormat = pkgs.formats.json { };
1010+1111+ cfg = config.services.anubis;
1212+ enabledInstances = lib.filterAttrs (_: conf: conf.enable) cfg.instances;
1313+ instanceName = name: if name == "" then "anubis" else "anubis-${name}";
1414+1515+ commonSubmodule =
1616+ isDefault:
1717+ let
1818+ mkDefaultOption =
1919+ path: opts:
2020+ lib.mkOption (
2121+ opts
2222+ // lib.optionalAttrs (!isDefault && opts ? default) {
2323+ default =
2424+ lib.attrByPath (lib.splitString "." path)
2525+ (throw "This is a bug in the Anubis module. Please report this as an issue.")
2626+ cfg.defaultOptions;
2727+ defaultText = lib.literalExpression "config.services.anubis.defaultOptions.${path}";
2828+ }
2929+ );
3030+ in
3131+ { name, ... }:
3232+ {
3333+ options = {
3434+ enable = lib.mkEnableOption "this instance of Anubis" // {
3535+ default = true;
3636+ };
3737+ user = mkDefaultOption "user" {
3838+ default = "anubis";
3939+ description = ''
4040+ The user under which Anubis is run.
4141+4242+ This module utilizes systemd's DynamicUser feature. See the corresponding section in
4343+ {manpage}`systemd.exec(5)` for more details.
4444+ '';
4545+ type = types.str;
4646+ };
4747+ group = mkDefaultOption "group" {
4848+ default = "anubis";
4949+ description = ''
5050+ The group under which Anubis is run.
5151+5252+ This module utilizes systemd's DynamicUser feature. See the corresponding section in
5353+ {manpage}`systemd.exec(5)` for more details.
5454+ '';
5555+ type = types.str;
5656+ };
5757+5858+ botPolicy = lib.mkOption {
5959+ default = null;
6060+ description = ''
6161+ Anubis policy configuration in Nix syntax. Set to `null` to use the baked-in policy which should be
6262+ sufficient for most use-cases.
6363+6464+ This option has no effect if `settings.POLICY_FNAME` is set to a different value, which is useful for
6565+ importing an existing configuration.
6666+6767+ See [the documentation](https://anubis.techaro.lol/docs/admin/policies) for details.
6868+ '';
6969+ type = types.nullOr jsonFormat.type;
7070+ };
7171+7272+ extraFlags = mkDefaultOption "extraFlags" {
7373+ default = [ ];
7474+ description = "A list of extra flags to be passed to Anubis.";
7575+ example = [ "-metrics-bind \"\"" ];
7676+ type = types.listOf types.str;
7777+ };
7878+7979+ settings = lib.mkOption {
8080+ default = { };
8181+ description = ''
8282+ Freeform configuration via environment variables for Anubis.
8383+8484+ See [the documentation](https://anubis.techaro.lol/docs/admin/installation) for a complete list of
8585+ available environment variables.
8686+ '';
8787+ type = types.submodule [
8888+ {
8989+ freeformType =
9090+ with types;
9191+ attrsOf (
9292+ nullOr (oneOf [
9393+ str
9494+ int
9595+ bool
9696+ ])
9797+ );
9898+9999+ options = {
100100+ # BIND and METRICS_BIND are defined in instance specific options, since global defaults don't make sense
101101+ BIND_NETWORK = mkDefaultOption "settings.BIND_NETWORK" {
102102+ default = "unix";
103103+ description = ''
104104+ The network family that Anubis should bind to.
105105+106106+ Accepts anything supported by Go's [`net.Listen`](https://pkg.go.dev/net#Listen).
107107+108108+ Common values are `tcp` and `unix`.
109109+ '';
110110+ example = "tcp";
111111+ type = types.str;
112112+ };
113113+ METRICS_BIND_NETWORK = mkDefaultOption "settings.METRICS_BIND_NETWORK" {
114114+ default = "unix";
115115+ description = ''
116116+ The network family that the metrics server should bind to.
117117+118118+ Accepts anything supported by Go's [`net.Listen`](https://pkg.go.dev/net#Listen).
119119+120120+ Common values are `tcp` and `unix`.
121121+ '';
122122+ example = "tcp";
123123+ type = types.str;
124124+ };
125125+ SOCKET_MODE = mkDefaultOption "settings.SOCKET_MODE" {
126126+ default = "0770";
127127+ description = "The permissions on the Unix domain sockets created.";
128128+ example = "0700";
129129+ type = types.str;
130130+ };
131131+ DIFFICULTY = mkDefaultOption "settings.DIFFICULTY" {
132132+ default = 4;
133133+ description = ''
134134+ The difficulty required for clients to solve the challenge.
135135+136136+ Currently, this means the amount of leading zeros in a successful response.
137137+ '';
138138+ type = types.int;
139139+ example = 5;
140140+ };
141141+ SERVE_ROBOTS_TXT = mkDefaultOption "settings.SERVE_ROBOTS_TXT" {
142142+ default = false;
143143+ description = ''
144144+ Whether to serve a default robots.txt that denies access to common AI bots by name and all other
145145+ bots by wildcard.
146146+ '';
147147+ type = types.bool;
148148+ };
149149+150150+ # generated by default
151151+ POLICY_FNAME = mkDefaultOption "settings.POLICY_FNAME" {
152152+ default = null;
153153+ description = ''
154154+ The bot policy file to use. Leave this as `null` to respect the value set in
155155+ {option}`services.anubis.instances.<name>.botPolicy`.
156156+ '';
157157+ type = types.nullOr types.path;
158158+ };
159159+ };
160160+ }
161161+ (lib.optionalAttrs (!isDefault) (instanceSpecificOptions name))
162162+ ];
163163+ };
164164+ };
165165+ };
166166+167167+ instanceSpecificOptions = name: {
168168+ options = {
169169+ # see other options above
170170+ BIND = lib.mkOption {
171171+ default = "/run/anubis/${instanceName name}.sock";
172172+ description = ''
173173+ The address that Anubis listens to. See Go's [`net.Listen`](https://pkg.go.dev/net#Listen) for syntax.
174174+175175+ Defaults to Unix domain sockets. To use TCP sockets, set this to a TCP address and `BIND_NETWORK` to `"tcp"`.
176176+ '';
177177+ example = ":8080";
178178+ type = types.str;
179179+ };
180180+ METRICS_BIND = lib.mkOption {
181181+ default = "/run/anubis/${instanceName name}-metrics.sock";
182182+ description = ''
183183+ The address Anubis' metrics server listens to. See Go's [`net.Listen`](https://pkg.go.dev/net#Listen) for
184184+ syntax.
185185+186186+ The metrics server is enabled by default and may be disabled. However, due to implementation details, this is
187187+ only possible by setting a command line flag. See {option}`services.anubis.defaultOptions.extraFlags` for an
188188+ example.
189189+190190+ Defaults to Unix domain sockets. To use TCP sockets, set this to a TCP address and `METRICS_BIND_NETWORK` to
191191+ `"tcp"`.
192192+ '';
193193+ example = "127.0.0.1:8081";
194194+ type = types.str;
195195+ };
196196+ TARGET = lib.mkOption {
197197+ description = ''
198198+ The reverse proxy target that Anubis is protecting. This is a required option.
199199+200200+ The usage of Unix domain sockets is supported by the following syntax: `unix:///path/to/socket.sock`.
201201+ '';
202202+ example = "http://127.0.0.1:8000";
203203+ type = types.str;
204204+ };
205205+ };
206206+ };
207207+in
208208+{
209209+ options.services.anubis = {
210210+ package = lib.mkPackageOption pkgs "anubis" { };
211211+212212+ defaultOptions = lib.mkOption {
213213+ default = { };
214214+ description = "Default options for all instances of Anubis.";
215215+ type = types.submodule (commonSubmodule true);
216216+ };
217217+218218+ instances = lib.mkOption {
219219+ default = { };
220220+ description = ''
221221+ An attribute set of Anubis instances.
222222+223223+ The attribute name may be an empty string, in which case the `-<name>` suffix is not added to the service name
224224+ and socket paths.
225225+ '';
226226+ type = types.attrsOf (types.submodule (commonSubmodule false));
227227+ };
228228+ };
229229+230230+ config = lib.mkIf (enabledInstances != { }) {
231231+ users.users = lib.mkIf (cfg.defaultOptions.user == "anubis") {
232232+ anubis = {
233233+ isSystemUser = true;
234234+ group = cfg.defaultOptions.group;
235235+ };
236236+ };
237237+238238+ users.groups = lib.mkIf (cfg.defaultOptions.group == "anubis") {
239239+ anubis = { };
240240+ };
241241+242242+ systemd.services = lib.mapAttrs' (
243243+ name: instance:
244244+ lib.nameValuePair "${instanceName name}" {
245245+ description = "Anubis (${if name == "" then "default" else name} instance)";
246246+ wantedBy = [ "multi-user.target" ];
247247+ after = [ "network-online.target" ];
248248+ wants = [ "network-online.target" ];
249249+250250+ environment = lib.mapAttrs (lib.const (lib.generators.mkValueStringDefault { })) (
251251+ lib.filterAttrs (_: v: v != null) instance.settings
252252+ );
253253+254254+ serviceConfig = {
255255+ User = instance.user;
256256+ Group = instance.group;
257257+ DynamicUser = true;
258258+259259+ ExecStart = lib.concatStringsSep " " (
260260+ (lib.singleton (lib.getExe cfg.package)) ++ instance.extraFlags
261261+ );
262262+ RuntimeDirectory =
263263+ if
264264+ lib.any (lib.hasPrefix "/run/anubis") (
265265+ with instance.settings;
266266+ [
267267+ BIND
268268+ METRICS_BIND
269269+ ]
270270+ )
271271+ then
272272+ "anubis"
273273+ else
274274+ null;
275275+276276+ # hardening
277277+ NoNewPrivileges = true;
278278+ CapabilityBoundingSet = null;
279279+ SystemCallFilter = [
280280+ "@system-service"
281281+ "~@privileged"
282282+ ];
283283+ SystemCallArchitectures = "native";
284284+ MemoryDenyWriteExecute = true;
285285+286286+ PrivateUsers = true;
287287+ PrivateTmp = true;
288288+ PrivateDevices = true;
289289+ ProtectHome = true;
290290+ ProtectClock = true;
291291+ ProtectHostname = true;
292292+ ProtectKernelLogs = true;
293293+ ProtectKernelModules = true;
294294+ ProtectKernelTunables = true;
295295+ ProtectProc = "invisible";
296296+ ProtectSystem = "strict";
297297+ ProtectControlGroups = "strict";
298298+ LockPersonality = true;
299299+ RestrictRealtime = true;
300300+ RestrictSUIDSGID = true;
301301+ RestrictNamespaces = true;
302302+ RestrictAddressFamilies = [
303303+ "AF_UNIX"
304304+ "AF_INET"
305305+ "AF_INET6"
306306+ ];
307307+ };
308308+ }
309309+ ) enabledInstances;
310310+ };
311311+312312+ meta.maintainers = with lib.maintainers; [ soopyc ];
313313+ meta.doc = ./anubis.md;
314314+}
···5656 GZIP compression level of the resulting disk image (1-9).
5757 '';
5858 };
5959+6060+ virtualisation.googleComputeImage.contents = mkOption {
6161+ type = with types; listOf attrs;
6262+ default = [ ];
6363+ description = ''
6464+ The files and directories to be placed in the image.
6565+ This is a list of attribute sets {source, target, mode, user, group} where
6666+ `source' is the file system object (regular file or directory) to be
6767+ grafted in the file system at path `target', `mode' is a string containing
6868+ the permissions that will be set (ex. "755"), `user' and `group' are the
6969+ user and group name that will be set as owner of the files.
7070+ `mode', `user', and `group' are optional.
7171+ When setting one of `user' or `group', the other needs to be set too.
7272+ '';
7373+ example = literalExpression ''
7474+ [
7575+ {
7676+ source = ./default.nix;
7777+ target = "/etc/nixos/default.nix";
7878+ mode = "0644";
7979+ user = "root";
8080+ group = "root";
8181+ }
8282+ ];
8383+ '';
8484+ };
8585+5986 virtualisation.googleComputeImage.efi = mkEnableOption "EFI booting";
6087 };
6188···99126 '';
100127 format = "raw";
101128 configFile = if cfg.configFile == null then defaultConfigFile else cfg.configFile;
129129+ inherit (cfg) contents;
102130 partitionTableType = if cfg.efi then "efi" else "legacy";
103131 inherit (config.virtualisation) diskSize;
104132 inherit config lib pkgs;
···21272127 publisher = "github";
21282128 name = "copilot-chat";
21292129 # Verify which version is available with nix run nixpkgs#vsce -- show github.copilot-chat --json
21302130- version = "0.26.2025030506"; # latest compatible with vscode ^1.98
21312131- hash = "sha256-mCmZs5xGxcqHyo8NyMjk2mu9LmxFlMb2NGUwjXg27JA=";
21302130+ version = "0.26.2025040204"; # latest compatible with vscode ^1.98
21312131+ hash = "sha256-grG/pn+R4paCqkSx6DGzKjyjQVZ2FINRxdpXynGF35g=";
21322132 };
21332133 meta = {
21342134 description = "GitHub Copilot Chat is a companion extension to GitHub Copilot that houses experimental chat features";
···148148149149## TODON'T
150150151151-- Reimplement `systemd-run` logic: will be moved to the new
152152- [`apply`](https://github.com/NixOS/nixpkgs/pull/344407) script
153151- Nix bootstrap: it is only used for non-Flake paths and it is basically
154152 useless nowadays. It was created at a time when Nix was changing frequently
155153 and there was a need to bootstrap a new version of Nix before evaluating the
···62626363rustPlatform.buildRustPackage {
6464 pname = "servo";
6565- version = "0-unstable-2025-03-29";
6565+ version = "0-unstable-2025-04-08";
66666767 src = fetchFromGitHub {
6868 owner = "servo";
6969 repo = "servo";
7070- rev = "5d1c64dba9cf3e65f770370eb17f00ad4114edce";
7171- hash = "sha256-0DuS2WfgWgnxh5qDc/XNL28XxXKnYPQW7F2m4OlANck=";
7070+ rev = "4d4f94936f8859f039497df370083fd7ea35fb00";
7171+ hash = "sha256-SI3HnKuh6zD07D7SUswfehwXEFkuaZQkqipH0Rlj9Gg=";
7272 # Breaks reproducibility depending on whether the picked commit
7373 # has other ref-names or not, which may change over time, i.e. with
7474 # "ref-names: HEAD -> main" as long this commit is the branch HEAD
···7979 };
80808181 useFetchCargoVendor = true;
8282- cargoHash = "sha256-m6lsXHf7SIgbIt8RyhUkJpd1/nJQMSNRS9uTJ6th9ng=";
8282+ cargoHash = "sha256-toVo1QpeMeK8SoQaYU5d+VAd3s22iwRI4caJIpxPP6I=";
83838484 # set `HOME` to a temp dir for write access
8585 # Fix invalid option errors during linking (https://github.com/mozilla/nixpkgs-mozilla/commit/c72ff151a3e25f14182569679ed4cd22ef352328)