diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 120000 index 0000000..39744d6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1 @@ +/nix/store/sbc33iwjwgwj0cklac3qjffvi93i723k-pre-commit-config.json \ No newline at end of file diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..f9713ef --- /dev/null +++ b/default.nix @@ -0,0 +1,93 @@ +/* Copyright : + - Maurice Debray 2023 + - Tom Hubrecht 2023 + + Ce logiciel est un programme informatique servant à déployer des + configurations de serveurs via NixOS. + + Ce logiciel est régi par la licence CeCILL soumise au droit français et + respectant les principes de diffusion des logiciels libres. Vous pouvez + utiliser, modifier et/ou redistribuer ce programme sous les conditions + de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA + sur le site "http://www.cecill.info". + + En contrepartie de l'accessibilité au code source et des droits de copie, + de modification et de redistribution accordés par cette licence, il n'est + offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, + seule une responsabilité restreinte pèse sur l'auteur du programme, le + titulaire des droits patrimoniaux et les concédants successifs. + + A cet égard l'attention de l'utilisateur est attirée sur les risques + associés au chargement, à l'utilisation, à la modification et/ou au + développement et à la reproduction du logiciel par l'utilisateur étant + donné sa spécificité de logiciel libre, qui peut le rendre complexe à + manipuler et qui le réserve donc à des développeurs et des professionnels + avertis possédant des connaissances informatiques approfondies. Les + utilisateurs sont donc invités à charger et tester l'adéquation du + logiciel à leurs besoins dans des conditions permettant d'assurer la + sécurité de leurs systèmes et ou de leurs données et, plus généralement, + à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. + + Le fait que vous puissiez accéder à cet en-tête signifie que vous avez + pris connaissance de la licence CeCILL, et que vous en avez accepté les + termes. +*/ + +let + sources = import ./npins; + pkgs = import sources.nixpkgs { }; + + pre-commit-check = (import sources.pre-commit-hooks).run { + src = ./.; + + hooks = { + # Nix Hooks + statix.enable = true; + deadnix.enable = true; + rfc101 = { + enable = true; + + name = "RFC-101 formatting"; + entry = "${pkgs.lib.getExe pkgs.nixfmt-rfc-style}"; + files = "\\.nix$"; + }; + + # Misc Hooks + commitizen.enable = true; + }; + }; +in + +{ + shells = { + default = pkgs.mkShell { + name = "dgnum-infra"; + + packages = + ( + with pkgs; + [ + npins + colmena + nixos-generators + ] + ++ (builtins.map (p: callPackage p { }) [ (sources.disko + "/package.nix") ]) + ) + ++ (import ./scripts { inherit pkgs; }); + + shellHook = '' + ${pre-commit-check.shellHook} + ''; + + preferLocalBuild = true; + }; + + pre-commit = pkgs.mkShell { + name = "pre-commit-shell"; + + shellHook = '' + ${pre-commit-check.shellHook} + ''; + }; + }; +} diff --git a/external/netbox/default.nix b/external/netbox/default.nix index e97fc00..4de9690 100644 --- a/external/netbox/default.nix +++ b/external/netbox/default.nix @@ -1,4 +1,5 @@ -{ config, pkgs, ... }: { +{ config, pkgs, ... }: +{ imports = [ ./secrets ]; services = { @@ -8,8 +9,7 @@ listenAddress = "127.0.0.1"; settings = { ALLOWED_HOSTS = [ "netbox.dgnum.sinavir.fr" ]; - REMOTE_AUTH_BACKEND = - "social_core.backends.open_id_connect.OpenIdConnectAuth"; + REMOTE_AUTH_BACKEND = "social_core.backends.open_id_connect.OpenIdConnectAuth"; }; extraConfig = '' @@ -27,12 +27,8 @@ enableACME = true; forceSSL = true; - locations."/".proxyPass = - "http://${config.services.netbox.listenAddress}:${ - builtins.toString config.services.netbox.port - }"; - locations."/static/".alias = - "${config.services.netbox.dataDir}/static/"; + locations."/".proxyPass = "http://${config.services.netbox.listenAddress}:${builtins.toString config.services.netbox.port}"; + locations."/static/".alias = "${config.services.netbox.dataDir}/static/"; }; }; @@ -50,5 +46,8 @@ }; users.users.nginx.extraGroups = [ "netbox" ]; - networking.firewall.allowedTCPPorts = [ 443 80 ]; + networking.firewall.allowedTCPPorts = [ + 443 + 80 + ]; } diff --git a/external/netbox/secrets/secrets.nix b/external/netbox/secrets/secrets.nix index fb94c7c..9541d2b 100644 --- a/external/netbox/secrets/secrets.nix +++ b/external/netbox/secrets/secrets.nix @@ -6,10 +6,15 @@ let inherit ((import ../../../meta).members) groups; - publicKeys = lib.splitString "\n" - (builtins.readFile (./maurice.keys)) # maurice servers' keys + publicKeys = + lib.splitString "\n" (builtins.readFile (./maurice.keys)) # maurice servers' keys ++ nix-lib.getAllKeys (groups.netbox ++ groups.root); -in { - "netbox.age" = { inherit publicKeys; }; - "netbox_env.age" = { inherit publicKeys; }; +in +{ + "netbox.age" = { + inherit publicKeys; + }; + "netbox_env.age" = { + inherit publicKeys; + }; } diff --git a/hive.nix b/hive.nix index badb3b3..e4e4ca4 100644 --- a/hive.nix +++ b/hive.nix @@ -6,32 +6,34 @@ let patch = import sources.nix-patches { patchFile = ./patches; }; - mkNode = node: - { name, nodes, pkgs, ... }: { - # Import the base configuration for each node - imports = builtins.map (lib.mkRel ./machines/${node}) [ - "_configuration.nix" - "_hardware-configuration.nix" - ]; + mkNode = node: _: { + # Import the base configuration for each node + imports = builtins.map (lib.mkRel ./machines/${node}) [ + "_configuration.nix" + "_hardware-configuration.nix" + ]; - # Include default secrets - age-secrets.sources = [ ./machines/${node}/secrets ]; + # Include default secrets + age-secrets.sources = [ ./machines/${node}/secrets ]; - # Deployment config is specified in meta.nodes.${node}.deployment - inherit (metadata.nodes.${node}) deployment; + # Deployment config is specified in meta.nodes.${node}.deployment + inherit (metadata.nodes.${node}) deployment; - # Set NIX_PATH to the patched version of nixpkgs - nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ]; - nix.optimise.automatic = true; + # Set NIX_PATH to the patched version of nixpkgs + nix.nixPath = [ "nixpkgs=${mkNixpkgs node}" ]; + nix.optimise.automatic = true; - # Allow unfree packages - nixpkgs.config.allowUnfree = true; + # Allow unfree packages + nixpkgs.config.allowUnfree = true; - # Use the stateVersion declared in the metadata - system = { inherit (metadata.nodes.${node}) stateVersion; }; + # Use the stateVersion declared in the metadata + system = { + inherit (metadata.nodes.${node}) stateVersion; }; + }; - mkNixpkgs = node: + mkNixpkgs = + node: patch.mkNixpkgsSrc rec { src = sources.${version}; version = "nixos-${metadata.nodes.${node}.nixpkgs}"; @@ -42,9 +44,12 @@ let ### # Function to create arguments based on the node # - mkArgs = node: - let lib' = (mkNixpkgs' node).lib; - in { + mkArgs = + node: + let + lib' = (mkNixpkgs' node).lib; + in + { lib = import sources.nix-lib { lib = lib'; keysRoot = ./keys; @@ -52,8 +57,8 @@ let }; nodes = builtins.attrNames metadata.nodes; - -in { +in +{ meta = { nodeNixpkgs = lib.mapSingleFuse mkNixpkgs' nodes; @@ -65,8 +70,9 @@ in { nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes; }; - defaults = { pkgs, ... }: { + defaults = _: { # Import the default modules imports = [ ./modules ]; }; -} // (lib.mapSingleFuse mkNode nodes) +} +// (lib.mapSingleFuse mkNode nodes) diff --git a/iso/configuration.nix b/iso/configuration.nix index 8adfdd1..f41040b 100644 --- a/iso/configuration.nix +++ b/iso/configuration.nix @@ -34,5 +34,6 @@ in }; users.users.root.openssh.authorizedKeys.keyFiles = - builtins.map (m: dgn-lib.mkRel ../keys "${m}.keys") dgn-members; + builtins.map (m: dgn-lib.mkRel ../keys "${m}.keys") + dgn-members; } diff --git a/iso/nixpkgs.nix b/iso/nixpkgs.nix index 73a6d6a..339b092 100644 --- a/iso/nixpkgs.nix +++ b/iso/nixpkgs.nix @@ -2,4 +2,7 @@ let inherit (import ../npins) nixpkgs; in -(import nixpkgs { }).srcOnly { name = "nixpkgs-for-iso"; src = nixpkgs; } +(import nixpkgs { }).srcOnly { + name = "nixpkgs-for-iso"; + src = nixpkgs; +} diff --git a/lib/default.nix b/lib/default.nix index d7a330c..0d05a74 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -3,20 +3,24 @@ _: let sources = import ../npins; - nix-lib = (import sources.nix-lib { - inherit ((import sources.nixpkgs { })) lib; + nix-lib = + (import sources.nix-lib { + inherit ((import sources.nixpkgs { })) lib; - keysRoot = ../keys; - }).extra; - -in nix-lib // (with nix-lib; { + keysRoot = ../keys; + }).extra; +in +nix-lib +// (with nix-lib; { # Get publickeys associated to a node - getNodeKeys = node: + getNodeKeys = + node: let meta = import ../meta; names = builtins.foldl' (names: group: names ++ meta.members.groups.${group}) - (meta.nodes.${node}.admins ++ [ "/machines/${node}" ]) - (meta.nodes.${node}.adminGroups ++ [ "root" ]); - in getAllKeys names; + (meta.nodes.${node}.admins ++ [ "/machines/${node}" ]) + (meta.nodes.${node}.adminGroups ++ [ "root" ]); + in + getAllKeys names; }) diff --git a/machines/compute01/_hardware-configuration.nix b/machines/compute01/_hardware-configuration.nix index 7f75d72..c433754 100644 --- a/machines/compute01/_hardware-configuration.nix +++ b/machines/compute01/_hardware-configuration.nix @@ -29,6 +29,5 @@ fsType = "vfat"; }; - swapDevices = - [{ device = "/dev/disk/by-uuid/30547280-00e9-4ee1-8a07-d116590d9fbf"; }]; + swapDevices = [ { device = "/dev/disk/by-uuid/30547280-00e9-4ee1-8a07-d116590d9fbf"; } ]; } diff --git a/machines/compute01/ds-fr/default.nix b/machines/compute01/ds-fr/default.nix index bf2d95c..06bd035 100644 --- a/machines/compute01/ds-fr/default.nix +++ b/machines/compute01/ds-fr/default.nix @@ -1,7 +1,9 @@ { config, ... }: -let host = "demarches.dgnum.eu"; -in { +let + host = "demarches.dgnum.eu"; +in +{ imports = [ ./module.nix ]; services.demarches-simplifiees = { @@ -62,5 +64,7 @@ in { }; }; - age-secrets.matches."^ds_fr-.*$" = { owner = "ds-fr"; }; + age-secrets.matches."^ds_fr-.*$" = { + owner = "ds-fr"; + }; } diff --git a/machines/compute01/ds-fr/module.nix b/machines/compute01/ds-fr/module.nix index 220979c..1fe9ff1 100644 --- a/machines/compute01/ds-fr/module.nix +++ b/machines/compute01/ds-fr/module.nix @@ -31,15 +31,26 @@ # The fact that you are presently reading this means that you have had # knowledge of the CeCILL license and that you accept its terms. -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) - mdDoc mkDefault mkEnableOption mkIf mkOption + mdDoc + mkDefault + mkEnableOption + mkIf + mkOption - optional optionalString + optional + optionalString - types; + types + ; cfg = config.services.demarches-simplifiees; @@ -64,16 +75,14 @@ let $SUDO ${cfg.package}/bin/$BIN "$@" ''; - -in { +in +{ options.services.demarches-simplifiees = { enable = mkEnableOption "demarches-simplifiees."; package = mkOption { type = types.package; - default = pkgs.callPackage ./package { - inherit (cfg) initialDeploymentDate dataDir logDir; - }; + default = pkgs.callPackage ./package { inherit (cfg) initialDeploymentDate dataDir logDir; }; }; user = mkOption { @@ -127,15 +136,17 @@ in { description = "Demarches Simplifiees setup"; wantedBy = [ "multi-user.target" ]; - path = [ pkgs.bash ds-fr ]; + path = [ + pkgs.bash + ds-fr + ]; after = [ "postgresql.service" ]; serviceConfig = { Type = "oneshot"; User = cfg.user; Group = cfg.group; - EnvironmentFile = [ env ] - ++ (optional (cfg.secretFile != null) cfg.secretFile); + EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile); StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr"; }; @@ -155,14 +166,19 @@ in { ds-fr-work = { description = "Demarches Simplifiees work service"; - wantedBy = [ "multi-user.target" "ds-fr.service" ]; - after = [ "network.target" "ds-fr-setup.service" ]; + wantedBy = [ + "multi-user.target" + "ds-fr.service" + ]; + after = [ + "network.target" + "ds-fr-setup.service" + ]; requires = [ "ds-fr-setup.service" ]; serviceConfig = { ExecStart = "${ds-fr}/bin/ds-fr rails jobs:work"; - EnvironmentFile = [ env ] - ++ (optional (cfg.secretFile != null) cfg.secretFile); + EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile); User = cfg.user; Group = cfg.group; StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; @@ -174,15 +190,17 @@ in { description = "Demarches Simplifiees web service"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" "ds-fr-setup.service" ]; + after = [ + "network.target" + "ds-fr-setup.service" + ]; requires = [ "ds-fr-setup.service" ]; path = [ pkgs.imagemagick ]; serviceConfig = { ExecStart = "${ds-fr}/bin/ds-fr rails server"; Environment = [ "RAILS_QUEUE_ADAPTER=delayed_job" ]; - EnvironmentFile = [ env ] - ++ (optional (cfg.secretFile != null) cfg.secretFile); + EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile); User = cfg.user; Group = cfg.group; StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; @@ -192,171 +210,173 @@ in { }; services = { - demarches-simplifiees.settings = (builtins.mapAttrs (_: mkDefault) { - RAILS_ENV = "production"; - RAILS_ROOT = builtins.toString cfg.package; + demarches-simplifiees.settings = + (builtins.mapAttrs (_: mkDefault) { + RAILS_ENV = "production"; + RAILS_ROOT = builtins.toString cfg.package; - # Application host name - # - # Examples: - # * For local development: localhost:3000 - # * For preproduction: staging.ds.example.org - # * For production: ds.example.org - APP_HOST = "localhost:3000"; + # Application host name + # + # Examples: + # * For local development: localhost:3000 + # * For preproduction: staging.ds.example.org + # * For production: ds.example.org + APP_HOST = "localhost:3000"; - # Rails key for signing sensitive data - # See https://guides.rubyonrails.org/security.html - # - # For production you MUST generate a new key, and keep it secret. - # Secrets must be long and random. Use bin/rails secret to get new unique secrets. + # Rails key for signing sensitive data + # See https://guides.rubyonrails.org/security.html + # + # For production you MUST generate a new key, and keep it secret. + # Secrets must be long and random. Use bin/rails secret to get new unique secrets. - # Secret key for One-Time-Password codes, used for 2-factors authentication - # OTP_SECRET_KEY = ""; + # Secret key for One-Time-Password codes, used for 2-factors authentication + # OTP_SECRET_KEY = ""; - # Protect access to the instance with a static login/password (useful for staging environments) - BASIC_AUTH_ENABLED = "disabled"; - BASIC_AUTH_USERNAME = ""; - BASIC_AUTH_PASSWORD = ""; + # Protect access to the instance with a static login/password (useful for staging environments) + BASIC_AUTH_ENABLED = "disabled"; + BASIC_AUTH_USERNAME = ""; + BASIC_AUTH_PASSWORD = ""; - # ActiveStorage service to use for attached files. - # Possible values: - # - "local": store files on the local filesystem - # - "amazon": store files remotely on an S3 storage service - # - "openstack": store files remotely on an OpenStack storage service - # - # (See config/storage.yml for the configuration of each service.) - ACTIVE_STORAGE_SERVICE = "local"; + # ActiveStorage service to use for attached files. + # Possible values: + # - "local": store files on the local filesystem + # - "amazon": store files remotely on an S3 storage service + # - "openstack": store files remotely on an OpenStack storage service + # + # (See config/storage.yml for the configuration of each service.) + ACTIVE_STORAGE_SERVICE = "local"; - # Configuration for the OpenStack storage service (if enabled) - FOG_OPENSTACK_API_KEY = ""; - FOG_OPENSTACK_USERNAME = ""; - FOG_OPENSTACK_URL = ""; - FOG_OPENSTACK_REGION = ""; - DS_PROXY_URL = ""; + # Configuration for the OpenStack storage service (if enabled) + FOG_OPENSTACK_API_KEY = ""; + FOG_OPENSTACK_USERNAME = ""; + FOG_OPENSTACK_URL = ""; + FOG_OPENSTACK_REGION = ""; + DS_PROXY_URL = ""; - # SAML - SAML_IDP_ENABLED = "disabled"; + # SAML + SAML_IDP_ENABLED = "disabled"; - # External service: authentication through France Connect - FC_PARTICULIER_ID = ""; - FC_PARTICULIER_SECRET = ""; - FC_PARTICULIER_BASE_URL = ""; + # External service: authentication through France Connect + FC_PARTICULIER_ID = ""; + FC_PARTICULIER_SECRET = ""; + FC_PARTICULIER_BASE_URL = ""; - # External service: authentication through Agent Connect - AGENT_CONNECT_ID = ""; - AGENT_CONNECT_SECRET = ""; - AGENT_CONNECT_BASE_URL = ""; - AGENT_CONNECT_JWKS = ""; - AGENT_CONNECT_REDIRECT = ""; + # External service: authentication through Agent Connect + AGENT_CONNECT_ID = ""; + AGENT_CONNECT_SECRET = ""; + AGENT_CONNECT_BASE_URL = ""; + AGENT_CONNECT_JWKS = ""; + AGENT_CONNECT_REDIRECT = ""; - # External service: integration with HelpScout (optional) - HELPSCOUT_MAILBOX_ID = ""; - HELPSCOUT_CLIENT_ID = ""; - HELPSCOUT_CLIENT_SECRET = ""; - HELPSCOUT_WEBHOOK_SECRET = ""; + # External service: integration with HelpScout (optional) + HELPSCOUT_MAILBOX_ID = ""; + HELPSCOUT_CLIENT_ID = ""; + HELPSCOUT_CLIENT_SECRET = ""; + HELPSCOUT_WEBHOOK_SECRET = ""; - # External service: external supervision - SENTRY_ENABLED = "disabled"; - SENTRY_CURRENT_ENV = "development"; - SENTRY_DSN_RAILS = ""; - SENTRY_DSN_JS = ""; + # External service: external supervision + SENTRY_ENABLED = "disabled"; + SENTRY_CURRENT_ENV = "development"; + SENTRY_DSN_RAILS = ""; + SENTRY_DSN_JS = ""; - # External service: Matomo web analytics - MATOMO_ENABLED = "disabled"; - MATOMO_COOKIE_DOMAIN = "*.www.demarches-simplifiees.fr"; - MATOMO_DOMAIN = "*.www.demarches-simplifiees.fr"; - MATOMO_ID = ""; - MATOMO_HOST = "matomo.example.org"; + # External service: Matomo web analytics + MATOMO_ENABLED = "disabled"; + MATOMO_COOKIE_DOMAIN = "*.www.demarches-simplifiees.fr"; + MATOMO_DOMAIN = "*.www.demarches-simplifiees.fr"; + MATOMO_ID = ""; + MATOMO_HOST = "matomo.example.org"; - # Default SMTP Provider: Mailjet - MAILJET_API_KEY = ""; - MAILJET_SECRET_KEY = ""; + # Default SMTP Provider: Mailjet + MAILJET_API_KEY = ""; + MAILJET_SECRET_KEY = ""; - # Alternate SMTP Provider: SendInBlue/DoList - SENDINBLUE_CLIENT_KEY = ""; - SENDINBLUE_SMTP_KEY = ""; - SENDINBLUE_USER_NAME = ""; - # SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc" + # Alternate SMTP Provider: SendInBlue/DoList + SENDINBLUE_CLIENT_KEY = ""; + SENDINBLUE_SMTP_KEY = ""; + SENDINBLUE_USER_NAME = ""; + # SENDINBLUE_LOGIN_URL="https://app.sendinblue.com/account/saml/login/truc" - # Alternate SMTP Provider: Mailtrap (mail catcher for staging environments) - # When enabled, all emails will be sent using this provider - MAILTRAP_ENABLED = "disabled"; - MAILTRAP_USERNAME = ""; - MAILTRAP_PASSWORD = ""; + # Alternate SMTP Provider: Mailtrap (mail catcher for staging environments) + # When enabled, all emails will be sent using this provider + MAILTRAP_ENABLED = "disabled"; + MAILTRAP_USERNAME = ""; + MAILTRAP_PASSWORD = ""; - # Alternative SMTP Provider: Mailcatcher (Catches mail and serves it through a dream.) - # When enabled, all emails will be sent using this provider - MAILCATCHER_ENABLED = "disabled"; - MAILCATCHER_HOST = ""; - MAILCATCHER_PORT = ""; + # Alternative SMTP Provider: Mailcatcher (Catches mail and serves it through a dream.) + # When enabled, all emails will be sent using this provider + MAILCATCHER_ENABLED = "disabled"; + MAILCATCHER_HOST = ""; + MAILCATCHER_PORT = ""; - # External service: live chat for admins (specific to démarches-simplifiées.fr) - CRISP_ENABLED = "disabled"; - CRISP_CLIENT_KEY = ""; + # External service: live chat for admins (specific to démarches-simplifiées.fr) + CRISP_ENABLED = "disabled"; + CRISP_CLIENT_KEY = ""; - # API Entreprise credentials - # https://api.gouv.fr/api/api-entreprise.html - API_ENTREPRISE_KEY = ""; + # API Entreprise credentials + # https://api.gouv.fr/api/api-entreprise.html + API_ENTREPRISE_KEY = ""; - # External service: CRM for following admin accounts pipeline (specific to démarches-simplifiées.fr) - PIPEDRIVE_KEY = ""; + # External service: CRM for following admin accounts pipeline (specific to démarches-simplifiées.fr) + PIPEDRIVE_KEY = ""; - # Networks bypassing the email login token that verifies new devices, and rack-attack throttling - TRUSTED_NETWORKS = ""; + # Networks bypassing the email login token that verifies new devices, and rack-attack throttling + TRUSTED_NETWORKS = ""; - # External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr) - SKYLIGHT_AUTHENTICATION_KEY = ""; - # "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0"; + # External service: mesuring performance of the Rails app (specific to démarches-simplifiées.fr) + SKYLIGHT_AUTHENTICATION_KEY = ""; + # "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0"; - # Enable or disable Lograge logs - LOGRAGE_ENABLED = "disabled"; + # Enable or disable Lograge logs + LOGRAGE_ENABLED = "disabled"; - # Logs source for Lograge - # - # Examples: - # * For local development: tps_local - # * For preproduction: tps_staging - # * For production: tps_prod - LOGRAGE_SOURCE = "tps_prod"; + # Logs source for Lograge + # + # Examples: + # * For local development: tps_local + # * For preproduction: tps_staging + # * For production: tps_prod + LOGRAGE_SOURCE = "tps_prod"; - # External service: timestamping a daily archive of dossiers status changes - UNIVERSIGN_API_URL = "https://ws.universign.eu/tsa/post/"; - UNIVERSIGN_USERPWD = ""; + # External service: timestamping a daily archive of dossiers status changes + UNIVERSIGN_API_URL = "https://ws.universign.eu/tsa/post/"; + UNIVERSIGN_USERPWD = ""; - # External service: API Geo / Adresse - API_ADRESSE_URL = "https://api-adresse.data.gouv.fr"; - API_GEO_URL = "https://geo.api.gouv.fr"; + # External service: API Geo / Adresse + API_ADRESSE_URL = "https://api-adresse.data.gouv.fr"; + API_GEO_URL = "https://geo.api.gouv.fr"; - # External service: API Education - API_EDUCATION_URL = "https://data.education.gouv.fr/api/records/1.0"; + # External service: API Education + API_EDUCATION_URL = "https://data.education.gouv.fr/api/records/1.0"; - # Encryption key for sensitive columns in the database - ENCRYPTION_SERVICE_SALT = ""; + # Encryption key for sensitive columns in the database + ENCRYPTION_SERVICE_SALT = ""; - # ActiveRecord encryption keys. Generate them with bin/rails db:encryption:init (you can omit deterministic_key) - AR_ENCRYPTION_PRIMARY_KEY = ""; - AR_ENCRYPTION_KEY_DERIVATION_SALT = ""; + # ActiveRecord encryption keys. Generate them with bin/rails db:encryption:init (you can omit deterministic_key) + AR_ENCRYPTION_PRIMARY_KEY = ""; + AR_ENCRYPTION_KEY_DERIVATION_SALT = ""; - # Salt for invisible_captcha session data. - # Must be the same value for all app instances behind a load-balancer. - INVISIBLE_CAPTCHA_SECRET = "kikooloool"; + # Salt for invisible_captcha session data. + # Must be the same value for all app instances behind a load-balancer. + INVISIBLE_CAPTCHA_SECRET = "kikooloool"; - # Clamav antivirus usage - CLAMAV_ENABLED = "disabled"; + # Clamav antivirus usage + CLAMAV_ENABLED = "disabled"; - # Siret number used for API Entreprise, by default we use SIRET from dinum - API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret"; - }) // { - # Database credentials - DB_DATABASE = "ds-fr"; - DB_USERNAME = cfg.user; - DB_PASSWORD = ""; - DB_HOST = "/run/postgresql"; - DB_POOL = ""; + # Siret number used for API Entreprise, by default we use SIRET from dinum + API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret"; + }) + // { + # Database credentials + DB_DATABASE = "ds-fr"; + DB_USERNAME = cfg.user; + DB_PASSWORD = ""; + DB_HOST = "/run/postgresql"; + DB_POOL = ""; - # Log on stdout - RAILS_LOG_TO_STDOUT = true; - }; + # Log on stdout + RAILS_LOG_TO_STDOUT = true; + }; postgresql = { enable = true; @@ -368,8 +388,7 @@ in { ensureDBOwnership = true; }; - extraPlugins = with config.services.postgresql.package.pkgs; - [ postgis ]; + extraPlugins = with config.services.postgresql.package.pkgs; [ postgis ]; }; nginx = { @@ -381,7 +400,9 @@ in { root = "${cfg.package}/public/"; locations."/".tryFiles = "$uri @proxy"; - locations."@proxy" = { proxyPass = "http://127.0.0.1:3000"; }; + locations."@proxy" = { + proxyPass = "http://127.0.0.1:3000"; + }; }; }; }; diff --git a/machines/compute01/ds-fr/package/default.nix b/machines/compute01/ds-fr/package/default.nix index 12d0cad..2d92a7f 100644 --- a/machines/compute01/ds-fr/package/default.nix +++ b/machines/compute01/ds-fr/package/default.nix @@ -1,6 +1,18 @@ -{ lib, stdenv, fetchFromGitHub, git, fetchYarnDeps, yarn, fixup_yarn_lock, imagemagick -, nodejs, ruby_3_2, bundlerEnv, logDir ? "/var/log/ds-fr" -, dataDir ? "/var/lib/ds-fr", initialDeploymentDate ? "17941030" }: +{ + lib, + stdenv, + fetchFromGitHub, + git, + fetchYarnDeps, + yarn, + fixup_yarn_lock, + nodejs, + ruby_3_2, + bundlerEnv, + logDir ? "/var/log/ds-fr", + dataDir ? "/var/lib/ds-fr", + initialDeploymentDate ? "17941030", +}: let pname = "ds-fr"; @@ -43,7 +55,12 @@ let }; buildInputs = [ rubyEnv ]; - nativeBuildInputs = [ fixup_yarn_lock nodejs yarn rubyEnv.wrappedRuby ]; + nativeBuildInputs = [ + fixup_yarn_lock + nodejs + yarn + rubyEnv.wrappedRuby + ]; RAILS_ENV = "production"; NODE_ENV = "dev"; @@ -53,8 +70,9 @@ let ./patches/build.patch ]; - postPatch = builtins.concatStringsSep "\n" - (builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches); + postPatch = builtins.concatStringsSep "\n" ( + builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches + ); OTP_SECRET_KEY = "precompile_placeholder"; SECRET_KEY_BASE = "precompile_placeholder"; @@ -82,8 +100,8 @@ let }; dgn-patches = import ./dgnum.nix { }; - -in stdenv.mkDerivation { +in +stdenv.mkDerivation { name = "demarches-simplifiees.fr-${version}"; inherit src; @@ -98,8 +116,9 @@ in stdenv.mkDerivation { ./patches/secrets-fc.patch ]; - postPatch = builtins.concatStringsSep "\n" - (builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches); + postPatch = builtins.concatStringsSep "\n" ( + builtins.map (p: "${git}/bin/git apply -p1 < ${p}") dgn-patches + ); buildPhase = '' rm -rf public @@ -132,8 +151,7 @@ in stdenv.mkDerivation { meta = with lib; { description = "Dématérialiser et simplifier les démarches administratives"; - homepage = - "https://github.com/demarches-simplifiees/demarches-simplifiees.fr"; + homepage = "https://github.com/demarches-simplifiees/demarches-simplifiees.fr"; license = licenses.agpl3Only; maintainers = with maintainers; [ thubrecht ]; }; diff --git a/machines/compute01/ds-fr/package/dgnum.nix b/machines/compute01/ds-fr/package/dgnum.nix index a3e6208..01492df 100644 --- a/machines/compute01/ds-fr/package/dgnum.nix +++ b/machines/compute01/ds-fr/package/dgnum.nix @@ -1,6 +1,5 @@ _: -builtins.map (id: - builtins.fetchurl - "https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${id}.patch") -[ "0b9b32483a700ad3060b3d4ef723d5f40c290c62" ] +builtins.map + (id: builtins.fetchurl "https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${id}.patch") + [ "0b9b32483a700ad3060b3d4ef723d5f40c290c62" ] diff --git a/machines/compute01/ds-fr/package/meta.nix b/machines/compute01/ds-fr/package/meta.nix index e267331..0be863b 100644 --- a/machines/compute01/ds-fr/package/meta.nix +++ b/machines/compute01/ds-fr/package/meta.nix @@ -1,5 +1,5 @@ { - version = "2024-01-31-02"; - src-hash = "sha256-4ATsSXbjkIMGn5yuyYiI+N+C2R/MSzecMLs5hWCCAM4="; - deps-hash = "sha256-UR5K6DQMvmpWWTH8O9/zJ3Nd+Kkl7xofktFdmBB9z6M="; + version = "2024-01-31-02"; + src-hash = "sha256-4ATsSXbjkIMGn5yuyYiI+N+C2R/MSzecMLs5hWCCAM4="; + deps-hash = "sha256-UR5K6DQMvmpWWTH8O9/zJ3Nd+Kkl7xofktFdmBB9z6M="; } diff --git a/machines/compute01/ds-fr/package/rubyEnv/gemset.nix b/machines/compute01/ds-fr/package/rubyEnv/gemset.nix index 4248dd7..147edce 100644 --- a/machines/compute01/ds-fr/package/rubyEnv/gemset.nix +++ b/machines/compute01/ds-fr/package/rubyEnv/gemset.nix @@ -1,687 +1,896 @@ { aasm = { - dependencies = ["concurrent-ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ "concurrent-ruby" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "05j0rdhdzc628v5nyzrazp4704hh96j5sjbn48zxyk4v3a61f4m2"; type = "gem"; }; version = "5.2.0"; }; acsv = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "162vpm9d7acp8g8xvvfhafrpljqxkdcgrg7v9fzgr39cbpsvhvz7"; type = "gem"; }; version = "0.0.1"; }; actioncable = { - dependencies = ["actionpack" "activesupport" "nio4r" "websocket-driver"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "nio4r" + "websocket-driver" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "117vxic67jnw6q637kmsb3ryj0x485295pz9a9y4z8xn9bdlsl0z"; type = "gem"; }; version = "7.0.8"; }; actionmailbox = { - dependencies = ["actionpack" "activejob" "activerecord" "activestorage" "activesupport" "mail" "net-imap" "net-pop" "net-smtp"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activejob" + "activerecord" + "activestorage" + "activesupport" + "mail" + "net-imap" + "net-pop" + "net-smtp" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1r8ldj2giaz8cn49qkdqn5zc29gbsr5ky4fg6r7ali0yh1xh684l"; type = "gem"; }; version = "7.0.8"; }; actionmailer = { - dependencies = ["actionpack" "actionview" "activejob" "activesupport" "mail" "net-imap" "net-pop" "net-smtp" "rails-dom-testing"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "actionpack" + "actionview" + "activejob" + "activesupport" + "mail" + "net-imap" + "net-pop" + "net-smtp" + "rails-dom-testing" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0w6gvj7ybniq89834hqww9rj2xypz9l91f8niwaws2yq1qklymr2"; type = "gem"; }; version = "7.0.8"; }; actionpack = { - dependencies = ["actionview" "activesupport" "rack" "rack-test" "rails-dom-testing" "rails-html-sanitizer"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "actionview" + "activesupport" + "rack" + "rack-test" + "rails-dom-testing" + "rails-html-sanitizer" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1l319p0gipfgq8bp8dvbv97qqb72rad9zcqn5snhgv20cmpqr69b"; type = "gem"; }; version = "7.0.8"; }; actiontext = { - dependencies = ["actionpack" "activerecord" "activestorage" "activesupport" "globalid" "nokogiri"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activerecord" + "activestorage" + "activesupport" + "globalid" + "nokogiri" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0i47r3n2m8qm002gx7c0lx1pv15pr2zy57dm8j38x960rsb655pp"; type = "gem"; }; version = "7.0.8"; }; actionview = { - dependencies = ["activesupport" "builder" "erubi" "rails-dom-testing" "rails-html-sanitizer"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "activesupport" + "builder" + "erubi" + "rails-dom-testing" + "rails-html-sanitizer" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xnpdwj1d8m6c2d90jp9cs50ggiz0jj02ls2h9lg68k4k8mnjbd2"; type = "gem"; }; version = "7.0.8"; }; active_model_serializers = { - dependencies = ["actionpack" "activemodel" "case_transform" "jsonapi-renderer"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activemodel" + "case_transform" + "jsonapi-renderer" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xdp7cpj3yj3wl4vj0nqq44kzjavlxi1wq3cf9zp0whkir0ym0gy"; type = "gem"; }; version = "0.10.13"; }; active_storage_validations = { - dependencies = ["activejob" "activemodel" "activestorage" "activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activejob" + "activemodel" + "activestorage" + "activesupport" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1k8m8l79hfnab15znaz8hvpxz3l52kibfhdjxy94ipvil857szsp"; type = "gem"; }; version = "0.9.6"; }; activejob = { - dependencies = ["activesupport" "globalid"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "activesupport" + "globalid" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1cn1ic7ml75jm0c10s7cm5mvcgfnafj0kjvvjavpjcxgz6lxcqyb"; type = "gem"; }; version = "7.0.8"; }; activemodel = { - dependencies = ["activesupport"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "004w8zaz2g3y6lnrsvlcmljll0m3ndqpgwf0wfscgq6iysibiglm"; type = "gem"; }; version = "7.0.8"; }; activerecord = { - dependencies = ["activemodel" "activesupport"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "activemodel" + "activesupport" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "04wavps80q3pvhvfbmi4gs102y1p6mxbg8xylzvib35b6m92adpj"; type = "gem"; }; version = "7.0.8"; }; activestorage = { - dependencies = ["actionpack" "activejob" "activerecord" "activesupport" "marcel" "mini_mime"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activejob" + "activerecord" + "activesupport" + "marcel" + "mini_mime" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0d6vm6alsp0g6f3548b615zxbz8l2wrmaikwgsf8kv11wf6swb4c"; type = "gem"; }; version = "7.0.8"; }; activestorage-openstack = { - dependencies = ["fog-openstack" "marcel" "rails"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "fog-openstack" + "marcel" + "rails" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1jrrp2n4p9wwnrsbf9wlghgcy74nswaiyvrxfkfli57hscj9fdl6"; type = "gem"; }; version = "1.6.0"; }; activesupport = { - dependencies = ["concurrent-ruby" "i18n" "minitest" "tzinfo"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "i18n" + "minitest" + "tzinfo" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "188kbwkn1lbhz40ala8ykp20jzqphgc68g3d8flin8cqa2xid0s5"; type = "gem"; }; version = "7.0.8"; }; addressable = { - dependencies = ["public_suffix"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "public_suffix" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0irbdwkkjwzajq1ip6ba46q49sxnrl2cw7ddkdhsfhb6aprnm3vr"; type = "gem"; }; version = "2.8.6"; }; administrate = { - dependencies = ["actionpack" "actionview" "activerecord" "jquery-rails" "kaminari" "sassc-rails" "selectize-rails"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "actionview" + "activerecord" + "jquery-rails" + "kaminari" + "sassc-rails" + "selectize-rails" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "00hlp3i6imkmvppby8bzpf24n486h5xiqnlglvxsfg95l5nk1jwq"; type = "gem"; }; version = "0.18.0"; }; administrate-field-enum = { - dependencies = ["administrate"]; - groups = ["default"]; - platforms = []; + dependencies = [ "administrate" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0mgc91nwz0jl3nsm9qk5q6z8qhgvf3iqbckh61jlw2sgrr7dfiq1"; type = "gem"; }; version = "0.0.9"; }; aes_key_wrap = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "19bn0y70qm6mfj4y1m0j3s8ggh6dvxwrwrj5vfamhdrpddsz8ddr"; type = "gem"; }; version = "1.1.0"; }; after_party = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "11g8w209w1fzg9058j8gmfgsn26zp6zwaq4liwxyg021lpc8fmcl"; type = "gem"; }; version = "1.11.2"; }; ancestry = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activerecord" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "183wbrpriw4yamlm5zkng66vm3760s19qnzc5vq9l8aw837nngxg"; type = "gem"; }; version = "4.3.3"; }; anchored = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0lbmfqwlk08hfqz2a2jdby72x3m0vpdf47l4dyw37x4xiischvzl"; type = "gem"; }; version = "1.1.0"; }; ast = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "04nc8x27hlzlrr5c2gn7mar4vdr0apw5xg22wp6m8dx3wqr04a0y"; type = "gem"; }; version = "2.4.2"; }; attr_required = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1g22axmi2rhhy7w8c3x6gppsawxqavbrnxpnmphh22fk7cwi0kh2"; type = "gem"; }; version = "1.0.1"; }; axe-core-api = { - dependencies = ["dumb_delegator" "virtus"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ + "dumb_delegator" + "virtus" + ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0bx67lskxslfd2mpim3kqrxa4sx4qhvnpjpr57j1ll2xppyl9kw8"; type = "gem"; }; version = "4.8.0"; }; axe-core-rspec = { - dependencies = ["axe-core-api" "dumb_delegator" "virtus"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "axe-core-api" + "dumb_delegator" + "virtus" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "07niarqd2lrbgnw00biyigc48lbdv4vy68p57myliz7k82nizidj"; type = "gem"; }; version = "4.8.0"; }; axiom-types = { - dependencies = ["descendants_tracker" "ice_nine" "thread_safe"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ + "descendants_tracker" + "ice_nine" + "thread_safe" + ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10q3k04pll041mkgy0m5fn2b1lazm6ly1drdbcczl5p57lzi3zy1"; type = "gem"; }; version = "0.1.1"; }; axlsx_styler = { - dependencies = ["activesupport" "caxlsx"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "caxlsx" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1g486p337qv6c771x8kz18siy9zbrgjnq5gyz2zsmnanxh7kpmxg"; type = "gem"; }; version = "1.1.0"; }; bcrypt = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "14crcsmcsyiskr9xzgzcfz2dr74zg1jvavrrxpf5vnn9q75fakz9"; type = "gem"; }; version = "3.1.19"; }; benchmark-ips = { - groups = ["development"]; - platforms = []; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1jyvyciwah3qxkcxjdaf0lx0fr0567kipc77wxq29d2xw1dlvp89"; type = "gem"; }; version = "2.12.0"; }; better_html = { - dependencies = ["actionview" "activesupport" "ast" "erubi" "html_tokenizer" "parser" "smart_properties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionview" + "activesupport" + "ast" + "erubi" + "html_tokenizer" + "parser" + "smart_properties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1sssv94gg7bnxiqn5pbbpf8rdnmw3iyj2qwn2pbgxxs8xmmq158b"; type = "gem"; }; version = "1.0.16"; }; bindata = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06lqi4svq5qls9f7nnvd2zmjdqmi2sf82sq78ci5d78fq0z5x2vr"; type = "gem"; }; version = "2.4.10"; }; bindex = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0zmirr3m02p52bzq4xgksq4pn8j641rx5d4czk68pv9rqnfwq7kv"; type = "gem"; }; version = "0.8.1"; }; bootsnap = { - dependencies = ["msgpack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "msgpack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "18prmylz53gsw651f0sibb2mvdxgd2zzdzh6a9a1idpqhyxcnbg7"; type = "gem"; }; version = "1.9.3"; }; brakeman = { - groups = ["development"]; - platforms = []; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wzvxpabnjwwjgr9s13965dbdgl3qfvwjbmhimh83p81bm5lsrnw"; type = "gem"; }; version = "5.4.1"; }; brow = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1zsgsd9h2h3id5wy2jbmkackifv348n636apy3cjymk736q7vdxv"; type = "gem"; }; version = "0.4.1"; }; browser = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0g4bcpax07kqqr9cp7cjc7i0pcij4nqpn1rdsg2wdwhzf00m6x32"; type = "gem"; }; version = "5.3.1"; }; builder = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "045wzckxpwcqzrjr353cxnyaxgf0qg22jh00dcx7z38cys5g1jlr"; type = "gem"; }; version = "3.2.4"; }; capybara = { - dependencies = ["addressable" "matrix" "mini_mime" "nokogiri" "rack" "rack-test" "regexp_parser" "xpath"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "addressable" + "matrix" + "mini_mime" + "nokogiri" + "rack" + "rack-test" + "regexp_parser" + "xpath" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "114qm5f5vhwaaw9rj1h2lcamh46zl13v1m18jiw68zl961gwmw6n"; type = "gem"; }; version = "3.39.2"; }; capybara-email = { - dependencies = ["capybara" "mail"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "capybara" + "mail" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0vv9c3vldky1rfy3x20nz4a8ic0fg66x2223wbmv35n02ndxsrdb"; type = "gem"; }; version = "3.0.2"; }; capybara-screenshot = { - dependencies = ["capybara" "launchy"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "capybara" + "launchy" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xqc7hdiw1ql42mklpfvqd2pyfsxmy55cpx0h9y0jlkpl1q96sw1"; type = "gem"; }; version = "1.0.26"; }; case_transform = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0fzyws6spn5arqf6q604dh9mrj84a36k5hsc8z7jgcpfvhc49bg2"; type = "gem"; }; version = "0.2"; }; caxlsx = { - dependencies = ["htmlentities" "marcel" "nokogiri" "rubyzip"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "htmlentities" + "marcel" + "nokogiri" + "rubyzip" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1lx0dh0m1wnwqyf4ixvxkvdgim4rlmh5i5if624hj4z6mwlhpn70"; type = "gem"; }; version = "3.1.0"; }; charlock_holmes = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0hybw8jw9ryvz5zrki3gc9r88jqy373m6v46ynxsdzv1ysiyr40p"; type = "gem"; }; version = "0.7.7"; }; chartkick = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0838bglijxsv3yyl3xif7fvs1x7rn4sv2kld90b52ybyazvjsldh"; type = "gem"; }; version = "5.0.4"; }; choice = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0x6972zngnsvr3nd3iiy25d6ipi0cr21c1jxm0w1p4nlvzvig5m1"; type = "gem"; }; version = "0.2.0"; }; chunky_png = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1znw5x86hmm9vfhidwdsijz8m38pqgmv98l9ryilvky0aldv7mc9"; type = "gem"; }; version = "1.4.0"; }; clamav-client = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10mdaz695057kxpm3j802cagf1isxl57zzismvkzr5kajsvqdlim"; type = "gem"; }; version = "3.2.0"; }; coercible = { - dependencies = ["descendants_tracker"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ "descendants_tracker" ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1p5azydlsz0nkxmcq0i1gzmcfq02lgxc4as7wmf47j1c6ljav0ah"; type = "gem"; }; version = "1.0.0"; }; concurrent-ruby = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0krcwb6mn0iklajwngwsg850nk8k9b35dhmc2qkbdqvmifdi2y9q"; type = "gem"; }; version = "1.2.2"; }; connection_pool = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1x32mcpm2cl5492kd6lbjbaf17qsssmpx9kdyr7z1wcif2cwyh0g"; type = "gem"; }; version = "2.4.1"; }; content_disposition = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "05m5ipc81fj2pphlz1ms1yxq80ymilfjhprz790lafjlq6lks5da"; type = "gem"; }; version = "1.0.0"; }; crack = { - dependencies = ["rexml"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ "rexml" ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1cr1kfpw3vkhysvkk3wg7c54m75kd68mbm9rs5azdjdq57xid13r"; type = "gem"; }; version = "0.4.5"; }; crass = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0pfl5c0pyqaparxaqxi6s4gfl21bdldwiawrc0aknyvflli60lfw"; type = "gem"; }; version = "1.0.6"; }; css_parser = { - dependencies = ["addressable"]; - groups = ["default"]; - platforms = []; + dependencies = [ "addressable" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "18mii41bbl106rn940ah8v3xclj4yrxxa0bwlwp546244n9b83zp"; type = "gem"; }; version = "1.16.0"; }; daemons = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0l5gai3vd4g7aqff0k1mp41j9zcsvm2rbwmqn115a325k9r7pf4w"; type = "gem"; }; version = "1.3.1"; }; date = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "149jknsq999gnhy865n33fkk22s0r447k76x9pmcnnwldfv2q7wp"; type = "gem"; }; version = "3.3.4"; }; deep_cloneable = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activerecord" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0dychjkr6fbdnw6ynsrcjj6anghhcw3ghrx5073pc6y0wc7v8zn8"; type = "gem"; }; version = "3.2.0"; }; delayed_cron_job = { - dependencies = ["delayed_job"]; - groups = ["default"]; - platforms = []; + dependencies = [ "delayed_job" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1qsf7csnhyk787yx88ilsqris3h0gga3g6ri31hccdfbdab1f33a"; type = "gem"; }; version = "0.7.4"; }; delayed_job = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0s2xg72ljg4cwmr05zi67vcyz8zib46gvvf7rmrdhsyq387m2qcq"; type = "gem"; }; version = "4.1.11"; }; delayed_job_active_record = { - dependencies = ["activerecord" "delayed_job"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activerecord" + "delayed_job" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wh1146hg0b85zv336dn00jx9mzw5ma0maj67is7bvz5l35hd6yk"; type = "gem"; }; version = "4.1.7"; }; delayed_job_web = { - dependencies = ["activerecord" "delayed_job" "rack-protection" "sinatra"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activerecord" + "delayed_job" + "rack-protection" + "sinatra" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "01kbdbmzlbr5z0vn32llbr6fh9srk7884b1zsjif2v5x1qs9d13k"; type = "gem"; }; version = "1.4.4"; }; descendants_tracker = { - dependencies = ["thread_safe"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ "thread_safe" ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "15q8g3fcqyb41qixn6cky0k3p86291y7xsh1jfd851dvrza1vi79"; type = "gem"; }; version = "0.0.4"; }; devise = { - dependencies = ["bcrypt" "orm_adapter" "railties" "responders" "warden"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "bcrypt" + "orm_adapter" + "railties" + "responders" + "warden" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { fetchSubmodules = false; rev = "edffc79bf05d7f1c58ba50ffeda645e2e4ae0cb1"; @@ -692,2646 +901,3321 @@ version = "4.9.3"; }; devise-i18n = { - dependencies = ["devise"]; - groups = ["default"]; - platforms = []; + dependencies = [ "devise" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0cq4l25b17x0yc71kb3y77rc0idnpqcc30hsnl4i07h2s543arvg"; type = "gem"; }; version = "1.9.2"; }; devise-two-factor = { - dependencies = ["activesupport" "devise" "railties" "rotp"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "devise" + "railties" + "rotp" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hh0yc85ixnan90hibz3nba6pamhscxfr1zaymxgv3vw5icv50ya"; type = "gem"; }; version = "5.0.0"; }; diff-lcs = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0rwvjahnp7cpmracd8x732rjgnilqv2sx7d1gfrysslc3h039fa9"; type = "gem"; }; version = "1.5.0"; }; discard = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activerecord" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1xavjhccyyzn9z6fz3034vgvzprc983mbrq6n9sc0drfw7m3vrip"; type = "gem"; }; version = "1.2.1"; }; domain_name = { - dependencies = ["unf"]; - groups = ["default"]; - platforms = []; + dependencies = [ "unf" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0lcqjsmixjp52bnlgzh4lg9ppsk52x9hpwdjd53k8jnbah2602h0"; type = "gem"; }; version = "0.5.20190701"; }; dotenv = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0iym172c5337sm1x2ykc2i3f961vj3wdclbyg1x6sxs3irgfsl94"; type = "gem"; }; version = "2.7.6"; }; dotenv-rails = { - dependencies = ["dotenv" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "dotenv" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1my2jdmgmpf32rfxffkb9cyxh7ayis4q5ygpwjqj4vpp25y3a70c"; type = "gem"; }; version = "2.7.6"; }; dry-cli = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1w39jms4bsggxvl23cxanhccv1ngb6nqxsqhi784v5bjz1lx3si8"; type = "gem"; }; version = "1.0.0"; }; dry-core = { - dependencies = ["concurrent-ruby" "zeitwerk"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "zeitwerk" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "01gks2hrp7nl3pzb487azvd25dlbrc40d5cpk4n0szwnf2c0k4ks"; type = "gem"; }; version = "1.0.0"; }; dry-inflector = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "17mkdwglqsd9fg272y3zms7rixjgkb1km1xcb88ir5lxvk1jkky7"; type = "gem"; }; version = "0.2.0"; }; dry-monads = { - dependencies = ["concurrent-ruby" "dry-core" "zeitwerk"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "dry-core" + "zeitwerk" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06sh48d13gyb2lascfd5g2pyf1qxzinydgb0ir81kbwga3zqj0rv"; type = "gem"; }; version = "1.6.0"; }; dumb_delegator = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "151fdn7y0gqs7f6y3y7rn3frv0z359qrw9hb4s7avn6j2qc42ppz"; type = "gem"; }; version = "1.0.0"; }; ecma-re-validator = { - dependencies = ["regexp_parser"]; - groups = ["default"]; - platforms = []; + dependencies = [ "regexp_parser" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1mz0nsl2093jd94nygw8qs13rwfwl1ax76xz3ypinr5hqbc5pab6"; type = "gem"; }; version = "0.3.0"; }; elastic-apm = { - dependencies = ["concurrent-ruby" "http" "ruby2_keywords"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "http" + "ruby2_keywords" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0j56r0vykn3hlixziav7xwg981l5algi9xsngp4kbgir8wkjgm05"; type = "gem"; }; version = "4.6.0"; }; erubi = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "08s75vs9cxlc4r1q2bjg4br8g9wc5lc5x5vl0vv4zq5ivxsdpgi7"; type = "gem"; }; version = "1.12.0"; }; et-orbi = { - dependencies = ["tzinfo"]; - groups = ["default"]; - platforms = []; + dependencies = [ "tzinfo" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xr8i8ql4xzx17d12590i3j299hj6vc0ja2j29dy12i5nlchxrvp"; type = "gem"; }; version = "1.2.4"; }; ethon = { - dependencies = ["ffi"]; - groups = ["default"]; - platforms = []; + dependencies = [ "ffi" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0kd7c61f28f810fgxg480j7457nlvqarza9c2ra0zhav0dd80288"; type = "gem"; }; version = "0.15.0"; }; excon = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0mbkyyadz9vw7mzixi9dks6i6iw033yn2hzwfvnfdvgqq6ywqs4g"; type = "gem"; }; version = "0.102.0"; }; factory_bot = { - dependencies = ["activesupport"]; - groups = ["test"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "11ij9s4hasy963qjqbrrf0m8lm9m9pxkh2vf4wrnafa6gw6r9qk8"; type = "gem"; }; version = "6.1.0"; }; ffi = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1yvii03hcgqj30maavddqamqy50h7y6xcn2wcyq72wn823zl4ckd"; type = "gem"; }; version = "1.16.3"; }; ffi-compiler = { - dependencies = ["ffi" "rake"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "ffi" + "rake" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0c2caqm9wqnbidcb8dj4wd3s902z15qmgxplwyfyqbwa0ydki7q1"; type = "gem"; }; version = "1.0.1"; }; flipper = { - dependencies = ["brow" "concurrent-ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "brow" + "concurrent-ruby" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1jnwwq8qzk7b3xvhrc3pm401lysqmv3mcsv3r5wqpb0jxwgyl79q"; type = "gem"; }; version = "1.0.0"; }; flipper-active_record = { - dependencies = ["activerecord" "flipper"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activerecord" + "flipper" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "04knwacvqyf7g3q7rdp4svbkysr3j8j39381b8r49vilwj0xp5dp"; type = "gem"; }; version = "1.0.0"; }; flipper-ui = { - dependencies = ["erubi" "flipper" "rack" "rack-protection" "sanitize"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "erubi" + "flipper" + "rack" + "rack-protection" + "sanitize" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0123zfy3jarw7vbsk0wzbpwlrg778ivvvsr1c53xwbkkm0r5s858"; type = "gem"; }; version = "1.0.0"; }; fog-core = { - dependencies = ["builder" "excon" "formatador" "mime-types"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "builder" + "excon" + "formatador" + "mime-types" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06m6hxq8vspx9h9bgc2s19m56jzasvl45vblrfv1q5h1qg1k6amw"; type = "gem"; }; version = "2.3.0"; }; fog-json = { - dependencies = ["fog-core" "multi_json"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "fog-core" + "multi_json" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1zj8llzc119zafbmfa4ai3z5s7c4vp9akfs0f9l2piyvcarmlkyx"; type = "gem"; }; version = "1.2.0"; }; fog-openstack = { - dependencies = ["fog-core" "fog-json"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "fog-core" + "fog-json" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1xh9qs00l1d7rxsr9qjlba8dprh9km8ya06y59qf17vncihl1xa7"; type = "gem"; }; version = "1.1.0"; }; formatador = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1l06bv4avphbdmr1y4g0rqlczr38k6r65b3zghrbj2ynyhm3xqjl"; type = "gem"; }; version = "1.1.0"; }; fugit = { - dependencies = ["et-orbi" "raabro"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "et-orbi" + "raabro" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0sz6yx80zgj8yj7w3c95yyqg743hqp0szxlqpmpnbirmmfdb2r9y"; type = "gem"; }; version = "1.4.2"; }; geo_coord = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1s6p0zh39g8x3rgkkf5k02ypspnghmz3v3qkp56zmslxg72jskmf"; type = "gem"; }; version = "0.2.0"; }; geocoder = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "120lqyq308q8hg8ykawd7cp3k2ck8z9g5f9ffijp8dn2k9f21fjc"; type = "gem"; }; version = "1.8.2"; }; globalid = { - dependencies = ["activesupport"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1sbw6b66r7cwdx3jhs46s4lr991969hvigkjpbdl7y3i31qpdgvh"; type = "gem"; }; version = "1.2.1"; }; gon = { - dependencies = ["actionpack" "i18n" "multi_json" "request_store"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "i18n" + "multi_json" + "request_store" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1w6ji15jrl4p6q0gxy5mmqspvzbmgkqj1d3xmbqr0a1rb7b1i9p3"; type = "gem"; }; version = "6.4.0"; }; graphql = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0ihkydzvc773vb9lfbpn293j0h45calxrgmp3y0z6ns786zvpx7q"; type = "gem"; }; version = "2.0.24"; }; graphql-batch = { - dependencies = ["graphql" "promise.rb"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "graphql" + "promise.rb" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1znnjl7ykhp27p48by97hk83s2pa9fvn6zmx8aywmhw9pkbw8jq9"; type = "gem"; }; version = "0.5.1"; }; graphql-rails_logger = { - dependencies = ["actionpack" "activesupport" "railties" "rouge"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "railties" + "rouge" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0z792847jyaq9q0lai5r58q5kgiybbmsc0cwv024qfzmqzf03m06"; type = "gem"; }; version = "1.2.3"; }; graphql-schema_comparator = { - dependencies = ["graphql" "thor"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ + "graphql" + "thor" + ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0hf03rqpzjycz623glp9p3w2nxabiwmqy6pjzkwsjqq6w91wsr9p"; type = "gem"; }; version = "1.1.2"; }; groupdate = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0m7cbahlhd7akkizrn2rjp4g6y6wkg8s3dqas6rgjj1apx2hd535"; type = "gem"; }; version = "6.4.0"; }; haml = { - dependencies = ["temple" "thor" "tilt"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "temple" + "thor" + "tilt" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1w6lrad138dz3r4rva525r09n2wk54zc3zzanam067n6rkyi4j23"; type = "gem"; }; version = "6.0.5"; }; haml-lint = { - dependencies = ["haml_lint"]; - groups = ["development"]; - platforms = []; + dependencies = [ "haml_lint" ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "15g3g47bxvdjx6z6awl6wqqw1ddvf5vzjb09x8hb43dvdp8ba7sv"; type = "gem"; }; version = "0.999.999"; }; haml-rails = { - dependencies = ["actionpack" "activesupport" "haml" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "haml" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1sjrdwc4azzfpsp2xk0365z031482gcrs0c54d5wx0igkqca0fr7"; type = "gem"; }; version = "2.1.0"; }; haml_lint = { - dependencies = ["haml" "parallel" "rainbow" "rubocop" "sysexits"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "haml" + "parallel" + "rainbow" + "rubocop" + "sysexits" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "110fshcqm9dsl5vmrbmdcyr5nxan7svh48c7hhimz6miybigp8jr"; type = "gem"; }; version = "0.42.0"; }; hana = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "03cvrv2wl25j9n4n509hjvqnmwa60k92j741b64a1zjisr1dn9al"; type = "gem"; }; version = "1.3.7"; }; hashdiff = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1nynpl0xbj0nphqx1qlmyggq58ms1phf5i03hk64wcc0a17x1m1c"; type = "gem"; }; version = "1.0.1"; }; hashie = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "02bsx12ihl78x0vdm37byp78jjw2ff6035y7rrmbd90qxjwxr43q"; type = "gem"; }; version = "4.1.0"; }; highline = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0yclf57n2j3cw8144ania99h1zinf8q3f5zrhqa754j6gl95rp9d"; type = "gem"; }; version = "2.0.3"; }; html_tokenizer = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0dq6685sdzdn53mkzags6mvx3l0afcx6xma664zij6y3dxj2a7p8"; type = "gem"; }; version = "0.0.7"; }; htmlentities = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1nkklqsn8ir8wizzlakncfv42i32wc0w9hxp00hvdlgjr7376nhj"; type = "gem"; }; version = "4.3.4"; }; http = { - dependencies = ["addressable" "http-cookie" "http-form_data" "llhttp-ffi"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "addressable" + "http-cookie" + "http-form_data" + "llhttp-ffi" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bzb8p31kzv6q5p4z5xq88mnqk414rrw0y5rkhpnvpl29x5c3bpw"; type = "gem"; }; version = "5.1.1"; }; http-accept = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "09m1facypsdjynfwrcv19xcb1mqg8z6kk31g8r33pfxzh838c9n6"; type = "gem"; }; version = "1.7.0"; }; http-cookie = { - dependencies = ["domain_name"]; - groups = ["default"]; - platforms = []; + dependencies = [ "domain_name" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "004cgs4xg5n6byjs7qld0xhsjq3n6ydfh897myr2mibvh6fjc49g"; type = "gem"; }; version = "1.0.3"; }; http-form_data = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1wx591jdhy84901pklh1n9sgh74gnvq1qyqxwchni1yrc49ynknc"; type = "gem"; }; version = "2.3.0"; }; http_accept_language = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0d0nlfz9vm4jr1l6q0chx4rp2hrnrfbx3gadc1dz930lbbaz0hq0"; type = "gem"; }; version = "2.1.1"; }; httpclient = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "19mxmvghp7ki3klsxwrlwr431li7hm1lczhhj8z4qihl2acy8l99"; type = "gem"; }; version = "2.8.3"; }; i18n = { - dependencies = ["concurrent-ruby"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "concurrent-ruby" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0qaamqsh5f3szhcakkak8ikxlzxqnv49n2p7504hcz2l0f4nj0wx"; type = "gem"; }; version = "1.14.1"; }; i18n-tasks = { - dependencies = ["activesupport" "ast" "better_html" "erubi" "highline" "i18n" "parser" "rails-i18n" "rainbow" "terminal-table"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "ast" + "better_html" + "erubi" + "highline" + "i18n" + "parser" + "rails-i18n" + "rainbow" + "terminal-table" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hiblss98hmybs82xsaavhz1cwlhhx92jzlx8ypkriylxhhwmigk"; type = "gem"; }; version = "1.0.9"; }; i18n_data = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1jzrb3z8i0ny3wkh09x1xs04ay0q8lk1prvkbpwzr99jw9a2h8sc"; type = "gem"; }; version = "0.13.0"; }; iban-tools = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1lz6idka39qbh1vv8sp8kd5rzdmxi5452lx2ank63958jiww52by"; type = "gem"; }; version = "1.1.0"; }; ice_nine = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1nv35qg1rps9fsis28hz2cq2fx1i96795f91q4nmkm934xynll2x"; type = "gem"; }; version = "0.11.2"; }; image_processing = { - dependencies = ["mini_magick" "ruby-vips"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "mini_magick" + "ruby-vips" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1f32dzj77p9mfp4q95930vfkp80psf88phjc46jhf9ncl72ykffk"; type = "gem"; }; version = "1.12.2"; }; invisible_captcha = { - dependencies = ["rails"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rails" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0hn06njrwbxhxs2myr04fq3spqn38b8wm3irvkll91qv3p5yv0d3"; type = "gem"; }; version = "2.0.0"; }; io-console = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1fmwbcapyhla84xhwj3gfws6rb4lw3928ybz6g3lr372dgxakzx5"; type = "gem"; }; version = "0.7.1"; }; irb = { - dependencies = ["rdoc" "reline"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ + "rdoc" + "reline" + ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0phrzmmxbwqmkh4dzld3pc82yml996nzfdzjipniv8wwrxwbgb3r"; type = "gem"; }; version = "1.11.0"; }; job-iteration = { - dependencies = ["activejob"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activejob" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1br4chy8dzyrpvggyry9fqlk7sps9989qzl656ax9hzc9l7c8hvj"; type = "gem"; }; version = "1.4.1"; }; jquery-rails = { - dependencies = ["rails-dom-testing" "railties" "thor"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "rails-dom-testing" + "railties" + "thor" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0rxfy6mk1yh8yjkk7gd1908f85dkc60xnfplwz7mi09f6j3f812p"; type = "gem"; }; version = "4.5.1"; }; json = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0lrirj0gw420kw71bjjlqkqhqbrplla61gbv1jzgsz6bv90qr3ci"; type = "gem"; }; version = "2.5.1"; }; json-jwt = { - dependencies = ["activesupport" "aes_key_wrap" "bindata"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "aes_key_wrap" + "bindata" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0nzbk1mrbf9mnvjpn3bxy8a85rjf94qmfdnvk78mjzk8pa0fvgdr"; type = "gem"; }; version = "1.13.0"; }; json_schemer = { - dependencies = ["ecma-re-validator" "hana" "regexp_parser" "uri_template"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "ecma-re-validator" + "hana" + "regexp_parser" + "uri_template" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "03wfpkckl4i5dgywa1cxd71ph6hm15x6pnqkja196zdkfb647znd"; type = "gem"; }; version = "0.2.17"; }; jsonapi-renderer = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0ys4drd0k9rw5ixf8n8fx8v0pjh792w4myh0cpdspd317l1lpi5m"; type = "gem"; }; version = "0.2.2"; }; jwt = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0bg8pjx0mpvl10k6d8a6gc8dzlv2z5jkqcjbjcirnk032iriq838"; type = "gem"; }; version = "2.3.0"; }; kaminari = { - dependencies = ["activesupport" "kaminari-actionview" "kaminari-activerecord" "kaminari-core"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "kaminari-actionview" + "kaminari-activerecord" + "kaminari-core" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0gia8irryvfhcr6bsr64kpisbgdbqjsqfgrk12a11incmpwny1y4"; type = "gem"; }; version = "1.2.2"; }; kaminari-actionview = { - dependencies = ["actionview" "kaminari-core"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionview" + "kaminari-core" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "02f9ghl3a9b5q7l079d3yzmqjwkr4jigi7sldbps992rigygcc0k"; type = "gem"; }; version = "1.2.2"; }; kaminari-activerecord = { - dependencies = ["activerecord" "kaminari-core"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activerecord" + "kaminari-core" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0c148z97s1cqivzbwrak149z7kl1rdmj7dxk6rpkasimmdxsdlqd"; type = "gem"; }; version = "1.2.2"; }; kaminari-core = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1zw3pg6kj39y7jxakbx7if59pl28lhk98fx71ks5lr3hfgn6zliv"; type = "gem"; }; version = "1.2.2"; }; kredis = { - dependencies = ["activemodel" "activesupport" "redis"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activemodel" + "activesupport" + "redis" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "148dnrpqb058ddvbxhk0vh5brlpjb28zh0ml4cn1apq69rwxwqbh"; type = "gem"; }; version = "1.7.0"; }; launchy = { - dependencies = ["addressable"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "addressable" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1xdyvr5j0gjj7b10kgvh8ylxnwk3wx19my42wqn9h82r4p246hlm"; type = "gem"; }; version = "2.5.0"; }; letter_opener = { - dependencies = ["launchy"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "launchy" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "09a7kgsmr10a0hrc9bwxglgqvppjxij9w8bxx91mnvh0ivaw0nq9"; type = "gem"; }; version = "1.7.0"; }; letter_opener_web = { - dependencies = ["actionmailer" "letter_opener" "railties"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "actionmailer" + "letter_opener" + "railties" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0pianlrbf9n7jrqxpyxgsfk1j1d312d57d6gq7yxni6ax2q0293q"; type = "gem"; }; version = "1.4.0"; }; listen = { - dependencies = ["rb-fsevent" "rb-inotify"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "rb-fsevent" + "rb-inotify" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "13rgkfar8pp31z1aamxf5y7cfq88wv6rxxcwy7cmm177qq508ycn"; type = "gem"; }; version = "3.8.0"; }; llhttp-ffi = { - dependencies = ["ffi-compiler" "rake"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "ffi-compiler" + "rake" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "00dh6zmqdj59rhcya0l4b9aaxq6n8xizfbil93k0g06gndyk5xz5"; type = "gem"; }; version = "0.4.0"; }; lograge = { - dependencies = ["actionpack" "activesupport" "railties" "request_store"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "railties" + "request_store" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1vrjm4yqn5l6q5gsl72fmk95fl6j9z1a05gzbrwmsm3gp1a1bgac"; type = "gem"; }; version = "0.11.2"; }; logstash-event = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bk7fhhryjxp1klr3hq6i6srrc21wl4p980bysjp0w66z9hdr9w9"; type = "gem"; }; version = "1.2.02"; }; loofah = { - dependencies = ["crass" "nokogiri"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "crass" + "nokogiri" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1zkjqf37v2d7s11176cb35cl83wls5gm3adnfkn2zcc61h3nxmqh"; type = "gem"; }; version = "2.22.0"; }; mail = { - dependencies = ["mini_mime" "net-imap" "net-pop" "net-smtp"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "mini_mime" + "net-imap" + "net-pop" + "net-smtp" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bf9pysw1jfgynv692hhaycfxa8ckay1gjw5hz3madrbrynryfzc"; type = "gem"; }; version = "2.8.1"; }; mailjet = { - dependencies = ["activesupport" "rack" "rest-client"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "rack" + "rest-client" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0kbxxxhb3as0w3k2hkiv7zaygvr68r5y35zhbi88380g2nnqcv4v"; type = "gem"; }; version = "1.6.0"; }; maintenance_tasks = { - dependencies = ["actionpack" "activejob" "activerecord" "job-iteration" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activejob" + "activerecord" + "job-iteration" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1lxd0jm5l4cigqzn8q39y8c5ssqrbn2fkb0rdzkhzrnwj9n955ly"; type = "gem"; }; version = "2.3.2"; }; marcel = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0kky3yiwagsk8gfbzn3mvl2fxlh3b39v6nawzm4wpjs6xxvvc4x0"; type = "gem"; }; version = "1.0.2"; }; matrix = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1h2cgkpzkh3dd0flnnwfq6f3nl2b1zff9lvqz8xs853ssv5kq23i"; type = "gem"; }; version = "0.4.2"; }; memory_profiler = { - groups = ["development"]; - platforms = []; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0s8qaf19yr4lhvdxk3cy3ifc47cgxdz2jybg6hzxsy9gh88c1f7v"; type = "gem"; }; version = "1.0.0"; }; method_source = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1pnyh44qycnf9mzi1j6fywd5fkskv3x7nmsqrrws0rjn5dd4ayfp"; type = "gem"; }; version = "1.0.0"; }; mime-types = { - dependencies = ["mime-types-data"]; - groups = ["default"]; - platforms = []; + dependencies = [ "mime-types-data" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0q8d881k1b3rbsfcdi3fx0b5vpdr5wcrhn88r2d9j7zjdkxp5mw5"; type = "gem"; }; version = "3.5.1"; }; mime-types-data = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "17zdim7kzrh5j8c97vjqp4xp78wbyz7smdp4hi5iyzk0s9imdn5a"; type = "gem"; }; version = "3.2023.0808"; }; mina = { - dependencies = ["open4" "rake"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ + "open4" + "rake" + ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0h7cy17qd1z13irnlifpdqis9hnsjijbkj0qryprlmiccfshqxk5"; type = "gem"; }; version = "1.2.4"; }; mini_magick = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1aj604x11d9pksbljh0l38f70b558rhdgji1s9i763hiagvvx2hs"; type = "gem"; }; version = "4.11.0"; }; mini_mime = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1vycif7pjzkr29mfk4dlqv3disc5dn0va04lkwajlpr1wkibg0c6"; type = "gem"; }; version = "1.1.5"; }; mini_portile2 = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1kl9c3kdchjabrihdqfmcplk3lq4cw1rr9f378y6q22qwy5dndvs"; type = "gem"; }; version = "2.8.5"; }; minitest = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0bkmfi9mb49m0fkdhl2g38i3xxa02d411gg0m8x0gvbwfmmg5ym3"; type = "gem"; }; version = "5.20.0"; }; msgpack = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06iajjyhx0rvpn4yr3h1hc4w4w3k59bdmfhxnjzzh76wsrdxxrc6"; type = "gem"; }; version = "1.4.2"; }; multi_json = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z"; type = "gem"; }; version = "1.15.0"; }; mustermann = { - dependencies = ["ruby2_keywords"]; - groups = ["default"]; - platforms = []; + dependencies = [ "ruby2_keywords" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0rwbq20s2gdh8dljjsgj5s6wqqfmnbclhvv2c2608brv7jm6jdbd"; type = "gem"; }; version = "3.0.0"; }; net-imap = { - dependencies = ["date" "net-protocol"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "date" + "net-protocol" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0z9f6kfxz9qanar534gs3mk6snyvw8rnx3f6ykjn2jiziv0rv1ig"; type = "gem"; }; version = "0.4.9.1"; }; net-pop = { - dependencies = ["net-protocol"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "net-protocol" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1wyz41jd4zpjn0v1xsf9j778qx1vfrl24yc20cpmph8k42c4x2w4"; type = "gem"; }; version = "0.1.2"; }; net-protocol = { - dependencies = ["timeout"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "timeout" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1a32l4x73hz200cm587bc29q8q9az278syw3x6fkc9d1lv5y0wxa"; type = "gem"; }; version = "0.2.2"; }; net-smtp = { - dependencies = ["net-protocol"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "net-protocol" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0csspzqrg7s2v2wdp6vqqs1rra6w5ilpgnps5h52ig6rp7x2i389"; type = "gem"; }; version = "0.4.0.1"; }; netrc = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0gzfmcywp1da8nzfqsql2zqi648mfnx6qwkig3cv36n9m0yy676y"; type = "gem"; }; version = "0.11.0"; }; nio4r = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xkjz56qc7hl7zy7i7bhiyw5pl85wwjsa4p70rj6s958xj2sd1lm"; type = "gem"; }; version = "2.7.0"; }; nokogiri = { - dependencies = ["mini_portile2" "racc"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "mini_portile2" + "racc" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1l8b0i24h4irivyhwy9xmkjbggw86cxkzkiqdqg0jpcp9qc8h4rl"; type = "gem"; }; version = "1.16.0"; }; open4 = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1cgls3f9dlrpil846q0w7h66vsc33jqn84nql4gcqkk221rh7px1"; type = "gem"; }; version = "1.3.4"; }; openid_connect = { - dependencies = ["activemodel" "attr_required" "json-jwt" "rack-oauth2" "swd" "tzinfo" "validate_email" "validate_url" "webfinger"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activemodel" + "attr_required" + "json-jwt" + "rack-oauth2" + "swd" + "tzinfo" + "validate_email" + "validate_url" + "webfinger" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0w474bz3s1hqhilvrddr33l2nkyikypaczp3808w0345jr88b5m7"; type = "gem"; }; version = "1.3.0"; }; orm_adapter = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1fg9jpjlzf5y49qs9mlpdrgs5rpcyihq1s4k79nv9js0spjhnpda"; type = "gem"; }; version = "0.5.0"; }; parallel = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0jcc512l38c0c163ni3jgskvq1vc3mr8ly5pvjijzwvfml9lf597"; type = "gem"; }; version = "1.23.0"; }; parsby = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1swwcyzc1h1fr344ad0xlyad0470znfi617mk8sv98xgwq24z5qc"; type = "gem"; }; version = "1.1.1"; }; parser = { - dependencies = ["ast" "racc"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "ast" + "racc" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "181faqz59p2mbfab5q4l1r298pq0nxl0k85rjcb58g0lardmv321"; type = "gem"; }; version = "3.3.0.2"; }; pdf-core = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1fz0yj4zrlii2j08kaw11j769s373ayz8jrdhxwwjzmm28pqndjg"; type = "gem"; }; version = "0.9.0"; }; pg = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "07m6lxljabw9kyww5k5lgsxsznsm1v5l14r1la09gqka9b5kv3yr"; type = "gem"; }; version = "1.4.6"; }; phonelib = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10grpnng2bkf3szmadkn2mkq95rk5a0jl72x1qq4bxsr6b6liyzz"; type = "gem"; }; version = "0.6.53"; }; prawn = { - dependencies = ["pdf-core" "ttfunk"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "pdf-core" + "ttfunk" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1g9avv2rprsjisdk137s9ljr05r7ajhm78hxa1vjsv0jyx22f1l2"; type = "gem"; }; version = "2.4.0"; }; prawn-rails = { - dependencies = ["prawn" "prawn-table" "rails"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "prawn" + "prawn-table" + "rails" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1wxjs8wmkfd2zc864irpkddjapb1a9ncsiybmx4lx8dxbzxhsycm"; type = "gem"; }; version = "1.3.0"; }; prawn-table = { - dependencies = ["prawn"]; - groups = ["default"]; - platforms = []; + dependencies = [ "prawn" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1nxd6qmxqwl850icp18wjh5k0s3amxcajdrkjyzpfgq0kvilcv9k"; type = "gem"; }; version = "0.2.2"; }; premailer = { - dependencies = ["addressable" "css_parser" "htmlentities"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "addressable" + "css_parser" + "htmlentities" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1ni7h8wcfzr9lsmcw25gdhmr11j9wm4d6jv2mb8zsnx7qkmkb2ak"; type = "gem"; }; version = "1.22.0"; }; premailer-rails = { - dependencies = ["actionmailer" "premailer"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionmailer" + "premailer" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0q23clzqgzxcg1jld7hn5jy2yqxvana3iw66vmjgzz7y4ylf97b6"; type = "gem"; }; version = "1.11.1"; }; "promise.rb" = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0a819sikcqvhi8hck1y10d1nv2qkjvmmm553626fmrh51h2i089d"; type = "gem"; }; version = "0.7.4"; }; psych = { - dependencies = ["stringio"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "stringio" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0s5383m6004q76xm3lb732bp4sjzb6mxb6rbgn129gy2izsj4wrk"; type = "gem"; }; version = "5.1.2"; }; public_suffix = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bni4qjrsh2q49pnmmd6if4iv3ak36bd2cckrs6npl111n769k9m"; type = "gem"; }; version = "5.0.4"; }; puma = { - dependencies = ["nio4r"]; - groups = ["default"]; - platforms = []; + dependencies = [ "nio4r" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0i2vaww6qcazj0ywva1plmjnj6rk23b01szswc5jhcq7s2cikd1y"; type = "gem"; }; version = "6.4.2"; }; pundit = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "17z2f7w3syh3c04c8m1v9pvb9pfpymk8b5plszr5l24hx374xvsd"; type = "gem"; }; version = "2.2.0"; }; raabro = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10m8bln9d00dwzjil1k42i5r7l82x25ysbi45fwyv4932zsrzynl"; type = "gem"; }; version = "1.4.0"; }; racc = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "01b9662zd2x9bp4rdjfid07h09zxj7kvn7f5fghbqhzc625ap1dp"; type = "gem"; }; version = "1.7.3"; }; rack = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "15rdwbyk71c9nxvd527bvb8jxkcys8r3dj3vqra5b3sa63qs30vv"; type = "gem"; }; version = "2.2.8"; }; rack-attack = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0kiixzpazjqgljjy1ngfz1by5vz6kjx0d4mf1fq7b3ywpfjf80lq"; type = "gem"; }; version = "6.5.0"; }; rack-mini-profiler = { - dependencies = ["rack"]; - groups = ["development"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "121fqk18x1bd52c2bkz8wkvv9nkgpqphj5aycnb7lkf67jkwic0h"; type = "gem"; }; version = "3.0.0"; }; rack-oauth2 = { - dependencies = ["activesupport" "attr_required" "httpclient" "json-jwt" "rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "attr_required" + "httpclient" + "json-jwt" + "rack" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0gxxr209r8h3nxhc9h731khv6yswiv9hc6q2pg672v530xmknznw"; type = "gem"; }; version = "1.19.0"; }; rack-protection = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1a12m1mv8dc0g90fs1myvis8vsgr427k1arg1q4a9qlfw6fqyhis"; type = "gem"; }; version = "3.0.5"; }; rack-proxy = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "12jw7401j543fj8cc83lmw72d8k6bxvkp9rvbifi88hh01blnsj4"; type = "gem"; }; version = "0.7.7"; }; rack-test = { - dependencies = ["rack"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1ysx29gk9k14a14zsp5a8czys140wacvp91fja8xcja0j1hzqq8c"; type = "gem"; }; version = "2.1.0"; }; rack_session_access = { - dependencies = ["builder" "rack"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "builder" + "rack" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0swd35lg7qmqhc3pglvsanq2indnvw360m8qxfxwqabl0br9isq3"; type = "gem"; }; version = "0.2.0"; }; rails = { - dependencies = ["actioncable" "actionmailbox" "actionmailer" "actionpack" "actiontext" "actionview" "activejob" "activemodel" "activerecord" "activestorage" "activesupport" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actioncable" + "actionmailbox" + "actionmailer" + "actionpack" + "actiontext" + "actionview" + "activejob" + "activemodel" + "activerecord" + "activestorage" + "activesupport" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0rsqin156dawz7gzpy1ijs02afqcr4704vqj56s6yxng3a9ayhwf"; type = "gem"; }; version = "7.0.8"; }; rails-controller-testing = { - dependencies = ["actionpack" "actionview" "activesupport"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "actionpack" + "actionview" + "activesupport" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "151f303jcvs8s149mhx2g5mn67487x0blrf9dzl76q1nb7dlh53l"; type = "gem"; }; version = "1.0.5"; }; rails-dom-testing = { - dependencies = ["activesupport" "minitest" "nokogiri"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "activesupport" + "minitest" + "nokogiri" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0fx9dx1ag0s1lr6lfr34lbx5i1bvn3bhyf3w3mx6h7yz90p725g5"; type = "gem"; }; version = "2.2.0"; }; rails-erd = { - dependencies = ["activerecord" "activesupport" "choice" "ruby-graphviz"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "activerecord" + "activesupport" + "choice" + "ruby-graphviz" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0dnj1vasfh3349sbxq6279ky377fqmf5pfnjfnl9wxrf6idygbpa"; type = "gem"; }; version = "1.6.1"; }; rails-html-sanitizer = { - dependencies = ["loofah" "nokogiri"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "loofah" + "nokogiri" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1pm4z853nyz1bhhqr7fzl44alnx4bjachcr6rh6qjj375sfz3sc6"; type = "gem"; }; version = "1.6.0"; }; rails-i18n = { - dependencies = ["i18n" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "i18n" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1lrbrx88ic42adcj36wip3dk1svmqld1f7qksngi4b9kqnc8w5g3"; type = "gem"; }; version = "7.0.3"; }; railties = { - dependencies = ["actionpack" "activesupport" "method_source" "rake" "thor" "zeitwerk"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "method_source" + "rake" + "thor" + "zeitwerk" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0sfc16zrcn4jgf5xczb08n6prhmqqgg9f0b4mn73zlzg6cwmqchj"; type = "gem"; }; version = "7.0.8"; }; rainbow = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0smwg4mii0fm38pyb5fddbmrdpifwv22zv3d3px2xx497am93503"; type = "gem"; }; version = "3.1.1"; }; rake = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1ilr853hawi09626axx0mps4rkkmxcs54mapz9jnqvpnlwd3wsmy"; type = "gem"; }; version = "13.1.0"; }; rake-progressbar = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wynsd94kh3mrp5c1n1bvkvbcpvqq8nqnn0i9xjh2mk8k6cgqipr"; type = "gem"; }; version = "0.0.5"; }; rb-fsevent = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1zmf31rnpm8553lqwibvv3kkx0v7majm1f341xbxc0bk5sbhp423"; type = "gem"; }; version = "0.11.2"; }; rb-inotify = { - dependencies = ["ffi"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "ffi" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1jm76h8f8hji38z3ggf4bzi8vps6p7sagxn3ab57qc0xyga64005"; type = "gem"; }; version = "0.10.1"; }; rdoc = { - dependencies = ["psych"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "psych" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "14wnrpd1kl43ynk1wwwgv9avsw84d1lrvlfyrjy3d4h7h7ndnqzp"; type = "gem"; }; version = "6.6.2"; }; redcarpet = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1sg9sbf9pm91l7lac7fs4silabyn0vflxwaa2x3lrzsm0ff8ilca"; type = "gem"; }; version = "3.6.0"; }; redis = { - dependencies = ["redis-client"]; - groups = ["default"]; - platforms = []; + dependencies = [ "redis-client" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10r5z5mg1x5kjx3wvwx5d8bqgd2j8pc4dlaasq7nmnl3nsn7sn9k"; type = "gem"; }; version = "5.0.6"; }; redis-client = { - dependencies = ["connection_pool"]; - groups = ["default"]; - platforms = []; + dependencies = [ "connection_pool" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "013p2968vqrr282yvxp3pyy5vn0nrgdppzqywbwbfjq2kkwx2fx9"; type = "gem"; }; version = "0.18.0"; }; regexp_parser = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "136br91alxdwh1s85z912dwz23qlhm212vy6i3wkinz3z8mkxxl3"; type = "gem"; }; version = "2.8.1"; }; reline = { - dependencies = ["io-console"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "io-console" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0fhwdmw89zqb1fdxcd6lr57zabbfi08z8j6kqwngak0xnxi2j10l"; type = "gem"; }; version = "0.4.2"; }; request_store = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0cx74kispmnw3ljwb239j65a2j14n8jlsygy372hrsa8mxc71hxi"; type = "gem"; }; version = "1.5.0"; }; responders = { - dependencies = ["actionpack" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06ilkbbwvc8d0vppf8ywn1f79ypyymlb9krrhqv4g0q215zaiwlj"; type = "gem"; }; version = "3.1.1"; }; rest-client = { - dependencies = ["http-accept" "http-cookie" "mime-types" "netrc"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "http-accept" + "http-cookie" + "mime-types" + "netrc" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1qs74yzl58agzx9dgjhcpgmzfn61fqkk33k1js2y5yhlvc5l19im"; type = "gem"; }; version = "2.1.0"; }; rexml = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "05i8518ay14kjbma550mv0jm8a6di8yp5phzrd8rj44z9qnrlrp0"; type = "gem"; }; version = "3.2.6"; }; rodf = { - dependencies = ["builder" "dry-inflector" "rubyzip"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "builder" + "dry-inflector" + "rubyzip" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1h2jflga597bdrlz7m1n58sx8a3bnrn8z3npal7v2wz2a2wx2xn0"; type = "gem"; }; version = "1.1.1"; }; rotp = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "10mmzc85y7andsich586ndykw678qn1ns2wpjxrg0sc0gr4w3pig"; type = "gem"; }; version = "6.2.2"; }; rouge = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1dnfkrk8xx2m8r3r9m2p5xcq57viznyc09k7r3i4jbm758i57lx3"; type = "gem"; }; version = "3.30.0"; }; rqrcode = { - dependencies = ["chunky_png" "rqrcode_core"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "chunky_png" + "rqrcode_core" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0f1cv9a9sjqc898qm3h7zmkhwglrjw5blsskbg3gsaws01d4bc47"; type = "gem"; }; version = "1.2.0"; }; rqrcode_core = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "00kqasqja8zyzqvlgiwd9r0wndqk01qk5j68a8lhlz4ayrd4qy0y"; type = "gem"; }; version = "0.2.0"; }; rspec-core = { - dependencies = ["rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "rspec-support" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0l95bnjxdabrn79hwdhn2q1n7mn26pj7y1w5660v5qi81x458nqm"; type = "gem"; }; version = "3.12.2"; }; rspec-expectations = { - dependencies = ["diff-lcs" "rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "diff-lcs" + "rspec-support" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "05j44jfqlv7j2rpxb5vqzf9hfv7w8ba46wwgxwcwd8p0wzi1hg89"; type = "gem"; }; version = "3.12.3"; }; rspec-mocks = { - dependencies = ["diff-lcs" "rspec-support"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ + "diff-lcs" + "rspec-support" + ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hfm17xakfvwya236graj6c2arr4sb9zasp35q5fykhyz8mhs0w2"; type = "gem"; }; version = "3.12.5"; }; rspec-rails = { - dependencies = ["actionpack" "activesupport" "railties" "rspec-core" "rspec-expectations" "rspec-mocks" "rspec-support"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "railties" + "rspec-core" + "rspec-expectations" + "rspec-mocks" + "rspec-support" + ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0d3fnabkaw8n0na2dpnlg2xygggj51djzpj9x6y5rkiqbfyqwv01"; type = "gem"; }; version = "6.0.1"; }; rspec-retry = { - dependencies = ["rspec-core"]; - groups = ["test"]; - platforms = []; + dependencies = [ "rspec-core" ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0n6qc0d16h6bgh1xarmc8vc58728mgjcsjj8wcd822c8lcivl0b1"; type = "gem"; }; version = "0.6.2"; }; rspec-support = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "12y52zwwb3xr7h91dy9k3ndmyyhr3mjcayk0nnarnrzz8yr48kfx"; type = "gem"; }; version = "3.12.0"; }; rspec_junit_formatter = { - dependencies = ["rspec-core"]; - groups = ["test"]; - platforms = []; + dependencies = [ "rspec-core" ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1aynmrgnv26pkprrajvp7advb8nbh0x4pkwk6jwq8qmwzarzk21p"; type = "gem"; }; version = "0.4.1"; }; rubocop = { - dependencies = ["json" "parallel" "parser" "rainbow" "regexp_parser" "rexml" "rubocop-ast" "ruby-progressbar" "unicode-display_width"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "json" + "parallel" + "parser" + "rainbow" + "regexp_parser" + "rexml" + "rubocop-ast" + "ruby-progressbar" + "unicode-display_width" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0l46lw5gfj3mcm982wpmx7br4rs466gyislv0hfwcsk8dxhv1zkw"; type = "gem"; }; version = "1.50.2"; }; rubocop-ast = { - dependencies = ["parser"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "parser" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0n2gsafg6p7nr1z8i1hkvp2qqkkbg842ba183dnl0h08xd9ms6q5"; type = "gem"; }; version = "1.28.0"; }; rubocop-capybara = { - dependencies = ["rubocop"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "rubocop" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1pz52ml0qbxgcjlmp8y0wsq8xy398n6ypkbrwfaa8zb0v7pscj6n"; type = "gem"; }; version = "2.17.1"; }; rubocop-performance = { - dependencies = ["rubocop" "rubocop-ast"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "rubocop" + "rubocop-ast" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1z6i24r0485fxa5n4g3rhp88w589fifszhd1khbzya2iiknkjxkr"; type = "gem"; }; version = "1.17.1"; }; rubocop-rails = { - dependencies = ["activesupport" "rack" "rubocop"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "activesupport" + "rack" + "rubocop" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0j6dn8pz70bngx6van8yzsimpdd93gm7c8lr93wz1j4ahm6q4hn9"; type = "gem"; }; version = "2.19.1"; }; rubocop-rspec = { - dependencies = ["rubocop" "rubocop-capybara"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "rubocop" + "rubocop-capybara" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0ydmr0qhldrndh86zy87yyl17i1mcxfv83jzb6lmx18cghkz7lpd"; type = "gem"; }; version = "2.20.0"; }; ruby-graphviz = { - dependencies = ["rexml"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "rexml" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "010m283gk4qgzxkgrldlnrglh8d5fn6zvrzm56wf5abd7x7b8aqw"; type = "gem"; }; version = "1.2.5"; }; ruby-progressbar = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0cwvyb7j47m7wihpfaq7rc47zwwx9k4v7iqd9s1xch5nm53rrz40"; type = "gem"; }; version = "1.13.0"; }; ruby-vips = { - dependencies = ["ffi"]; - groups = ["default"]; - platforms = []; + dependencies = [ "ffi" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "19pzpx406rr9s3qk527rn9y3b76sjq5pi7y0xzqiy50q3k0hhg7g"; type = "gem"; }; version = "2.1.4"; }; ruby2_keywords = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz"; type = "gem"; }; version = "0.0.5"; }; rubyzip = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0grps9197qyxakbpw02pda59v45lfgbgiyw48i0mq9f2bn9y6mrz"; type = "gem"; }; version = "2.3.2"; }; saml_idp = { - dependencies = ["activesupport" "builder" "nokogiri" "rexml" "xmlenc"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "builder" + "nokogiri" + "rexml" + "xmlenc" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0h57ls13k0f3rni5lf1xy2mv9g6f80c8x0fnv9yc5g4hyj44af9m"; type = "gem"; }; version = "0.14.0"; }; sanitize = { - dependencies = ["crass" "nokogiri"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "crass" + "nokogiri" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wsw05y0h1ln3x2kvcw26fs9ivryb4xbjrb4hsk2pishkhydkz4j"; type = "gem"; }; version = "6.1.0"; }; sass = { - dependencies = ["sass-listen"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ "sass-listen" ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0p95lhs0jza5l7hqci1isflxakz83xkj97lkvxl919is0lwhv2w0"; type = "gem"; }; version = "3.7.4"; }; sass-listen = { - dependencies = ["rb-fsevent" "rb-inotify"]; - groups = ["default" "development"]; - platforms = []; + dependencies = [ + "rb-fsevent" + "rb-inotify" + ]; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xw3q46cmahkgyldid5hwyiwacp590zj2vmswlll68ryvmvcp7df"; type = "gem"; }; version = "4.0.0"; }; sassc = { - dependencies = ["ffi"]; - groups = ["default"]; - platforms = []; + dependencies = [ "ffi" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0gpqv48xhl8mb8qqhcifcp0pixn206a7imc07g48armklfqa4q2c"; type = "gem"; }; version = "2.4.0"; }; sassc-rails = { - dependencies = ["railties" "sassc" "sprockets" "sprockets-rails" "tilt"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "railties" + "sassc" + "sprockets" + "sprockets-rails" + "tilt" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1d9djmwn36a5m8a83bpycs48g8kh1n2xkyvghn7dr6zwh4wdyksz"; type = "gem"; }; version = "2.1.2"; }; scss_lint = { - dependencies = ["sass"]; - groups = ["development"]; - platforms = []; + dependencies = [ "sass" ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0nrpgwvpmyxzlw0c580kd4dhfqp5185ckdc32nw83kfxrphx1lma"; type = "gem"; }; version = "0.60.0"; }; selectize-rails = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1adzp7b3qyl4ki1432mga914za0j9dzy7401vs92kl4avr40nns2"; type = "gem"; }; version = "0.12.6"; }; selenium-devtools = { - dependencies = ["selenium-webdriver"]; - groups = ["test"]; - platforms = []; + dependencies = [ "selenium-webdriver" ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "07qfhkviz26ahf21wjm9ijk33qy0v4q5m151mb804va1y8wl9jhz"; type = "gem"; }; version = "0.114.0"; }; selenium-webdriver = { - dependencies = ["rexml" "rubyzip" "websocket"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "rexml" + "rubyzip" + "websocket" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "037v9w6rwkdi9msydiyj31pxdlh4vcr8h8w3g1mzanbsas2m1b1a"; type = "gem"; }; version = "4.13.1"; }; sentry-delayed_job = { - dependencies = ["delayed_job" "sentry-ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "delayed_job" + "sentry-ruby" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0cpyjwbfsq50jnz0rp9y8ffc6r22g2lgf8bi04c37n691mrvayq2"; type = "gem"; }; version = "5.9.0"; }; sentry-rails = { - dependencies = ["railties" "sentry-ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "railties" + "sentry-ruby" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1krl5ahgnb6bh8p5f2w8642jvsdf2qx3n0jwwz59yk3czbwagn3i"; type = "gem"; }; version = "5.9.0"; }; sentry-ruby = { - dependencies = ["concurrent-ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ "concurrent-ruby" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "140bbc709vwhi330mxb78c6ca5l7n97vpwqdwa068pv3dnzxbzj8"; type = "gem"; }; version = "5.9.0"; }; sentry-sidekiq = { - dependencies = ["sentry-ruby" "sidekiq"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "sentry-ruby" + "sidekiq" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1z5q9rb924qarh2sfl6zqgrg7yam1k5zqdr7qg3gqfzn7aylp11i"; type = "gem"; }; version = "5.9.0"; }; shoulda-matchers = { - dependencies = ["activesupport"]; - groups = ["test"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1qi7gzli00mqlaq9an28m6xd323k7grgq19r6dqa2amjnnxy41ld"; type = "gem"; }; version = "4.5.1"; }; sib-api-v3-sdk = { - dependencies = ["json" "typhoeus"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "json" + "typhoeus" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0z8s6a5a95myr7kcg1w40qfb3n7043g1bxmmzrnp32j358znkr9d"; type = "gem"; }; version = "7.4.0"; }; sidekiq = { - dependencies = ["concurrent-ruby" "connection_pool" "rack" "redis-client"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "connection_pool" + "rack" + "redis-client" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0clkpka6liyh0ky3mcrlr42l4kzivwias26q90ypmw3r5yvglc5j"; type = "gem"; }; version = "7.2.0"; }; simple_xlsx_reader = { - dependencies = ["nokogiri" "rubyzip"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ + "nokogiri" + "rubyzip" + ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1kyw7yvcqcbiwl10s6nrk8qzjj8dl47ahaj0ikpyvya8ihr5fw26"; type = "gem"; }; version = "1.0.4"; }; sinatra = { - dependencies = ["mustermann" "rack" "rack-protection" "tilt"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "mustermann" + "rack" + "rack-protection" + "tilt" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1ryfja9yd3fq8n1p5yi3qnd0pjk7bkycmxxmbb1bj0axlr1pdv20"; type = "gem"; }; version = "3.0.5"; }; skylight = { - dependencies = ["activesupport"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activesupport" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "09c4wzqg0ndgfmwxzy6bzb7lzqdq7qz6y6xka3mfdvx8s7z8dslj"; type = "gem"; }; version = "6.0.1"; }; smart_properties = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0jrqssk9qhwrpq41arm712226vpcr458xv6xaqbk8cp94a0kycpr"; type = "gem"; }; version = "1.17.0"; }; spreadsheet_architect = { - dependencies = ["axlsx_styler" "caxlsx" "rodf"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "axlsx_styler" + "caxlsx" + "rodf" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1cw139wd2q7bl1ibqmiwr9ndz86nhiw3apqmy6by7y8pfn4s8qrn"; type = "gem"; }; version = "4.1.0"; }; spring = { - groups = ["development" "test"]; - platforms = []; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1wvdvwp395cc9srjy0fak5sy0531x7yh358cvmwlkbz0zlb0290x"; type = "gem"; }; version = "4.1.1"; }; spring-commands-rspec = { - dependencies = ["spring"]; - groups = ["development" "test"]; - platforms = []; + dependencies = [ "spring" ]; + groups = [ + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0b0svpq3md1pjz5drpa5pxwg8nk48wrshq8lckim4x3nli7ya0k2"; type = "gem"; }; version = "1.0.4"; }; sprockets = { - dependencies = ["concurrent-ruby" "rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "concurrent-ruby" + "rack" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0k0236g4h3ax7v6vp9k0l2fa0w6f1wqp7dn060zm4isw4n3k89sw"; type = "gem"; }; version = "4.2.0"; }; sprockets-rails = { - dependencies = ["actionpack" "activesupport" "sprockets"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activesupport" + "sprockets" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1b9i14qb27zs56hlcc2hf139l0ghbqnjpmfi0054dxycaxvk5min"; type = "gem"; }; version = "3.4.2"; }; stackprof = { - groups = ["development"]; - platforms = []; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bpmrz2vw59gw556y5hsha3xlrvfv4qwck4wg2r39qf2bp2hcr1b"; type = "gem"; }; version = "0.2.21"; }; stringio = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "063psvsn1aq6digpznxfranhcpmi0sdv2jhra5g0459sw0x2dxn1"; type = "gem"; }; version = "3.1.0"; }; strong_migrations = { - dependencies = ["activerecord"]; - groups = ["default"]; - platforms = []; + dependencies = [ "activerecord" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wz4zhsp4xia8zcpi98v4sgjlv2prd515l8jz4f7j0wk45dfkjs1"; type = "gem"; }; version = "0.8.0"; }; swd = { - dependencies = ["activesupport" "attr_required" "httpclient"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "attr_required" + "httpclient" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "12b3q2sw42nnilfb51nlqdv07f31vdv2j595kd99asnkw4cjlf5w"; type = "gem"; }; version = "1.3.0"; }; sysexits = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0qjng6pllznmprzx8vb0zg0c86hdrkyjs615q41s9fjpmv2430jr"; type = "gem"; }; version = "1.2.0"; }; temple = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "060zzj7c2kicdfk6cpnn40n9yjnhfrr13d0rsbdhdij68chp2861"; type = "gem"; }; version = "0.8.2"; }; terminal-table = { - dependencies = ["unicode-display_width"]; - groups = ["default"]; - platforms = []; + dependencies = [ "unicode-display_width" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "14dfmfjppmng5hwj7c5ka6qdapawm3h6k9lhn8zj001ybypvclgr"; type = "gem"; }; version = "3.0.2"; }; thor = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hx77jxkrwi66yvs10wfxqa8s25ds25ywgrrf66acm9nbfg7zp0s"; type = "gem"; }; version = "1.3.0"; }; thread_safe = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0nmhcgq6cgz44srylra07bmaw99f5271l0dpsvl5f75m44l0gmwy"; type = "gem"; }; version = "0.3.6"; }; tilt = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "186nfbcsk0l4l86gvng1fw6jq6p6s7rc0caxr23b3pnbfb20y63v"; type = "gem"; }; version = "2.0.11"; }; timecop = { - groups = ["test"]; - platforms = []; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1fw3nzycvd15qa7sxy9dxb4hqyizy1s8f7q3d50smbzyyvr8fvia"; type = "gem"; }; version = "0.9.4"; }; timeout = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "16mvvsmx90023wrhf8dxc1lpqh0m8alk65shb7xcya6a9gflw7vg"; type = "gem"; }; version = "0.4.1"; }; ttfunk = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "15iaxz9iak5643bq2bc0jkbjv8w2zn649lxgvh5wg48q9d4blw13"; type = "gem"; }; version = "1.7.0"; }; turbo-rails = { - dependencies = ["actionpack" "activejob" "railties"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "activejob" + "railties" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "07xbklyfs7yjs3v83qr2via9k9ik2wzkcqhjqylzpdjymrk6py11"; type = "gem"; }; version = "1.3.2"; }; typhoeus = { - dependencies = ["ethon"]; - groups = ["default"]; - platforms = []; + dependencies = [ "ethon" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1m22yrkmbj81rzhlny81j427qdvz57yk5wbcf3km0nf3bl6qiygz"; type = "gem"; }; version = "1.4.0"; }; tzinfo = { - dependencies = ["concurrent-ruby"]; - groups = ["default" "development" "test"]; - platforms = []; + dependencies = [ "concurrent-ruby" ]; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "16w2g84dzaf3z13gxyzlzbf748kylk5bdgg3n1ipvkvvqy685bwd"; type = "gem"; }; version = "2.0.6"; }; ulid-ruby = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1949zg2gzc56c9zjmkrg9lp7nnvawmm8rivq16ldgg99485kh9bp"; type = "gem"; }; version = "1.0.2"; }; unf = { - dependencies = ["unf_ext"]; - groups = ["default"]; - platforms = []; + dependencies = [ "unf_ext" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0bh2cf73i2ffh4fcpdn9ir4mhq8zi50ik0zqa1braahzadx536a9"; type = "gem"; }; version = "0.1.4"; }; unf_ext = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wc47r23h063l8ysws8sy24gzh74mks81cak3lkzlrw4qkqb3sg4"; type = "gem"; }; version = "0.0.7.7"; }; unicode-display_width = { - groups = ["default" "development"]; - platforms = []; + groups = [ + "default" + "development" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1gi82k102q7bkmfi7ggn9ciypn897ylln1jk9q67kjhr39fj043a"; type = "gem"; }; version = "2.4.2"; }; uri_template = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0p8qbxlpmg3msw0ihny6a3gsn0yvydx9ksh5knn8dnq06zhqyb1i"; type = "gem"; }; version = "0.7.0"; }; validate_email = { - dependencies = ["activemodel" "mail"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activemodel" + "mail" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1r1fz29l699arka177c9xw7409d1a3ff95bf7a6pmc97slb91zlx"; type = "gem"; }; version = "0.1.6"; }; validate_url = { - dependencies = ["activemodel" "public_suffix"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activemodel" + "public_suffix" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1bwj34rz7961rrl545f006m2jdz1nrc0m72gfqmnb41xwsvpagbk"; type = "gem"; }; version = "1.0.13"; }; vcr = { - groups = ["test"]; - platforms = []; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1xzd8f17mmcq9f6lxg4w0x4nd9pyp41lr77gjzxwynijzp8rcgjl"; type = "gem"; }; version = "6.1.0"; }; view_component = { - dependencies = ["activesupport" "concurrent-ruby" "method_source"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "concurrent-ruby" + "method_source" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1px8bcmj43xzcnzs7a8sh2qvhr07afbk0b2qjdjns4zjprsqksml"; type = "gem"; }; version = "3.9.0"; }; virtus = { - dependencies = ["axiom-types" "coercible" "descendants_tracker"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ + "axiom-types" + "coercible" + "descendants_tracker" + ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hniwgbdsjxa71qy47n6av8faf8qpwbaapms41rhkk3zxgjdlhc8"; type = "gem"; }; version = "2.0.0"; }; vite_rails = { - dependencies = ["railties" "vite_ruby"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "railties" + "vite_ruby" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1k4bllg0zpmpkjfmk1gybc2ygca4v40l2fmlplf9h0jqwniqa3mr"; type = "gem"; }; version = "3.0.17"; }; vite_ruby = { - dependencies = ["dry-cli" "rack-proxy" "zeitwerk"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "dry-cli" + "rack-proxy" + "zeitwerk" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0wza7pnwz8ym92gw0x4zr1icialhlw0l032kn4f86vw1vlzxmrd3"; type = "gem"; }; version = "3.5.0"; }; warden = { - dependencies = ["rack"]; - groups = ["default"]; - platforms = []; + dependencies = [ "rack" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1l7gl7vms023w4clg02pm4ky9j12la2vzsixi2xrv9imbn44ys26"; type = "gem"; }; version = "1.2.9"; }; web-console = { - dependencies = ["actionview" "activemodel" "bindex" "railties"]; - groups = ["development"]; - platforms = []; + dependencies = [ + "actionview" + "activemodel" + "bindex" + "railties" + ]; + groups = [ "development" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "087y4byl2s3fg0nfhix4s0r25cv1wk7d2j8n5324waza21xg7g77"; type = "gem"; }; version = "4.2.1"; }; webfinger = { - dependencies = ["activesupport" "httpclient"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activesupport" + "httpclient" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "18jj50b44a471ig7hw1ax90wxaaz40acmrf6cm7m2iyshlffy53q"; type = "gem"; }; version = "1.2.0"; }; webmock = { - dependencies = ["addressable" "crack" "hashdiff"]; - groups = ["test"]; - platforms = []; + dependencies = [ + "addressable" + "crack" + "hashdiff" + ]; + groups = [ "test" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1hdlbvfw316lkz251qnfk79drmaay7l51kidvicz41nhvw12xz8v"; type = "gem"; }; version = "3.11.2"; }; websocket = { - groups = ["default" "test"]; - platforms = []; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1a4zc8d0d91c3xqwapda3j3zgpfwdbj76hkb69xn6qvfkfks9h9c"; type = "gem"; }; version = "1.2.10"; }; websocket-driver = { - dependencies = ["websocket-extensions"]; - groups = ["default"]; - platforms = []; + dependencies = [ "websocket-extensions" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1nyh873w4lvahcl8kzbjfca26656d5c6z3md4sbqg5y1gfz0157n"; type = "gem"; }; version = "0.7.6"; }; websocket-extensions = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0hc2g9qps8lmhibl5baa91b4qx8wqw872rgwagml78ydj8qacsqw"; type = "gem"; }; version = "0.1.5"; }; xmlenc = { - dependencies = ["activemodel" "activesupport" "nokogiri" "xmlmapper"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "activemodel" + "activesupport" + "nokogiri" + "xmlmapper" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "09504vaqq37vwihsvy5skbi9vhbimqivanmgrkg4b7mry0rsxqmv"; type = "gem"; }; version = "0.8.0"; }; xmlmapper = { - dependencies = ["nokogiri"]; - groups = ["default"]; - platforms = []; + dependencies = [ "nokogiri" ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0xsglrl47p81ap0yh2vwb6z1hb7j6vax008bqx3mq665l6zf2chs"; type = "gem"; }; version = "0.8.1"; }; xpath = { - dependencies = ["nokogiri"]; - groups = ["default" "test"]; - platforms = []; + dependencies = [ "nokogiri" ]; + groups = [ + "default" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0bh8lk9hvlpn7vmi6h4hkcwjzvs2y0cmkk3yjjdr8fxvj6fsgzbd"; type = "gem"; }; version = "3.2.0"; }; zeitwerk = { - groups = ["default" "development" "test"]; - platforms = []; + groups = [ + "default" + "development" + "test" + ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1gir0if4nryl1jhwi28669gjwhxb7gzrm1fcc8xzsch3bnbi47jn"; type = "gem"; }; version = "2.6.12"; }; zip_tricks = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "06gaba552jsxzx0gfmjypzm89jzhlg2iw3nfhrpyxkkvv4jljr7a"; type = "gem"; }; version = "5.6.0"; }; zipline = { - dependencies = ["actionpack" "content_disposition" "zip_tricks"]; - groups = ["default"]; - platforms = []; + dependencies = [ + "actionpack" + "content_disposition" + "zip_tricks" + ]; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "1glg6x2p9gi3rlmy0aqy9pqkncbkn5jmzn3lqs8mw6q06gvrc9pv"; type = "gem"; }; version = "1.4.1"; }; zxcvbn-ruby = { - groups = ["default"]; - platforms = []; + groups = [ "default" ]; + platforms = [ ]; source = { - remotes = ["https://rubygems.org"]; + remotes = [ "https://rubygems.org" ]; sha256 = "0afxvi4hy49civms434l6ndm5wcfq0gf5pkgmw7bjxhwfl5jg0c1"; type = "gem"; }; diff --git a/machines/compute01/hedgedoc.nix b/machines/compute01/hedgedoc.nix index 2f10b47..abd466b 100644 --- a/machines/compute01/hedgedoc.nix +++ b/machines/compute01/hedgedoc.nix @@ -3,7 +3,8 @@ let host = "pads.dgnum.eu"; port = 3007; -in { +in +{ services = { hedgedoc = { enable = true; @@ -43,13 +44,17 @@ in { ensureDatabases = [ "hedgedoc" ]; - ensureUsers = [{ - name = "hedgedoc"; - ensureDBOwnership = true; - }]; + ensureUsers = [ + { + name = "hedgedoc"; + ensureDBOwnership = true; + } + ]; }; }; - systemd.services.hedgedoc.serviceConfig.StateDirectory = - lib.mkForce [ "hedgedoc" "hedgedoc/uploads" ]; + systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce [ + "hedgedoc" + "hedgedoc/uploads" + ]; } diff --git a/machines/compute01/k-radius/default.nix b/machines/compute01/k-radius/default.nix index 04844da..8c2ff63 100644 --- a/machines/compute01/k-radius/default.nix +++ b/machines/compute01/k-radius/default.nix @@ -40,22 +40,23 @@ }; authTokenFile = config.age.secrets."radius-auth_token_file".path; - privateKeyPasswordFile = - config.age.secrets."radius-private_key_password_file".path; + privateKeyPasswordFile = config.age.secrets."radius-private_key_password_file".path; - certs = builtins.listToAttrs (builtins.map (name: - lib.nameValuePair name - config.age.secrets."radius-${name}_pem_file".path) [ + certs = builtins.listToAttrs ( + builtins.map (name: lib.nameValuePair name config.age.secrets."radius-${name}_pem_file".path) [ "ca" "cert" "dh" "key" - ]); + ] + ); radiusClients = { }; }; - age-secrets.matches."^radius-.*$" = { owner = "radius"; }; + age-secrets.matches."^radius-.*$" = { + owner = "radius"; + }; networking.firewall.allowedTCPPorts = [ 1812 ]; networking.firewall.allowedUDPPorts = [ 1812 ]; diff --git a/machines/compute01/k-radius/module.nix b/machines/compute01/k-radius/module.nix index 8359ec6..6275584 100644 --- a/machines/compute01/k-radius/module.nix +++ b/machines/compute01/k-radius/module.nix @@ -1,17 +1,27 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let - inherit (lib) mkEnableOption mkIf mkOption types; + inherit (lib) + mkEnableOption + mkIf + mkOption + types + ; settingsFormat = pkgs.formats.toml { }; py-pkgs = import ./packages/python { inherit pkgs; }; - pykanidm = - pkgs.callPackage ./packages/pykanidm.nix { inherit (py-pkgs) pydantic; }; + pykanidm = pkgs.callPackage ./packages/pykanidm.nix { inherit (py-pkgs) pydantic; }; rlm_python = pkgs.callPackage ./packages/rlm_python.nix { inherit pykanidm; }; cfg = config.services.k-radius; -in { +in +{ options.services.k-radius = { enable = mkEnableOption "a freeradius service linked to kanidm."; @@ -19,17 +29,17 @@ in { freeradius = mkOption { type = types.package; - default = pkgs.freeradius.overrideAttrs (old: { - buildInputs = (old.buildInputs or [ ]) - ++ [ (pkgs.python3.withPackages (ps: [ ps.kanidm ])) ]; - }); + default = pkgs.freeradius.overrideAttrs ( + old: { + buildInputs = (old.buildInputs or [ ]) ++ [ (pkgs.python3.withPackages (ps: [ ps.kanidm ])) ]; + } + ); }; configDir = mkOption { type = types.path; default = "/var/lib/radius/raddb"; - description = - "The path of the freeradius server configuration directory."; + description = "The path of the freeradius server configuration directory."; }; authTokenFile = mkOption { @@ -38,12 +48,14 @@ in { }; radiusClients = mkOption { - type = types.attrsOf (types.submodule { - options = { - secret = mkOption { type = types.path; }; - ipaddr = mkOption { type = types.str; }; - }; - }); + type = types.attrsOf ( + types.submodule { + options = { + secret = mkOption { type = types.path; }; + ipaddr = mkOption { type = types.str; }; + }; + } + ); default = { }; description = "A mapping of clients and their authentication tokens."; }; @@ -55,8 +67,7 @@ in { }; dh = mkOption { type = types.str; - description = - "The output of `openssl dhparam -in ca.pem -out dh.pem 2048`."; + description = "The output of `openssl dhparam -in ca.pem -out dh.pem 2048`."; }; cert = mkOption { type = types.str; @@ -113,26 +124,32 @@ in { # write the clients configuration rm ${cfg.configDir}/clients.conf && touch ${cfg.configDir}/clients.conf - ${builtins.concatStringsSep "\n" (builtins.attrValues (builtins.mapAttrs - (name: - { secret, ipaddr }: '' - cat <> ${cfg.configDir}/client.conf - client ${name} { - ipaddr = ${ipaddr} - secret = $(cat "${secret}") - proto = * - } - EOF - '') cfg.radiusClients))} + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs + ( + name: + { secret, ipaddr }: + '' + cat <> ${cfg.configDir}/client.conf + client ${name} { + ipaddr = ${ipaddr} + secret = $(cat "${secret}") + proto = * + } + EOF + '' + ) + cfg.radiusClients + ) + )} # Copy the kanidm configuration cat < /var/lib/radius/kanidm.toml auth_token = "$(cat "${cfg.authTokenFile}")" EOF - cat ${ - settingsFormat.generate "kanidm.toml" cfg.settings - } >> /var/lib/radius/kanidm.toml + cat ${settingsFormat.generate "kanidm.toml" cfg.settings} >> /var/lib/radius/kanidm.toml chmod u+w /var/lib/radius/kanidm.toml # Copy the certificates to the correct directory @@ -154,11 +171,13 @@ in { # ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout ''; - path = [ pkgs.openssl pkgs.gnused ]; + path = [ + pkgs.openssl + pkgs.gnused + ]; serviceConfig = { - ExecStart = - "${cfg.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout"; + ExecStart = "${cfg.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout"; ExecReload = [ "${cfg.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" "${pkgs.coreutils}/bin/kill -HUP $MAINPID" diff --git a/machines/compute01/k-radius/packages/pykanidm.nix b/machines/compute01/k-radius/packages/pykanidm.nix index 1a31a00..5ee75c5 100644 --- a/machines/compute01/k-radius/packages/pykanidm.nix +++ b/machines/compute01/k-radius/packages/pykanidm.nix @@ -1,25 +1,38 @@ -{ lib, fetchFromGitHub, python3, pydantic }: +{ + lib, + fetchFromGitHub, + python3, + pydantic, +}: let pname = "kanidm"; version = "0.0.3"; -in python3.pkgs.buildPythonPackage { +in +python3.pkgs.buildPythonPackage { inherit pname version; format = "pyproject"; disabled = python3.pythonOlder "3.8"; - src = (fetchFromGitHub { - owner = pname; - repo = pname; - # Latest 1.1.0-rc.15 tip - rev = "a5ca8018e3a636dbb0a79b3fd869db059d92979d"; - hash = "sha256-PFGoeGn7a/lVR6rOmOKA3ydAoo3/+9RlkwBAKS22Psg="; - }) + "/pykanidm"; + src = + (fetchFromGitHub { + owner = pname; + repo = pname; + # Latest 1.1.0-rc.15 tip + rev = "a5ca8018e3a636dbb0a79b3fd869db059d92979d"; + hash = "sha256-PFGoeGn7a/lVR6rOmOKA3ydAoo3/+9RlkwBAKS22Psg="; + }) + + "/pykanidm"; nativeBuildInputs = with python3.pkgs; [ poetry-core ]; - propagatedBuildInputs = with python3.pkgs; [ aiohttp pydantic toml (authlib.overridePythonAttrs (_: { doCheck = false; })) ]; + propagatedBuildInputs = with python3.pkgs; [ + aiohttp + pydantic + toml + (authlib.overridePythonAttrs (_: { doCheck = false; })) + ]; doCheck = false; @@ -29,6 +42,9 @@ in python3.pkgs.buildPythonPackage { description = "Kanidm client library"; homepage = "https://github.com/kanidm/kanidm/tree/master/pykanidm"; license = licenses.mpl20; - maintainers = with maintainers; [ arianvp hexa ]; + maintainers = with maintainers; [ + arianvp + hexa + ]; }; } diff --git a/machines/compute01/k-radius/packages/python/default.nix b/machines/compute01/k-radius/packages/python/default.nix index 805f124..968cd4b 100644 --- a/machines/compute01/k-radius/packages/python/default.nix +++ b/machines/compute01/k-radius/packages/python/default.nix @@ -5,8 +5,16 @@ let callPackage = lib.callPackageWith (pkgs // pkgs.python3.pkgs // self); - self = builtins.listToAttrs (builtins.map (name: { - inherit name; - value = callPackage (./. + "/${name}.nix") { }; - }) [ "pydantic" "pydantic-core" ]); -in self + self = builtins.listToAttrs ( + builtins.map + (name: { + inherit name; + value = callPackage (./. + "/${name}.nix") { }; + }) + [ + "pydantic" + "pydantic-core" + ] + ); +in +self diff --git a/machines/compute01/k-radius/packages/python/pydantic-core.nix b/machines/compute01/k-radius/packages/python/pydantic-core.nix index 4569ea3..87d8ace 100644 --- a/machines/compute01/k-radius/packages/python/pydantic-core.nix +++ b/machines/compute01/k-radius/packages/python/pydantic-core.nix @@ -1,17 +1,18 @@ -{ stdenv -, lib -, buildPythonPackage -, fetchFromGitHub -, cargo -, rustPlatform -, rustc -, libiconv -, typing-extensions -, pytestCheckHook -, hypothesis -, pytest-timeout -, pytest-mock -, dirty-equals +{ + stdenv, + lib, + buildPythonPackage, + fetchFromGitHub, + cargo, + rustPlatform, + rustc, + libiconv, + typing-extensions, + pytestCheckHook, + hypothesis, + pytest-timeout, + pytest-mock, + dirty-equals, }: let @@ -27,9 +28,7 @@ let hash = "sha256-UguZpA3KEutOgIavjx8Ie//0qJq+4FTZNQTwb/ZIgb8="; }; - patches = [ - ./01-remove-benchmark-flags.patch - ]; + patches = [ ./01-remove-benchmark-flags.patch ]; cargoDeps = rustPlatform.fetchCargoTarball { inherit src; @@ -45,13 +44,9 @@ let typing-extensions ]; - buildInputs = lib.optionals stdenv.isDarwin [ - libiconv - ]; + buildInputs = lib.optionals stdenv.isDarwin [ libiconv ]; - propagatedBuildInputs = [ - typing-extensions - ]; + propagatedBuildInputs = [ typing-extensions ]; pythonImportsCheck = [ "pydantic_core" ]; @@ -85,4 +80,5 @@ let maintainers = with maintainers; [ blaggacao ]; }; }; -in pydantic-core +in +pydantic-core diff --git a/machines/compute01/k-radius/packages/python/pydantic.nix b/machines/compute01/k-radius/packages/python/pydantic.nix index 18762cc..e36ceb9 100644 --- a/machines/compute01/k-radius/packages/python/pydantic.nix +++ b/machines/compute01/k-radius/packages/python/pydantic.nix @@ -1,27 +1,28 @@ -{ lib -, buildPythonPackage -, fetchFromGitHub -, pythonOlder +{ + lib, + buildPythonPackage, + fetchFromGitHub, + pythonOlder, -# build-system -, hatchling -, hatch-fancy-pypi-readme + # build-system + hatchling, + hatch-fancy-pypi-readme, -# native dependencies -, libxcrypt + # native dependencies + libxcrypt, -# dependencies -, annotated-types -, pydantic-core -, typing-extensions + # dependencies + annotated-types, + pydantic-core, + typing-extensions, -# tests -, cloudpickle -, email-validator -, dirty-equals -, faker -, pytestCheckHook -, pytest-mock + # tests + cloudpickle, + email-validator, + dirty-equals, + faker, + pytestCheckHook, + pytest-mock, }: buildPythonPackage rec { @@ -38,9 +39,7 @@ buildPythonPackage rec { hash = "sha256-D0gYcyrKVVDhBgV9sCVTkGq/kFmIoT9l0i5bRM1qxzM="; }; - buildInputs = lib.optionals (pythonOlder "3.9") [ - libxcrypt - ]; + buildInputs = lib.optionals (pythonOlder "3.9") [ libxcrypt ]; nativeBuildInputs = [ hatch-fancy-pypi-readme @@ -54,9 +53,7 @@ buildPythonPackage rec { ]; passthru.optional-dependencies = { - email = [ - email-validator - ]; + email = [ email-validator ]; }; nativeCheckInputs = [ @@ -93,4 +90,3 @@ buildPythonPackage rec { maintainers = with maintainers; [ wd15 ]; }; } - diff --git a/machines/compute01/k-radius/packages/rlm_python.nix b/machines/compute01/k-radius/packages/rlm_python.nix index c276978..71f491a 100644 --- a/machines/compute01/k-radius/packages/rlm_python.nix +++ b/machines/compute01/k-radius/packages/rlm_python.nix @@ -1,8 +1,14 @@ -{ stdenv, fetchFromGitHub, python3, pykanidm }: +{ + stdenv, + fetchFromGitHub, + python3, + pykanidm, +}: -let pythonPath = with python3.pkgs; makePythonPath [ pykanidm ]; - -in stdenv.mkDerivation rec { +let + pythonPath = with python3.pkgs; makePythonPath [ pykanidm ]; +in +stdenv.mkDerivation rec { pname = "rlm_python"; version = "1.1.0-rc.15"; @@ -25,9 +31,15 @@ in stdenv.mkDerivation rec { cp -R rlm_python/{mods-available,sites-available} $out/etc/raddb/ ''; - phases = [ "unpackPhase" "patchPhase" "installPhase" ]; + phases = [ + "unpackPhase" + "patchPhase" + "installPhase" + ]; - passthru = { inherit pythonPath; }; + passthru = { + inherit pythonPath; + }; preferLocalBuild = true; } diff --git a/machines/compute01/kanidm/default.nix b/machines/compute01/kanidm/default.nix index 0850ed3..784d700 100644 --- a/machines/compute01/kanidm/default.nix +++ b/machines/compute01/kanidm/default.nix @@ -5,8 +5,16 @@ let cert = config.security.acme.certs.${domain}; - allowedSubDomains = [ "cloud" "git" "videos" "social" "demarches" "netbird" ]; -in { + allowedSubDomains = [ + "cloud" + "git" + "videos" + "social" + "demarches" + "netbird" + ]; +in +{ services.kanidm = { enableServer = true; diff --git a/machines/compute01/kanidm/secrets/secrets.nix b/machines/compute01/kanidm/secrets/secrets.nix index 175b50e..3d54c1b 100644 --- a/machines/compute01/kanidm/secrets/secrets.nix +++ b/machines/compute01/kanidm/secrets/secrets.nix @@ -7,4 +7,3 @@ lib.setDefault { inherit publicKeys; } [ "kanidm-password_admin" "kanidm-password_idm_admin" ] - diff --git a/machines/compute01/mastodon.nix b/machines/compute01/mastodon.nix index 0c076a4..5919e8c 100644 --- a/machines/compute01/mastodon.nix +++ b/machines/compute01/mastodon.nix @@ -1,7 +1,9 @@ { config, ... }: -let host = "social.dgnum.eu"; -in { +let + host = "social.dgnum.eu"; +in +{ services.mastodon = { enable = true; @@ -9,7 +11,6 @@ in { smtp = { # TODO: smtp setup fromAddress = "social@services.dgnum.eu"; - }; streamingProcesses = 4; @@ -38,5 +39,7 @@ in { extraEnvFiles = [ config.age.secrets."mastodon-extra_env_file".path ]; }; - age-secrets.matches."^mastodon-.*$" = { owner = "mastodon"; }; + age-secrets.matches."^mastodon-.*$" = { + owner = "mastodon"; + }; } diff --git a/machines/compute01/nextcloud.nix b/machines/compute01/nextcloud.nix index 5f63022..64a7983 100644 --- a/machines/compute01/nextcloud.nix +++ b/machines/compute01/nextcloud.nix @@ -3,7 +3,8 @@ let host = "cloud.dgnum.eu"; nextcloud-occ = "${config.services.nextcloud.occ}/bin/nextcloud-occ"; -in { +in +{ services.nextcloud = { enable = true; hostName = host; @@ -102,8 +103,7 @@ in { image = "collabora/code"; imageFile = pkgs.dockerTools.pullImage { imageName = "collabora/code"; - imageDigest = - "sha256:a8cce07c949aa59cea0a7f1f220266a1a6d886c717c3b5005782baf6f384d645"; + imageDigest = "sha256:a8cce07c949aa59cea0a7f1f220266a1a6d886c717c3b5005782baf6f384d645"; sha256 = "sha256-lN6skv62x+x7G7SNOUyZ8W6S/uScrkqE1nbBwwSEWXQ="; }; ports = [ "9980:9980" ]; @@ -111,7 +111,12 @@ in { domain = "cloud.dgnum.eu"; extra_params = "--o:ssl.enable=false --o:ssl.termination=true --o:remote_font_config.url=https://cloud.dgnum.eu/apps/richdocuments/settings/fonts.json"; }; - extraOptions = [ "--cap-add" "MKNOD" "--cap-add" "SYS_ADMIN" ]; + extraOptions = [ + "--cap-add" + "MKNOD" + "--cap-add" + "SYS_ADMIN" + ]; }; }; @@ -180,7 +185,9 @@ in { description = "Generate preview for nextcloud media."; script = "${nextcloud-occ} preview:pre-generate -vvv"; startAt = "*-*-* 01:00:00 UTC"; - serviceConfig = { Restart = "on-failure"; }; + serviceConfig = { + Restart = "on-failure"; + }; }; nextcloud-cron.path = [ pkgs.perl ]; @@ -188,9 +195,13 @@ in { environment.systemPackages = [ pkgs.ffmpeg_6-headless ]; - networking.hosts = { "129.199.146.148" = [ "s3.dgnum.eu" ]; }; + networking.hosts = { + "129.199.146.148" = [ "s3.dgnum.eu" ]; + }; - age-secrets.matches."^nextcloud-.*$" = { owner = "nextcloud"; }; + age-secrets.matches."^nextcloud-.*$" = { + owner = "nextcloud"; + }; system.activationScripts = { restart-nextcloud.text = '' diff --git a/machines/compute01/outline.nix b/machines/compute01/outline.nix index 76603ec..8dec2ed 100644 --- a/machines/compute01/outline.nix +++ b/machines/compute01/outline.nix @@ -1,7 +1,9 @@ { config, ... }: -let host = "docs.dgnum.eu"; -in { +let + host = "docs.dgnum.eu"; +in +{ services.outline = { enable = true; @@ -27,8 +29,7 @@ in { userinfoUrl = "https://sso.dgnum.eu/oauth2/openid/outline_dgn/userinfo"; displayName = "DGNum SSO"; - clientSecretFile = - config.age.secrets."outline-oidc_client_secret_file".path; + clientSecretFile = config.age.secrets."outline-oidc_client_secret_file".path; }; defaultLanguage = "fr_FR"; @@ -51,5 +52,7 @@ in { }; }; - age-secrets.matches."^outline-.*$" = { owner = "outline"; }; + age-secrets.matches."^outline-.*$" = { + owner = "outline"; + }; } diff --git a/machines/compute01/rstudio-server.nix b/machines/compute01/rstudio-server.nix index a85cb82..cf533eb 100644 --- a/machines/compute01/rstudio-server.nix +++ b/machines/compute01/rstudio-server.nix @@ -1,9 +1,10 @@ { pkgs, ... }: let - host = "rstudio.dgnum.eu"; + # host = "rstudio.dgnum.eu"; port = 19000; -in { +in +{ services.rstudio-server = { enable = true; rserverExtraConfig = '' @@ -11,14 +12,17 @@ in { ''; package = pkgs.rstudioServerWrapper.override { - packages = with pkgs.rPackages; [ ggplot2 rmarkdown dplyr ]; + packages = with pkgs.rPackages; [ + ggplot2 + rmarkdown + dplyr + ]; }; }; users.users.ruser = { isNormalUser = true; - hashedPassword = - "$6$pTXXVh8NfE.M8VPc$q0fFh3Y7Y0DauLCcZLgJzFciq1wkjoHmO61XpOrZLH3a1M32ZzOMbjx2XMm2QxrUncbx6hGerY/lD8rQ8InS4."; + hashedPassword = "$6$pTXXVh8NfE.M8VPc$q0fFh3Y7Y0DauLCcZLgJzFciq1wkjoHmO61XpOrZLH3a1M32ZzOMbjx2XMm2QxrUncbx6hGerY/lD8rQ8InS4."; }; dgn-access-control.users.ruser = [ "jemagius" ]; diff --git a/machines/compute01/satosa/default.nix b/machines/compute01/satosa/default.nix index 24d1070..d35d705 100644 --- a/machines/compute01/satosa/default.nix +++ b/machines/compute01/satosa/default.nix @@ -1,7 +1,9 @@ { config, ... }: -let host = "saml-idp.dgnum.eu"; -in { +let + host = "saml-idp.dgnum.eu"; +in +{ imports = [ ./module.nix ]; @@ -20,8 +22,7 @@ in { config = { endpoints.single_sign_on_service = { "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" = "sso/post"; - "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" = - "sso/redirect"; + "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" = "sso/redirect"; }; entityid_endpoint = true; enable_metadata_reload = false; @@ -32,11 +33,13 @@ in { url = "https://dgnum.eu"; }; - contact_person = [{ - contact_type = "technical"; - email_address = "mailto:tom.hubrecht@dgnum.eu"; - given_name = "Tom Hubrecht"; - }]; + contact_person = [ + { + contact_type = "technical"; + email_address = "mailto:tom.hubrecht@dgnum.eu"; + given_name = "Tom Hubrecht"; + } + ]; key_file = "/var/lib/satosa/ssl/key.pem"; cert_file = "/var/lib/satosa/ssl/cert.pem"; @@ -50,10 +53,12 @@ in { endpoints.single_sign_on_service = [ ]; name = "DGNum proxy IdP"; ui_info = { - display_name = [{ - lang = "fr"; - text = "Service de connexion DGNum"; - }]; + display_name = [ + { + lang = "fr"; + text = "Service de connexion DGNum"; + } + ]; }; name_id_format = [ "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" @@ -63,9 +68,10 @@ in { default = { attribute_restrictions = null; fail_on_missing_requested = false; - lifetime = { minutes = 15; }; - name_form = - "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"; + lifetime = { + minutes = 15; + }; + name_form = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"; encrypt_assertion = false; encrypted_advice_attributes = false; }; @@ -121,12 +127,15 @@ in { module = "satosa.backends.openid_connect.OpenIDConnectBackend"; name = "kanidm"; config = { - provider_metadata.issuer = - "https://sso.dgnum.eu/oauth2/openid/satosa_dgn/"; + provider_metadata.issuer = "https://sso.dgnum.eu/oauth2/openid/satosa_dgn/"; client = { auth_req_params = { response_type = "code"; - scope = [ "openid" "profile" "email" ]; + scope = [ + "openid" + "profile" + "email" + ]; }; client_metadata = { client_id = "satosa_dgn"; @@ -144,5 +153,7 @@ in { forceSSL = true; }; - age-secrets.matches."^satosa-.*$" = { owner = "satosa"; }; + age-secrets.matches."^satosa-.*$" = { + owner = "satosa"; + }; } diff --git a/machines/compute01/satosa/module.nix b/machines/compute01/satosa/module.nix index ec61e3e..50cc37a 100644 --- a/machines/compute01/satosa/module.nix +++ b/machines/compute01/satosa/module.nix @@ -1,7 +1,18 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let - inherit (lib) mkDefault mkEnableOption mkIf mkOption types; + inherit (lib) + mkDefault + mkEnableOption + mkIf + mkOption + types + ; yamlFormat = pkgs.formats.yaml { }; @@ -9,12 +20,17 @@ let cfg = config.services.satosa; - mkYamlFiles = files: - builtins.attrValues - (builtins.mapAttrs (name: yamlFormat.generate "${name}.yaml") files); + mkYamlFiles = + files: builtins.attrValues (builtins.mapAttrs (name: yamlFormat.generate "${name}.yaml") files); - pyEnv = cfg.package.python.withPackages (ps: [ cfg.package ps.gunicorn ]); -in { + pyEnv = cfg.package.python.withPackages ( + ps: [ + cfg.package + ps.gunicorn + ] + ); +in +{ options.services.satosa = { enable = mkEnableOption "SATOSA, a SAML and OIDC proxy."; @@ -88,8 +104,7 @@ in { MICRO_SERVICES = mkYamlFiles cfg.microServices; LOGGING = { version = 1; - formatters.simple.format = - "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s"; + formatters.simple.format = "[%(asctime)s] [%(levelname)s] [%(name)s.%(funcName)s] %(message)s"; handlers.stdout = { class = "logging.StreamHandler"; stream = "ext://sys.stdout"; @@ -171,7 +186,9 @@ in { TimeoutStopSec = "5"; EnvironmentFile = lib.optional (cfg.envFile != null) cfg.envFile; }; - environment = { SATOSA_CONFIG = configFile; }; + environment = { + SATOSA_CONFIG = configFile; + }; }; }; @@ -179,8 +196,7 @@ in { enable = true; virtualHosts.${cfg.host} = { - locations."/".proxyPass = - "http://127.0.0.1:${builtins.toString cfg.port}"; + locations."/".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}"; }; }; diff --git a/machines/compute01/satosa/package/cookies-samesite-compat.nix b/machines/compute01/satosa/package/cookies-samesite-compat.nix index d7e0442..0a68d5d 100644 --- a/machines/compute01/satosa/package/cookies-samesite-compat.nix +++ b/machines/compute01/satosa/package/cookies-samesite-compat.nix @@ -1,6 +1,7 @@ -{ lib -, python3 -, fetchPypi +{ + lib, + python3, + fetchPypi, }: python3.pkgs.buildPythonPackage rec { diff --git a/machines/compute01/satosa/package/default.nix b/machines/compute01/satosa/package/default.nix index 32b043e..3a503fc 100644 --- a/machines/compute01/satosa/package/default.nix +++ b/machines/compute01/satosa/package/default.nix @@ -13,5 +13,5 @@ let pydantic = callPackage ./pydantic.nix { }; pydantic-core = callPackage ./pydantic-core.nix { }; }; - -in self.satosa +in +self.satosa diff --git a/machines/compute01/satosa/package/oic.nix b/machines/compute01/satosa/package/oic.nix index 9b044b5..b330d70 100644 --- a/machines/compute01/satosa/package/oic.nix +++ b/machines/compute01/satosa/package/oic.nix @@ -1,7 +1,8 @@ -{ lib -, python3 -, fetchPypi -, pydantic-settings +{ + lib, + python3, + fetchPypi, + pydantic-settings, }: python3.pkgs.buildPythonPackage rec { diff --git a/machines/compute01/satosa/package/pydantic-core.nix b/machines/compute01/satosa/package/pydantic-core.nix index fc1e094..5951182 100644 --- a/machines/compute01/satosa/package/pydantic-core.nix +++ b/machines/compute01/satosa/package/pydantic-core.nix @@ -1,9 +1,10 @@ -{ lib -, python3 -, fetchPypi -, cargo -, rustPlatform -, rustc +{ + lib, + python3, + fetchPypi, + cargo, + rustPlatform, + rustc, }: python3.pkgs.buildPythonPackage rec { @@ -31,9 +32,7 @@ python3.pkgs.buildPythonPackage rec { rustc ]; - propagatedBuildInputs = with python3.pkgs; [ - typing-extensions - ]; + propagatedBuildInputs = with python3.pkgs; [ typing-extensions ]; pythonImportsCheck = [ "pydantic_core" ]; diff --git a/machines/compute01/satosa/package/pydantic-settings.nix b/machines/compute01/satosa/package/pydantic-settings.nix index 08bab28..e744015 100644 --- a/machines/compute01/satosa/package/pydantic-settings.nix +++ b/machines/compute01/satosa/package/pydantic-settings.nix @@ -1,7 +1,8 @@ -{ lib -, python3 -, fetchPypi -, pydantic +{ + lib, + python3, + fetchPypi, + pydantic, }: python3.pkgs.buildPythonPackage rec { @@ -15,9 +16,7 @@ python3.pkgs.buildPythonPackage rec { hash = "sha256-li3DZySVqtaulqQ5D6x+WTWR4URiXlES01n49n+3WUU="; }; - nativeBuildInputs = [ - python3.pkgs.hatchling - ]; + nativeBuildInputs = [ python3.pkgs.hatchling ]; propagatedBuildInputs = with python3.pkgs; [ pydantic diff --git a/machines/compute01/satosa/package/pydantic.nix b/machines/compute01/satosa/package/pydantic.nix index e75a07b..319a6af 100644 --- a/machines/compute01/satosa/package/pydantic.nix +++ b/machines/compute01/satosa/package/pydantic.nix @@ -1,7 +1,8 @@ -{ lib -, python3 -, fetchPypi -, pydantic-core +{ + lib, + python3, + fetchPypi, + pydantic-core, }: python3.pkgs.buildPythonPackage rec { @@ -26,9 +27,7 @@ python3.pkgs.buildPythonPackage rec { ]; passthru.optional-dependencies = with python3.pkgs; { - email = [ - email-validator - ]; + email = [ email-validator ]; }; pythonImportsCheck = [ "pydantic" ]; diff --git a/machines/compute01/satosa/package/pyop.nix b/machines/compute01/satosa/package/pyop.nix index 7148d1f..626c3b9 100644 --- a/machines/compute01/satosa/package/pyop.nix +++ b/machines/compute01/satosa/package/pyop.nix @@ -1,7 +1,8 @@ -{ lib -, python3 -, fetchPypi -, oic +{ + lib, + python3, + fetchPypi, + oic, }: python3.pkgs.buildPythonPackage rec { diff --git a/machines/compute01/satosa/package/satosa.nix b/machines/compute01/satosa/package/satosa.nix index b7ecca4..22b25b7 100644 --- a/machines/compute01/satosa/package/satosa.nix +++ b/machines/compute01/satosa/package/satosa.nix @@ -1,8 +1,9 @@ -{ lib -, python3 -, fetchPypi -, cookies-samesite-compat -, pyop +{ + lib, + python3, + fetchPypi, + cookies-samesite-compat, + pyop, }: python3.pkgs.buildPythonPackage rec { @@ -36,15 +37,9 @@ python3.pkgs.buildPythonPackage rec { ]; passthru.optional-dependencies = with python3.pkgs; { - ldap = [ - ldap3 - ]; - pyop_mongo = [ - pyop - ]; - pyop_redis = [ - pyop - ]; + ldap = [ ldap3 ]; + pyop_mongo = [ pyop ]; + pyop_redis = [ pyop ]; }; passthru.python = python3; diff --git a/machines/compute01/vaultwarden.nix b/machines/compute01/vaultwarden.nix index e28f689..0f9c25b 100644 --- a/machines/compute01/vaultwarden.nix +++ b/machines/compute01/vaultwarden.nix @@ -1,8 +1,9 @@ { config, ... }: -let host = "pass.dgnum.eu"; - -in { +let + host = "pass.dgnum.eu"; +in +{ services.vaultwarden = { enable = true; @@ -62,10 +63,12 @@ in { ensureDatabases = [ "vaultwarden" ]; - ensureUsers = [{ - name = "vaultwarden"; - ensureDBOwnership = true; - }]; + ensureUsers = [ + { + name = "vaultwarden"; + ensureDBOwnership = true; + } + ]; }; }; } diff --git a/machines/compute01/zammad.nix b/machines/compute01/zammad.nix index ec966a1..7dd42ee 100644 --- a/machines/compute01/zammad.nix +++ b/machines/compute01/zammad.nix @@ -5,7 +5,8 @@ let port = 3005; websocketPort = 6902; -in { +in +{ services.zammad = { enable = true; @@ -38,10 +39,9 @@ in { proxyWebsockets = true; }; - "~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png)".extraConfig = - '' - expires max; - ''; + "~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png)".extraConfig = '' + expires max; + ''; }; extraConfig = '' @@ -51,5 +51,7 @@ in { }; }; - age-secrets.matches."^zammad-.*$" = { owner = "zammad"; }; + age-secrets.matches."^zammad-.*$" = { + owner = "zammad"; + }; } diff --git a/machines/storage01/_hardware-configuration.nix b/machines/storage01/_hardware-configuration.nix index ac55ed7..440fc88 100644 --- a/machines/storage01/_hardware-configuration.nix +++ b/machines/storage01/_hardware-configuration.nix @@ -29,6 +29,5 @@ fsType = "vfat"; }; - swapDevices = - [{ device = "/dev/disk/by-uuid/65a6f6e4-e996-4718-a4d0-cd0c78dcb15b"; }]; + swapDevices = [ { device = "/dev/disk/by-uuid/65a6f6e4-e996-4718-a4d0-cd0c78dcb15b"; } ]; } diff --git a/machines/storage01/atticd.nix b/machines/storage01/atticd.nix index 55db857..14e7002 100644 --- a/machines/storage01/atticd.nix +++ b/machines/storage01/atticd.nix @@ -1,8 +1,14 @@ -{ config, pkgs, sources, ... }: +{ + config, + pkgs, + sources, + ... +}: -let host = "cachix.dgnum.eu"; - -in { +let + host = "cachix.dgnum.eu"; +in +{ services = { atticd = { enable = true; @@ -68,10 +74,12 @@ in { ensureDatabases = [ "atticd" ]; - ensureUsers = [{ - name = "atticd"; - ensureDBOwnership = true; - }]; + ensureUsers = [ + { + name = "atticd"; + ensureDBOwnership = true; + } + ]; }; }; } diff --git a/machines/storage01/forgejo-runners.nix b/machines/storage01/forgejo-runners.nix index f479201..3843831 100644 --- a/machines/storage01/forgejo-runners.nix +++ b/machines/storage01/forgejo-runners.nix @@ -3,18 +3,29 @@ let url = "https://git.dgnum.eu"; - mkRunner = { labels, name, token }: { - enable = true; + mkRunner = + { + labels, + name, + token, + }: + { + enable = true; - inherit name labels token url; + inherit + name + labels + token + url + ; - settings.container = { - network = "host"; - options = "--cpus=4"; + settings.container = { + network = "host"; + options = "--cpus=4"; + }; }; - }; - -in { +in +{ services.forgejo-nix-runners = { enable = true; @@ -23,7 +34,11 @@ in { storePath = "/data/slow/nix"; tokenFile = config.age.secrets."forgejo_runners-token_file".path; - dependencies = [ pkgs.colmena pkgs.npins pkgs.tea ]; + dependencies = [ + pkgs.colmena + pkgs.npins + pkgs.tea + ]; containerOptions = [ "--cpus=4" ]; diff --git a/machines/storage01/forgejo.nix b/machines/storage01/forgejo.nix index 85389e7..2de9e56 100644 --- a/machines/storage01/forgejo.nix +++ b/machines/storage01/forgejo.nix @@ -3,7 +3,8 @@ let port = 3000; host = "git.dgnum.eu"; -in { +in +{ services = { forgejo = { enable = true; @@ -19,7 +20,9 @@ in { }; settings = { - DEFAULT = { APP_NAME = "Forge git de la DGNum"; }; + DEFAULT = { + APP_NAME = "Forge git de la DGNum"; + }; server = { ROOT_URL = "https://${host}/"; @@ -62,7 +65,9 @@ in { virtualHosts.${host} = { enableACME = true; forceSSL = true; - locations."/" = { proxyPass = "http://127.0.0.1:${toString port}"; }; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString port}"; + }; }; }; }; @@ -77,5 +82,7 @@ in { users.groups.git = { }; - age-secrets.matches."^forgejo-.*$" = { owner = "git"; }; + age-secrets.matches."^forgejo-.*$" = { + owner = "git"; + }; } diff --git a/machines/storage01/garage.nix b/machines/storage01/garage.nix index 484dfd1..2687157 100644 --- a/machines/storage01/garage.nix +++ b/machines/storage01/garage.nix @@ -8,20 +8,22 @@ let metadata_dir = "/data/fast/garage/meta"; buckets = [ "peertube-videos-dgnum" ]; - -in { +in +{ services.garage = { enable = true; - package = pkgs.garage_0_9.overrideAttrs (old: { - patches = (old.patches or [ ]) ++ [ - # Allow 0 as a part number marker - (pkgs.fetchpatch { - url = "https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/670.patch"; - hash = "sha256-28ctLl1qscMRj2JEVnmhuLyK1Avub8QeyfQFxAK0y08="; - }) - ]; - }); + package = pkgs.garage_0_9.overrideAttrs ( + old: { + patches = (old.patches or [ ]) ++ [ + # Allow 0 as a part number marker + (pkgs.fetchpatch { + url = "https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/670.patch"; + hash = "sha256-28ctLl1qscMRj2JEVnmhuLyK1Avub8QeyfQFxAK0y08="; + }) + ]; + } + ); settings = { inherit data_dir metadata_dir; @@ -56,7 +58,10 @@ in { systemd.services.garage.serviceConfig = { User = "garage"; - ReadWriteDirectories = [ data_dir metadata_dir ]; + ReadWriteDirectories = [ + data_dir + metadata_dir + ]; }; users.users.garage = { diff --git a/machines/storage01/netbird/module.nix b/machines/storage01/netbird/module.nix index c0d47ad..e2fe552 100644 --- a/machines/storage01/netbird/module.nix +++ b/machines/storage01/netbird/module.nix @@ -1,8 +1,24 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) - filterAttrs literalExpression maintainers mkDefault mkEnableOption mkIf - mkMerge mkOption optionalAttrs optionalString optionals types; + filterAttrs + literalExpression + maintainers + mkDefault + mkEnableOption + mkIf + mkMerge + mkOption + optionalAttrs + optionalString + optionals + types + ; inherit ((import ./package { inherit pkgs; })) dashboard; @@ -13,92 +29,100 @@ let settingsFormat = pkgs.formats.keyValue { }; managementFormat = pkgs.formats.json { }; - settingsFile = settingsFormat.generate "setup.env" (builtins.mapAttrs (_: val: - if builtins.isList val then - ''"${builtins.concatStringsSep " " val}"'' - else - val) settings); + settingsFile = settingsFormat.generate "setup.env" ( + builtins.mapAttrs + (_: val: if builtins.isList val then ''"${builtins.concatStringsSep " " val}"'' else val) + settings + ); managementFile = managementFormat.generate "config.json" cfg.managementConfig; - settings = rec { - TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; - TURN_PORT = 3478; - TURN_USER = "netbird"; - TURN_MIN_PORT = 49152; - TURN_MAX_PORT = 65535; - TURN_PASSWORD = - if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null; - TURN_SECRET = - if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret"; + settings = + rec { + TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; + TURN_PORT = 3478; + TURN_USER = "netbird"; + TURN_MIN_PORT = 49152; + TURN_MAX_PORT = 65535; + TURN_PASSWORD = if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null; + TURN_SECRET = if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret"; - STUN_USERNAME = ""; - STUN_PASSWORD = - if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null; + STUN_USERNAME = ""; + STUN_PASSWORD = if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null; - NETBIRD_DASHBOARD_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:443"; - NETBIRD_MGMT_API_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ - builtins.toString - cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT + NETBIRD_DASHBOARD_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:443"; + NETBIRD_MGMT_API_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ + builtins.toString cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT }"; - NETBIRD_SIGNAL_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ - builtins.toString - cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT + NETBIRD_SIGNAL_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ + builtins.toString cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT }"; - NETBIRD_SIGNAL_PROTOCOL = "https"; - NETBIRD_SIGNAL_PORT = 443; + NETBIRD_SIGNAL_PROTOCOL = "https"; + NETBIRD_SIGNAL_PORT = 443; - NETBIRD_AUTH_USER_ID_CLAIM = "sub"; - NETBIRD_AUTH_CLIENT_SECRET = - if cfg.secretFiles.AUTH_CLIENT_SECRET != null then - "$AUTH_CLIENT_SECRET" - else - ""; - NETBIRD_AUTH_SUPPORTED_SCOPES = - [ "openid" "profile" "email" "offline_access" "api" ]; + NETBIRD_AUTH_USER_ID_CLAIM = "sub"; + NETBIRD_AUTH_CLIENT_SECRET = + if cfg.secretFiles.AUTH_CLIENT_SECRET != null then "$AUTH_CLIENT_SECRET" else ""; + NETBIRD_AUTH_SUPPORTED_SCOPES = [ + "openid" + "profile" + "email" + "offline_access" + "api" + ]; - NETBIRD_AUTH_REDIRECT_URI = ""; - NETBIRD_AUTH_SILENT_REDIRECT_URI = ""; + NETBIRD_AUTH_REDIRECT_URI = ""; + NETBIRD_AUTH_SILENT_REDIRECT_URI = ""; - NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none"; - NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; - NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE; - NETBIRD_AUTH_DEVICE_AUTH_SCOPE = - [ "openid" "profile" "email" "offline_access" "api" ]; - NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false; + NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none"; + NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE; + NETBIRD_AUTH_DEVICE_AUTH_SCOPE = [ + "openid" + "profile" + "email" + "offline_access" + "api" + ]; + NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false; - NETBIRD_MGMT_API_PORT = 443; + NETBIRD_MGMT_API_PORT = 443; - NETBIRD_MGMT_IDP = "none"; - NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; - NETBIRD_IDP_MGMT_CLIENT_SECRET = - if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then - "$IDP_MGMT_CLIENT_SECRET" - else - cfg.settings.NETBIRD_AUTH_CLIENT_SECRET; - NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials"; + NETBIRD_MGMT_IDP = "none"; + NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_IDP_MGMT_CLIENT_SECRET = + if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then + "$IDP_MGMT_CLIENT_SECRET" + else + cfg.settings.NETBIRD_AUTH_CLIENT_SECRET; + NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials"; - NETBIRD_TOKEN_SOURCE = "accessToken"; - NETBIRD_DRAG_QUERY_PARAMS = false; + NETBIRD_TOKEN_SOURCE = "accessToken"; + NETBIRD_DRAG_QUERY_PARAMS = false; - NETBIRD_USE_AUTH0 = false; + NETBIRD_USE_AUTH0 = false; - NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = ""; + NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = ""; - NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ]; - NETBIRD_AUTH_PKCE_REDIRECT_URLS = builtins.map (p: "http://localhost:${p}") - cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS; - } // (optionalAttrs cfg.setupAutoOidc { - NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT = - "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT"; - NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"; - NETBIRD_AUTH_TOKEN_ENDPOINT = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; - NETBIRD_AUTH_JWT_CERTS = "$NETBIRD_AUTH_JWT_CERTS"; - NETBIRD_AUTH_AUTHORITY = "$NETBIRD_AUTH_AUTHORITY"; - }) // cfg.settings; -in { - meta = { maintainers = with maintainers; [ thubrecht ]; }; + NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ]; + NETBIRD_AUTH_PKCE_REDIRECT_URLS = + builtins.map (p: "http://localhost:${p}") + cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS; + } + // (optionalAttrs cfg.setupAutoOidc { + NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT = "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT"; + NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"; + NETBIRD_AUTH_TOKEN_ENDPOINT = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; + NETBIRD_AUTH_JWT_CERTS = "$NETBIRD_AUTH_JWT_CERTS"; + NETBIRD_AUTH_AUTHORITY = "$NETBIRD_AUTH_AUTHORITY"; + }) + // cfg.settings; +in +{ + meta = { + maintainers = with maintainers; [ thubrecht ]; + }; options.services.netbird-server = { enable = mkEnableOption (lib.mdDoc "netbird management service."); @@ -111,8 +135,19 @@ in { }; settings = mkOption { - type = with types; - attrsOf (nullOr (oneOf [ (listOf str) bool int float str ])); + type = + with types; + attrsOf ( + nullOr ( + oneOf [ + (listOf str) + bool + int + float + str + ] + ) + ); defaultText = lib.literalExpression '' { TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; @@ -195,15 +230,19 @@ in { }; logLevel = mkOption { - type = types.enum [ "ERROR" "WARN" "INFO" "DEBUG" ]; + type = types.enum [ + "ERROR" + "WARN" + "INFO" + "DEBUG" + ]; default = "INFO"; description = lib.mdDoc "Log level of the netbird services."; }; - enableDeviceAuthorizationFlow = - mkEnableOption "device authorization flow for netbird." // { - default = true; - }; + enableDeviceAuthorizationFlow = mkEnableOption "device authorization flow for netbird." // { + default = true; + }; enableNginx = mkEnableOption "NGINX reverse-proxy for the netbird server."; @@ -232,8 +271,7 @@ in { disableAnonymousMetrics = mkOption { type = types.bool; default = true; - description = - lib.mdDoc "Disables push of anonymous usage metrics to NetBird."; + description = lib.mdDoc "Disables push of anonymous usage metrics to NetBird."; }; disableSingleAccountMode = mkOption { @@ -250,38 +288,32 @@ in { TURN_PASSWORD = mkOption { type = with types; nullOr path; default = null; - description = - lib.mdDoc "Path to a file containing the secret TURN_PASSWORD."; + description = lib.mdDoc "Path to a file containing the secret TURN_PASSWORD."; }; TURN_SECRET = mkOption { type = with types; nullOr path; default = null; - description = - lib.mdDoc "Path to a file containing the secret TURN_SECRET."; + description = lib.mdDoc "Path to a file containing the secret TURN_SECRET."; }; STUN_PASSWORD = mkOption { type = with types; nullOr path; default = null; - description = - lib.mdDoc "Path to a file containing the secret STUN_PASSWORD."; + description = lib.mdDoc "Path to a file containing the secret STUN_PASSWORD."; }; AUTH_CLIENT_SECRET = mkOption { type = with types; nullOr path; default = null; - description = lib.mdDoc - "Path to a file containing the secret NETBIRD_AUTH_CLIENT_SECRET."; + description = lib.mdDoc "Path to a file containing the secret NETBIRD_AUTH_CLIENT_SECRET."; }; IDP_MGMT_CLIENT_SECRET = mkOption { type = with types; nullOr path; default = cfg.secretFiles.AUTH_CLIENT_SECRET; - defaultText = - lib.literalExpression "cfg.secretFiles.AUTH_CLIENT_SECRET;"; - description = lib.mdDoc - "Path to a file containing the secret NETBIRD_IDP_MGMT_CLIENT_SECRET."; + defaultText = lib.literalExpression "cfg.secretFiles.AUTH_CLIENT_SECRET;"; + description = lib.mdDoc "Path to a file containing the secret NETBIRD_IDP_MGMT_CLIENT_SECRET."; }; }; }; @@ -289,19 +321,23 @@ in { config = mkMerge [ (mkIf cfg.enable { services.netbird-server.managementConfig = with settings; { - Stuns = mkDefault [{ - Proto = "udp"; - URI = "stun:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; - Username = STUN_USERNAME; - Password = STUN_PASSWORD; - }]; - TURNConfig = { - Turns = [{ + Stuns = mkDefault [ + { Proto = "udp"; - URI = "turn:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; - Username = TURN_USER; - Password = TURN_PASSWORD; - }]; + URI = "stun:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; + Username = STUN_USERNAME; + Password = STUN_PASSWORD; + } + ]; + TURNConfig = { + Turns = [ + { + Proto = "udp"; + URI = "turn:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; + Username = TURN_USER; + Password = TURN_PASSWORD; + } + ]; CredentialsTTL = "12h"; Secret = TURN_SECRET; TimeBasedCredentials = false; @@ -340,8 +376,7 @@ in { ClientID = NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID; TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT; DeviceAuthEndpoint = NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT; - Scope = - builtins.concatStringsSep " " NETBIRD_AUTH_DEVICE_AUTH_SCOPE; + Scope = builtins.concatStringsSep " " NETBIRD_AUTH_DEVICE_AUTH_SCOPE; UseIDToken = NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN; }; }; @@ -377,13 +412,10 @@ in { grpc_socket_keepalive on; ''; - "/api".proxyPass = - "http://localhost:${builtins.toString cfg.ports.management}"; + "/api".proxyPass = "http://localhost:${builtins.toString cfg.ports.management}"; "/management.ManagementService/".extraConfig = '' - grpc_pass grpc://localhost:${ - builtins.toString cfg.ports.management - }; + grpc_pass grpc://localhost:${builtins.toString cfg.ports.management}; grpc_read_timeout 1d; grpc_send_timeout 1d; grpc_socket_keepalive on; @@ -411,59 +443,81 @@ in { StartLimitBurst = 10; }; - path = (with pkgs; [ coreutils findutils gettext gnused ]) - ++ (optionals cfg.setupAutoOidc (with pkgs; [ curl jq ])); + path = + (with pkgs; [ + coreutils + findutils + gettext + gnused + ]) + ++ (optionals cfg.setupAutoOidc ( + with pkgs; + [ + curl + jq + ] + )); - script = '' - cp ${managementFile} ${stateDir}/management.json.copy - '' + (optionalString cfg.setupAutoOidc '' - mv ${stateDir}/management.json.copy ${stateDir}/management.json - echo "loading OpenID configuration from $NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT to the openid-configuration.json file" - curl "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" -q -o ${stateDir}/openid-configuration.json + script = + '' + cp ${managementFile} ${stateDir}/management.json.copy + '' + + (optionalString cfg.setupAutoOidc '' + mv ${stateDir}/management.json.copy ${stateDir}/management.json + echo "loading OpenID configuration from $NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT to the openid-configuration.json file" + curl "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" -q -o ${stateDir}/openid-configuration.json - export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${stateDir}/openid-configuration.json) - export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${stateDir}/openid-configuration.json) - export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${stateDir}/openid-configuration.json) - export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${stateDir}/openid-configuration.json) - export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${stateDir}/openid-configuration.json) + export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${stateDir}/openid-configuration.json) + export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${stateDir}/openid-configuration.json) + export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${stateDir}/openid-configuration.json) + export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${stateDir}/openid-configuration.json) + export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${stateDir}/openid-configuration.json) - envsubst '$NETBIRD_AUTH_AUTHORITY $NETBIRD_AUTH_JWT_CERTS $NETBIRD_AUTH_TOKEN_ENDPOINT $NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT $NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT' < ${stateDir}/management.json > ${stateDir}/management.json.copy - '') + '' - # Update secrets in management.json - ${builtins.concatStringsSep "\n" (builtins.attrValues - (builtins.mapAttrs (name: path: "export ${name}=$(cat ${path})") - (filterAttrs (_: p: p != null) cfg.secretFiles)))} + envsubst '$NETBIRD_AUTH_AUTHORITY $NETBIRD_AUTH_JWT_CERTS $NETBIRD_AUTH_TOKEN_ENDPOINT $NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT $NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT' < ${stateDir}/management.json > ${stateDir}/management.json.copy + '') + + '' + # Update secrets in management.json + ${builtins.concatStringsSep "\n" ( + builtins.attrValues ( + builtins.mapAttrs (name: path: "export ${name}=$(cat ${path})") ( + filterAttrs (_: p: p != null) cfg.secretFiles + ) + ) + )} - envsubst '$TURN_PASSWORD $TURN_SECRET $STUN_PASSWORD $AUTH_CLIENT_SECRET $IDP_MGMT_CLIENT_SECRET' < ${stateDir}/management.json.copy > ${stateDir}/management.json + envsubst '$TURN_PASSWORD $TURN_SECRET $STUN_PASSWORD $AUTH_CLIENT_SECRET $IDP_MGMT_CLIENT_SECRET' < ${stateDir}/management.json.copy > ${stateDir}/management.json - rm -rf ${stateDir}/web-ui - mkdir -p ${stateDir}/web-ui - cp -R ${dashboard}/* ${stateDir}/web-ui + rm -rf ${stateDir}/web-ui + mkdir -p ${stateDir}/web-ui + cp -R ${dashboard}/* ${stateDir}/web-ui - export AUTH_AUTHORITY="$NETBIRD_AUTH_AUTHORITY" - export AUTH_CLIENT_ID="$NETBIRD_AUTH_CLIENT_ID" - ${optionalString (cfg.secretFiles.AUTH_CLIENT_SECRET == null) - ''export AUTH_CLIENT_SECRET="$NETBIRD_AUTH_CLIENT_SECRET"''} - export AUTH_AUDIENCE="$NETBIRD_AUTH_AUDIENCE" - export AUTH_REDIRECT_URI="$NETBIRD_AUTH_REDIRECT_URI" - export AUTH_SILENT_REDIRECT_URI="$NETBIRD_AUTH_SILENT_REDIRECT_URI" - export USE_AUTH0="$NETBIRD_USE_AUTH0" - export AUTH_SUPPORTED_SCOPES=$(echo $NETBIRD_AUTH_SUPPORTED_SCOPES | sed -E 's/"//g') + export AUTH_AUTHORITY="$NETBIRD_AUTH_AUTHORITY" + export AUTH_CLIENT_ID="$NETBIRD_AUTH_CLIENT_ID" + ${optionalString (cfg.secretFiles.AUTH_CLIENT_SECRET == null) + ''export AUTH_CLIENT_SECRET="$NETBIRD_AUTH_CLIENT_SECRET"''} + export AUTH_AUDIENCE="$NETBIRD_AUTH_AUDIENCE" + export AUTH_REDIRECT_URI="$NETBIRD_AUTH_REDIRECT_URI" + export AUTH_SILENT_REDIRECT_URI="$NETBIRD_AUTH_SILENT_REDIRECT_URI" + export USE_AUTH0="$NETBIRD_USE_AUTH0" + export AUTH_SUPPORTED_SCOPES=$(echo $NETBIRD_AUTH_SUPPORTED_SCOPES | sed -E 's/"//g') - export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//') + export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//') - MAIN_JS=$(find ${stateDir}/web-ui/static/js/main.*js) - OIDC_TRUSTED_DOMAINS=${stateDir}/web-ui/OidcTrustedDomains.js - mv "$MAIN_JS" "$MAIN_JS".copy - envsubst '$USE_AUTH0 $AUTH_AUTHORITY $AUTH_CLIENT_ID $AUTH_CLIENT_SECRET $AUTH_SUPPORTED_SCOPES $AUTH_AUDIENCE $NETBIRD_MGMT_API_ENDPOINT $NETBIRD_MGMT_GRPC_API_ENDPOINT $NETBIRD_HOTJAR_TRACK_ID $AUTH_REDIRECT_URI $AUTH_SILENT_REDIRECT_URI $NETBIRD_TOKEN_SOURCE $NETBIRD_DRAG_QUERY_PARAMS' < "$MAIN_JS".copy > "$MAIN_JS" - envsubst '$NETBIRD_MGMT_API_ENDPOINT' < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS" - ''; + MAIN_JS=$(find ${stateDir}/web-ui/static/js/main.*js) + OIDC_TRUSTED_DOMAINS=${stateDir}/web-ui/OidcTrustedDomains.js + mv "$MAIN_JS" "$MAIN_JS".copy + envsubst '$USE_AUTH0 $AUTH_AUTHORITY $AUTH_CLIENT_ID $AUTH_CLIENT_SECRET $AUTH_SUPPORTED_SCOPES $AUTH_AUDIENCE $NETBIRD_MGMT_API_ENDPOINT $NETBIRD_MGMT_GRPC_API_ENDPOINT $NETBIRD_HOTJAR_TRACK_ID $AUTH_REDIRECT_URI $AUTH_SILENT_REDIRECT_URI $NETBIRD_TOKEN_SOURCE $NETBIRD_DRAG_QUERY_PARAMS' < "$MAIN_JS".copy > "$MAIN_JS" + envsubst '$NETBIRD_MGMT_API_ENDPOINT' < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS" + ''; }; netbird-signal = { after = [ "network.target" ]; wantedBy = [ "netbird-management.service" ]; - restartTriggers = [ settingsFile managementFile ]; + restartTriggers = [ + settingsFile + managementFile + ]; serviceConfig = { ExecStart = '' @@ -487,24 +541,27 @@ in { netbird-management = { description = "The management server for Netbird, a wireguard VPN"; documentation = [ "https://netbird.io/docs/" ]; - after = [ "network.target" "netbird-setup.service" ]; + after = [ + "network.target" + "netbird-setup.service" + ]; wantedBy = [ "multi-user.target" ]; - wants = [ "netbird-signal.service" "netbird-setup.service" ]; - restartTriggers = [ settingsFile managementFile ]; + wants = [ + "netbird-signal.service" + "netbird-setup.service" + ]; + restartTriggers = [ + settingsFile + managementFile + ]; serviceConfig = { ExecStart = '' ${cfg.package}/bin/netbird-mgmt management \ --config ${stateDir}/management.json \ --datadir ${stateDir}/data \ - ${ - optionalString cfg.management.disableAnonymousMetrics - "--disable-anonymous-metrics" - } \ - ${ - optionalString cfg.management.disableSingleAccountMode - "--disable-single-account-mode" - } \ + ${optionalString cfg.management.disableAnonymousMetrics "--disable-anonymous-metrics"} \ + ${optionalString cfg.management.disableSingleAccountMode "--disable-single-account-mode"} \ --dns-domain ${cfg.management.dnsDomain} \ --single-account-mode-domain ${cfg.management.singleAccountModeDomain} \ --idp-sign-key-refresh-enabled \ @@ -514,7 +571,10 @@ in { ''; Restart = "always"; RuntimeDirectory = "netbird-mgmt"; - StateDirectory = [ "netbird-mgmt" "netbird-mgmt/data" ]; + StateDirectory = [ + "netbird-mgmt" + "netbird-mgmt/data" + ]; WorkingDirectory = stateDir; }; unitConfig = { @@ -549,18 +609,25 @@ in { 5349 5350 ]; - allowedTCPPorts = with settings; [ TURN_PORT (TURN_PORT + 1) ]; - allowedUDPPortRanges = [{ - from = settings.TURN_MIN_PORT; - to = settings.TURN_MAX_PORT; - }]; + allowedTCPPorts = with settings; [ + TURN_PORT + (TURN_PORT + 1) + ]; + allowedUDPPortRanges = [ + { + from = settings.TURN_MIN_PORT; + to = settings.TURN_MAX_PORT; + } + ]; }; }) (mkIf (cfg.enableNginx && cfg.enableCoturn) { services.coturn = - let cert = config.security.acme.certs.${settings.TURN_DOMAIN}; - in { + let + cert = config.security.acme.certs.${settings.TURN_DOMAIN}; + in + { cert = "${cert.directory}/fullchain.pem"; pkey = "${cert.directory}/key.pem"; }; @@ -570,8 +637,7 @@ in { # share certs with coturn and restart on renewal security.acme.certs.${settings.TURN_DOMAIN} = { group = "turnserver"; - postRun = - "systemctl reload nginx.service; systemctl restart coturn.service"; + postRun = "systemctl reload nginx.service; systemctl restart coturn.service"; }; }) ]; diff --git a/machines/storage01/netbird/package/dashboard.nix b/machines/storage01/netbird/package/dashboard.nix index 7b27166..7dd72fc 100644 --- a/machines/storage01/netbird/package/dashboard.nix +++ b/machines/storage01/netbird/package/dashboard.nix @@ -1,4 +1,8 @@ -{ lib, buildNpmPackage, fetchFromGitHub }: +{ + lib, + buildNpmPackage, + fetchFromGitHub, +}: buildNpmPackage rec { pname = "netbird-dashboard"; diff --git a/machines/storage01/netbird/package/default.nix b/machines/storage01/netbird/package/default.nix index 40c4992..f6dd7d5 100644 --- a/machines/storage01/netbird/package/default.nix +++ b/machines/storage01/netbird/package/default.nix @@ -1,4 +1,6 @@ -{ pkgs ? import {} }: +{ + pkgs ? import { }, +}: { dashboard = pkgs.callPackage ./dashboard.nix { }; diff --git a/machines/storage01/peertube.nix b/machines/storage01/peertube.nix index 64544dd..ceefd56 100644 --- a/machines/storage01/peertube.nix +++ b/machines/storage01/peertube.nix @@ -1,7 +1,9 @@ { config, ... }: -let host = "videos.dgnum.eu"; -in { +let + host = "videos.dgnum.eu"; +in +{ services.peertube = { enable = true; @@ -53,8 +55,7 @@ in { database.createLocally = true; smtp.passwordFile = config.age.secrets."peertube-smtp_password_file".path; - serviceEnvironmentFile = - config.age.secrets."peertube-service_environment_file".path; + serviceEnvironmentFile = config.age.secrets."peertube-service_environment_file".path; secrets.secretsFile = config.age.secrets."peertube-secrets_file".path; }; @@ -63,5 +64,7 @@ in { forceSSL = true; }; - age-secrets.matches."^peertube-.*$" = { owner = "peertube"; }; + age-secrets.matches."^peertube-.*$" = { + owner = "peertube"; + }; } diff --git a/machines/storage01/secrets/secrets.nix b/machines/storage01/secrets/secrets.nix index cf6edba..5201bf7 100644 --- a/machines/storage01/secrets/secrets.nix +++ b/machines/storage01/secrets/secrets.nix @@ -1,8 +1,8 @@ let lib = import ../../../lib { }; publicKeys = lib.getNodeKeys "storage01"; - -in lib.setDefault { inherit publicKeys; } [ +in +lib.setDefault { inherit publicKeys; } [ "atticd-credentials_file" "forgejo-database_password_file" "forgejo_runners-token_file" diff --git a/machines/vault01/_configuration.nix b/machines/vault01/_configuration.nix index a7393db..adef81f 100644 --- a/machines/vault01/_configuration.nix +++ b/machines/vault01/_configuration.nix @@ -11,8 +11,10 @@ lib.extra.mkConfig { ]; extraConfig = { - dgn-fail2ban.jails = - lib.extra.enableAttrs' "enabled" [ "sshd-bruteforce" "sshd-timeout" ]; + dgn-fail2ban.jails = lib.extra.enableAttrs' "enabled" [ + "sshd-bruteforce" + "sshd-timeout" + ]; services.netbird.enable = true; diff --git a/machines/vault01/_hardware-configuration.nix b/machines/vault01/_hardware-configuration.nix index 7f4189f..325e600 100644 --- a/machines/vault01/_hardware-configuration.nix +++ b/machines/vault01/_hardware-configuration.nix @@ -8,8 +8,14 @@ boot = { initrd = { - availableKernelModules = - [ "xhci_pci" "megaraid_sas" "ehci_pci" "ahci" "usb_storage" "sd_mod" ]; + availableKernelModules = [ + "xhci_pci" + "megaraid_sas" + "ehci_pci" + "ahci" + "usb_storage" + "sd_mod" + ]; kernelModules = [ ]; }; @@ -30,6 +36,5 @@ }; }; - swapDevices = - [{ device = "/dev/disk/by-uuid/954ecb9c-ccd1-4e98-9eb6-3514bd3c01d1"; }]; + swapDevices = [ { device = "/dev/disk/by-uuid/954ecb9c-ccd1-4e98-9eb6-3514bd3c01d1"; } ]; } diff --git a/machines/vault01/secrets/secrets.nix b/machines/vault01/secrets/secrets.nix index bad9995..5f10b40 100644 --- a/machines/vault01/secrets/secrets.nix +++ b/machines/vault01/secrets/secrets.nix @@ -1,6 +1,5 @@ let lib = import ../../../lib { }; publicKeys = lib.getNodeKeys "vault01"; - -in lib.setDefault { inherit publicKeys; } [ -] +in +lib.setDefault { inherit publicKeys; } [ ] diff --git a/machines/web01/_hardware-configuration.nix b/machines/web01/_hardware-configuration.nix index 015c67b..d4ca50c 100644 --- a/machines/web01/_hardware-configuration.nix +++ b/machines/web01/_hardware-configuration.nix @@ -6,7 +6,12 @@ { imports = [ (modulesPath + "/profiles/qemu-guest.nix") - (let sources = import ../../npins; in sources.disko + "/module.nix") + ( + let + sources = import ../../npins; + in + sources.disko + "/module.nix" + ) ./disko.nix ]; } diff --git a/machines/web01/castopod-head-proxy.nix b/machines/web01/castopod-head-proxy.nix index 931af0e..baacfca 100644 --- a/machines/web01/castopod-head-proxy.nix +++ b/machines/web01/castopod-head-proxy.nix @@ -3,31 +3,31 @@ let cfg = config.services.castopod; fpm = config.services.phpfpm.pools.castopod; in - { +{ services.nginx = { - resolver.addresses = [ "127.0.0.53" ]; - virtualHosts."${cfg.localDomain}" = { + resolver.addresses = [ "127.0.0.53" ]; + virtualHosts."${cfg.localDomain}" = { - locations."@force_get" = { - extraConfig = lib.mkForce '' - recursive_error_pages on; - proxy_method GET; - proxy_pass https://podcasts.dgnum.eu/$request_uri; - ''; - }; + locations."@force_get" = { + extraConfig = lib.mkForce '' + recursive_error_pages on; + proxy_method GET; + proxy_pass https://podcasts.dgnum.eu/$request_uri; + ''; + }; - locations."~ \.php$" = { - extraConfig = lib.mkForce '' - error_page 550 = @force_get; - if ($request_method = HEAD) { return 550; } - fastcgi_intercept_errors on; - fastcgi_index index.php; - fastcgi_pass unix:${fpm.socket}; - try_files $uri =404; - fastcgi_read_timeout 3600; - fastcgi_send_timeout 3600; - ''; - }; + locations."~ .php$" = { + extraConfig = lib.mkForce '' + error_page 550 = @force_get; + if ($request_method = HEAD) { return 550; } + fastcgi_intercept_errors on; + fastcgi_index index.php; + fastcgi_pass unix:${fpm.socket}; + try_files $uri =404; + fastcgi_read_timeout 3600; + fastcgi_send_timeout 3600; + ''; }; }; - } + }; +} diff --git a/machines/web01/castopod.nix b/machines/web01/castopod.nix index 4a63f5c..d958f4a 100644 --- a/machines/web01/castopod.nix +++ b/machines/web01/castopod.nix @@ -1,38 +1,41 @@ -{ config, pkgs, ...}: +{ config, pkgs, ... }: let host = "podcasts.dgnum.eu"; in { - imports = [ - ./castopod-head-proxy.nix - ]; - services.castopod = { - enable = true; - localDomain = host; - environmentFile = config.age.secrets.castopod-environment_file.path; - maxUploadSize = 512; - settings = { - "email.fromEmail"="noreply@infra.dgnum.eu"; - "email.SMTPHost"="kurisu.lahfa.xyz"; - "email.SMTPUser"="web-services@infra.dgnum.eu"; - "email.SMTPPort"="587"; + imports = [ ./castopod-head-proxy.nix ]; - "media.fileManager"="s3"; - "media.s3.endpoint"="https://s3.dgnum.eu/"; - "media.s3.region"="garage"; - "media.s3.bucket"="castopod-dgnum"; - "media.s3.pathStyleEndpoint"=true; + services = { + castopod = { + enable = true; + localDomain = host; + environmentFile = config.age.secrets.castopod-environment_file.path; + maxUploadSize = 512; + settings = { + "email.fromEmail" = "noreply@infra.dgnum.eu"; + "email.SMTPHost" = "kurisu.lahfa.xyz"; + "email.SMTPUser" = "web-services@infra.dgnum.eu"; + "email.SMTPPort" = "587"; - "restapi.enabled"=true; - "restapi.basicAuthUsername"="castopod"; - "restapi.basicAuth"=true; + "media.fileManager" = "s3"; + "media.s3.endpoint" = "https://s3.dgnum.eu/"; + "media.s3.region" = "garage"; + "media.s3.bucket" = "castopod-dgnum"; + "media.s3.pathStyleEndpoint" = true; + + "restapi.enabled" = true; + "restapi.basicAuthUsername" = "castopod"; + "restapi.basicAuth" = true; + }; + database.createLocally = true; + configureNginx = true; + }; + + mysql.package = pkgs.mariadb; + + nginx.virtualHosts.${host} = { + forceSSL = true; + enableACME = true; }; - database.createLocally = true; - configureNginx = true; - }; - services.mysql.package = pkgs.mariadb; - services.nginx.virtualHosts.${host} = { - forceSSL = true; - enableACME = true; }; } diff --git a/machines/web01/disko.nix b/machines/web01/disko.nix index 52c9262..573f790 100644 --- a/machines/web01/disko.nix +++ b/machines/web01/disko.nix @@ -56,7 +56,10 @@ in mountpoint = "/var/log"; }; "/nix" = { - mountOptions = [ "noatime" "compress=zstd" ]; + mountOptions = [ + "noatime" + "compress=zstd" + ]; mountpoint = "/nix"; }; }; diff --git a/machines/web01/dolibarr.nix b/machines/web01/dolibarr.nix index ee0272e..abbb4a0 100644 --- a/machines/web01/dolibarr.nix +++ b/machines/web01/dolibarr.nix @@ -1,5 +1,4 @@ -{ ... }: -{ +_: { services.dolibarr = { enable = true; domain = "erp.dgnum.eu"; diff --git a/machines/web01/linkal/default.nix b/machines/web01/linkal/default.nix index 741c13c..148e25b 100644 --- a/machines/web01/linkal/default.nix +++ b/machines/web01/linkal/default.nix @@ -1,4 +1,9 @@ -{ sources, pkgs, lib, ... }: +{ + sources, + pkgs, + lib, + ... +}: let host = "cal.dgnum.eu"; @@ -26,7 +31,8 @@ let calendars = metis2linkal sources.metis; }; }; -in { +in +{ imports = [ ./module.nix ]; dgn-linkal = { diff --git a/machines/web01/linkal/metis-to-linkal.nix b/machines/web01/linkal/metis-to-linkal.nix index 3ba2383..8e9c9be 100644 --- a/machines/web01/linkal/metis-to-linkal.nix +++ b/machines/web01/linkal/metis-to-linkal.nix @@ -7,18 +7,10 @@ let inherit (import source { inherit pkgs; }) providers; # helper function to map 2-level deep attribute-sets - mapDeepAttrs = mapFct: - lib.concatMapAttrs (name: value: - lib.mapAttrs' (name': value': - mapFct name name' value' - ) value - ); - - - toLinkal = upstream: identifier: - lib.nameValuePair - "${providers.${upstream}}${identifier}" - ; + mapDeepAttrs = + mapFct: + lib.concatMapAttrs (name: value: lib.mapAttrs' (name': value': mapFct name name' value') value); + toLinkal = upstream: identifier: lib.nameValuePair "${providers.${upstream}}${identifier}"; in - mapDeepAttrs toLinkal calendars +mapDeepAttrs toLinkal calendars diff --git a/machines/web01/linkal/module.nix b/machines/web01/linkal/module.nix index bc49e69..df762fc 100644 --- a/machines/web01/linkal/module.nix +++ b/machines/web01/linkal/module.nix @@ -1,14 +1,28 @@ -{ config, lib, pkgs, sources, ... }: +{ + config, + lib, + pkgs, + sources, + ... +}: let - inherit (lib) mapAttrs' mkEnableOption mkIf mkOption nameValuePair types; + inherit (lib) + mapAttrs' + mkEnableOption + mkIf + mkOption + nameValuePair + types + ; package = import sources.linkal { inherit pkgs; }; cfg = config.dgn-linkal; jsonFormat = pkgs.formats.json { }; -in { +in +{ options.dgn-linkal = { enable = mkEnableOption "the linkal server."; @@ -20,32 +34,40 @@ in { domain = mkOption { type = types.str; }; calendarGroups = mkOption { - type = let inherit (types) attrsOf port submodule; - in attrsOf (submodule { - options = { - port = mkOption { type = port; }; - calendars = mkOption { inherit (jsonFormat) type; }; - }; - }); + type = + let + inherit (types) attrsOf port submodule; + in + attrsOf ( + submodule { + options = { + port = mkOption { type = port; }; + calendars = mkOption { inherit (jsonFormat) type; }; + }; + } + ); default = { }; }; }; config = mkIf cfg.enable { - systemd.services = mapAttrs' (name: - { port, calendars }: - nameValuePair "linkal-${name}" { - description = "Linkal - ${name}"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${cfg.package}/bin/linkal --port ${ - builtins.toString port - } --calendar-file ${ - jsonFormat.generate "linkal-${name}.json" { inherit calendars; } - }"; - }; - }) cfg.calendarGroups; + systemd.services = + mapAttrs' + ( + name: + { port, calendars }: + nameValuePair "linkal-${name}" { + description = "Linkal - ${name}"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/linkal --port ${builtins.toString port} --calendar-file ${ + jsonFormat.generate "linkal-${name}.json" { inherit calendars; } + }"; + }; + } + ) + cfg.calendarGroups; # Configure bind for DNS certificate validation on *.cal.dgnum.eu. # services.bind = { @@ -85,16 +107,20 @@ in { services.nginx = { enable = true; - virtualHosts = mapAttrs' (name: - { port, ... }: - nameValuePair "${name}.${cfg.domain}" { - enableACME = true; - # acmeRoot = null; # Use DNS-01 validation - forceSSL = true; + virtualHosts = + mapAttrs' + ( + name: + { port, ... }: + nameValuePair "${name}.${cfg.domain}" { + enableACME = true; + # acmeRoot = null; # Use DNS-01 validation + forceSSL = true; - locations."/".proxyPass = - "http://127.0.0.1:${builtins.toString port}/"; - }) cfg.calendarGroups; + locations."/".proxyPass = "http://127.0.0.1:${builtins.toString port}/"; + } + ) + cfg.calendarGroups; }; }; } diff --git a/machines/web01/matterbridge.nix b/machines/web01/matterbridge.nix index 5a152df..67411b4 100644 --- a/machines/web01/matterbridge.nix +++ b/machines/web01/matterbridge.nix @@ -6,5 +6,7 @@ configPath = config.age.secrets."matterbridge-config_file".path; }; - age-secrets.matches."^matterbridge-.*$" = { owner = "matterbridge"; }; + age-secrets.matches."^matterbridge-.*$" = { + owner = "matterbridge"; + }; } diff --git a/machines/web01/metis/default.nix b/machines/web01/metis/default.nix index 286ec4c..842be78 100644 --- a/machines/web01/metis/default.nix +++ b/machines/web01/metis/default.nix @@ -1,24 +1,35 @@ -{ lib, pkgs, sources, ... }: +{ + lib, + pkgs, + sources, + ... +}: let metis = import sources.metis { inherit pkgs; }; inherit (metis) providers; -in { +in +{ services.nginx.virtualHosts."calendrier.dgnum.eu" = { enableACME = true; forceSSL = true; root = metis.production; - locations = lib.mapAttrs' (name: value: - lib.nameValuePair "/cal/${name}/" { - extraConfig = '' - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass ${value}; - ''; - }) providers; + locations = + lib.mapAttrs' + ( + name: value: + lib.nameValuePair "/cal/${name}/" { + extraConfig = '' + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass ${value}; + ''; + } + ) + providers; extraConfig = '' rewrite ^/calendrier(.*)$ $1 permanent; diff --git a/machines/web01/ntfy-sh.nix b/machines/web01/ntfy-sh.nix index 27c117c..b6e3fb4 100644 --- a/machines/web01/ntfy-sh.nix +++ b/machines/web01/ntfy-sh.nix @@ -1,8 +1,9 @@ { config, ... }: -let host = "push.dgnum.eu"; - -in { +let + host = "push.dgnum.eu"; +in +{ services.ntfy-sh = { enable = true; @@ -26,6 +27,7 @@ in { }; }; - systemd.services.ntfy-sh.serviceConfig.EnvironmentFile = - [ config.age.secrets."ntfy_sh-environment_file".path ]; + systemd.services.ntfy-sh.serviceConfig.EnvironmentFile = [ + config.age.secrets."ntfy_sh-environment_file".path + ]; } diff --git a/machines/web01/redirections.nix b/machines/web01/redirections.nix index 539dc27..ff06710 100644 --- a/machines/web01/redirections.nix +++ b/machines/web01/redirections.nix @@ -3,15 +3,19 @@ _: let retired_host = "retired.dgnum.eu"; - mkRetired = hosts: - builtins.listToAttrs (builtins.map (name: { - inherit name; - value.to = retired_host; - }) hosts); + mkRetired = + hosts: + builtins.listToAttrs ( + builtins.map + (name: { + inherit name; + value.to = retired_host; + }) + hosts + ); mkSub = domain: builtins.map (s: "${s}.${domain}"); - mkSubs = attrs: - builtins.concatLists (builtins.attrValues (builtins.mapAttrs mkSub attrs)); + mkSubs = attrs: builtins.concatLists (builtins.attrValues (builtins.mapAttrs mkSub attrs)); redirections = { "calendrier.eleves.ens.fr".to = "calendrier.dgnum.eu"; @@ -23,9 +27,15 @@ let } // (mkRetired retired); retired = mkSubs { - "ens.fr" = [ "alevins" "www.climatenavigator" ]; + "ens.fr" = [ + "alevins" + "www.climatenavigator" + ]; "ens.wtf" = [ "photos" ]; - "rz.ens.wtf" = [ "s3" "cdn" ]; + "rz.ens.wtf" = [ + "s3" + "cdn" + ]; "beta.rz.ens.wtf" = [ "todo" "minecraft" @@ -39,14 +49,25 @@ let "rstudio" ]; }; - -in { - services.nginx.virtualHosts = { - ${retired_host}.default = true; - } // (builtins.mapAttrs (host: - { to, ssl ? true }: { - globalRedirect = to; - enableACME = ssl; - forceSSL = ssl; - }) redirections); +in +{ + services.nginx.virtualHosts = + { + ${retired_host}.default = true; + } + // (builtins.mapAttrs + ( + _: + { + to, + ssl ? true, + }: + { + globalRedirect = to; + enableACME = ssl; + forceSSL = ssl; + } + ) + redirections + ); } diff --git a/machines/web01/secrets/secrets.nix b/machines/web01/secrets/secrets.nix index 89d67fc..cf456cd 100644 --- a/machines/web01/secrets/secrets.nix +++ b/machines/web01/secrets/secrets.nix @@ -1,7 +1,8 @@ let lib = import ../../../lib { }; publicKeys = lib.getNodeKeys "web01"; -in lib.setDefault { inherit publicKeys; } [ +in +lib.setDefault { inherit publicKeys; } [ "acme-certs_secret" "matterbridge-config_file" "named-bind_dnskeys_conf" diff --git a/machines/web01/static/npins/default.nix b/machines/web01/static/npins/default.nix index 4a7c372..43cead3 100644 --- a/machines/web01/static/npins/default.nix +++ b/machines/web01/static/npins/default.nix @@ -1,20 +1,34 @@ # Generated by npins. Do not modify; will be overwritten regularly let data = builtins.fromJSON (builtins.readFile ./sources.json); - version = data.version; + inherit (data) version; - mkSource = spec: - assert spec ? type; let + mkSource = + spec: + assert spec ? type; + let path = - if spec.type == "Git" then mkGitSource spec - else if spec.type == "GitRelease" then mkGitSource spec - else if spec.type == "PyPi" then mkPyPiSource spec - else if spec.type == "Channel" then mkChannelSource spec - else builtins.throw "Unknown source type ${spec.type}"; + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; in spec // { outPath = path; }; - mkGitSource = { repository, revision, url ? null, hash, ... }: + mkGitSource = + { + repository, + revision, + url ? null, + hash, + ... + }: assert repository ? type; # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository # In the latter case, there we will always be an url to the tarball @@ -23,19 +37,23 @@ let inherit url; sha256 = hash; # FIXME: check nix version & use SRI hashes }) - else assert repository.type == "Git"; builtins.fetchGit { - url = repository.url; - rev = revision; - # hash = hash; - }; + else + assert repository.type == "Git"; + builtins.fetchGit { + inherit (repository) url; + rev = revision; + # hash = hash; + }; - mkPyPiSource = { url, hash, ... }: + mkPyPiSource = + { url, hash, ... }: builtins.fetchurl { inherit url; sha256 = hash; }; - mkChannelSource = { url, hash, ... }: + mkChannelSource = + { url, hash, ... }: builtins.fetchTarball { inherit url; sha256 = hash; diff --git a/machines/web01/wordpress/default.nix b/machines/web01/wordpress/default.nix index 0205a89..1f8357c 100644 --- a/machines/web01/wordpress/default.nix +++ b/machines/web01/wordpress/default.nix @@ -1,7 +1,9 @@ { pkgs, sources, ... }: -let wp4nix = pkgs.callPackage sources.wp4nix { }; -in { +let + wp4nix = pkgs.callPackage sources.wp4nix { }; +in +{ imports = [ ./module.nix ]; services.wp-containers = { @@ -9,26 +11,38 @@ in { sites = { "lavoixduntexte.normalesup.eu" = { - themes = { inherit (wp4nix.themes) avant; }; + themes = { + inherit (wp4nix.themes) avant; + }; - plugins = { inherit (wp4nix.plugins) wordpress-importer; }; + plugins = { + inherit (wp4nix.plugins) wordpress-importer; + }; languages = [ pkgs.wordpressPackages.languages.fr_FR ]; }; "bds.wp.dgnum.eu" = { - plugins = { inherit (wp4nix.plugins) user-role-editor; }; + plugins = { + inherit (wp4nix.plugins) user-role-editor; + }; languages = [ pkgs.wordpressPackages.languages.fr_FR ]; - themes = { inherit (wp4nix.themes) gateway twentytwentythree; }; + themes = { + inherit (wp4nix.themes) gateway twentytwentythree; + }; }; "bda.wp.dgnum.eu" = { - plugins = { inherit (wp4nix.plugins) user-role-editor; }; + plugins = { + inherit (wp4nix.plugins) user-role-editor; + }; languages = [ pkgs.wordpressPackages.languages.fr_FR ]; }; "cineclub.wp.dgnum.eu" = { - plugins = { inherit (wp4nix.plugins) user-role-editor; }; + plugins = { + inherit (wp4nix.plugins) user-role-editor; + }; languages = [ pkgs.wordpressPackages.languages.fr_FR ]; }; }; diff --git a/machines/web01/wordpress/module.nix b/machines/web01/wordpress/module.nix index 3be092f..92a7029 100644 --- a/machines/web01/wordpress/module.nix +++ b/machines/web01/wordpress/module.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) mkEnableOption mkIf mkOption; @@ -13,41 +18,52 @@ let mkHost = mkIp "10.31.41"; mkLocal = mkIp "10.0.0"; - mkConfig = { name, value, i }: { - services.wordpress = { - webserver = "nginx"; - sites.${name} = value; + mkConfig = + { + name, + value, + i, + }: + { + services.wordpress = { + webserver = "nginx"; + sites.${name} = value; + }; + + services.nginx.virtualHosts.${name} = { + onlySSL = true; + sslCertificate = "${certs.${name}.directory}/fullchain.pem"; + sslCertificateKey = "${certs.${name}.directory}/key.pem"; + sslTrustedCertificate = "${certs.${name}.directory}/chain.pem"; + }; + + networking = { + hostName = mkName name; + hosts.${mkLocal i} = [ name ]; + + firewall.allowedTCPPorts = [ 443 ]; + }; + + environment.systemPackages = [ + pkgs.wp-cli + pkgs.neovim + ]; + + system.stateVersion = "23.11"; }; - services.nginx.virtualHosts.${name} = { - onlySSL = true; - sslCertificate = "${certs.${name}.directory}/fullchain.pem"; - sslCertificateKey = "${certs.${name}.directory}/key.pem"; - sslTrustedCertificate = "${certs.${name}.directory}/chain.pem"; - }; - - networking = { - hostName = mkName name; - hosts.${mkLocal i} = [ name ]; - - firewall.allowedTCPPorts = [ 443 ]; - }; - - environment.systemPackages = [ pkgs.wp-cli pkgs.neovim ]; - - system.stateVersion = "23.11"; - }; - mkContainer = i: site: { name = mkName site.name; value = { privateNetwork = true; - forwardPorts = [{ - containerPort = 443; - hostPort = cfg.basePort + i; - }]; + forwardPorts = [ + { + containerPort = 443; + hostPort = cfg.basePort + i; + } + ]; bindMounts.certs = { hostPath = certs.${site.name}.directory; @@ -69,13 +85,13 @@ let enableACME = true; forceSSL = true; - locations."/".proxyPass = - "https://${mkHost i}:${builtins.toString (cfg.basePort + i)}"; + locations."/".proxyPass = "https://${mkHost i}:${builtins.toString (cfg.basePort + i)}"; }; }; siteList = lib.attrsToList cfg.sites; -in { +in +{ options.services.wp-containers = { enable = mkEnableOption "wordpress sites in containers"; @@ -93,7 +109,6 @@ in { config = mkIf cfg.enable { containers = builtins.listToAttrs (lib.imap1 mkContainer siteList); - services.nginx.virtualHosts = - builtins.listToAttrs (lib.imap1 mkVhost siteList); + services.nginx.virtualHosts = builtins.listToAttrs (lib.imap1 mkVhost siteList); }; } diff --git a/machines/web02/_configuration.nix b/machines/web02/_configuration.nix index 2f1eb5c..f11afbf 100644 --- a/machines/web02/_configuration.nix +++ b/machines/web02/_configuration.nix @@ -11,8 +11,10 @@ lib.extra.mkConfig { ]; extraConfig = { - dgn-fail2ban.jails = - lib.extra.enableAttrs' "enabled" [ "sshd-bruteforce" "sshd-timeout" ]; + dgn-fail2ban.jails = lib.extra.enableAttrs' "enabled" [ + "sshd-bruteforce" + "sshd-timeout" + ]; services.netbird.enable = true; }; diff --git a/machines/web02/_hardware-configuration.nix b/machines/web02/_hardware-configuration.nix index a361cc4..2c4341c 100644 --- a/machines/web02/_hardware-configuration.nix +++ b/machines/web02/_hardware-configuration.nix @@ -8,8 +8,14 @@ boot = { initrd = { - availableKernelModules = - [ "ata_piix" "uhci_hcd" "ehci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "ehci_pci" + "virtio_pci" + "sr_mod" + "virtio_blk" + ]; kernelModules = [ ]; }; @@ -30,6 +36,5 @@ }; }; - swapDevices = - [{ device = "/dev/disk/by-uuid/d64ae21e-693c-4c77-b62c-97d5e2a960cb"; }]; + swapDevices = [ { device = "/dev/disk/by-uuid/d64ae21e-693c-4c77-b62c-97d5e2a960cb"; } ]; } diff --git a/machines/web02/secrets/secrets.nix b/machines/web02/secrets/secrets.nix index a892a92..3c037bf 100644 --- a/machines/web02/secrets/secrets.nix +++ b/machines/web02/secrets/secrets.nix @@ -1,6 +1,5 @@ let lib = import ../../../lib { }; publicKeys = lib.getNodeKeys "web02"; - -in lib.setDefault { inherit publicKeys; } [ -] +in +lib.setDefault { inherit publicKeys; } [ ] diff --git a/meta/infrastructure.nix b/meta/infrastructure.nix index c66bb4d..3edb423 100644 --- a/meta/infrastructure.nix +++ b/meta/infrastructure.nix @@ -8,9 +8,7 @@ ]; # Jourdan - par02 = [ - "vault01" - ]; + par02 = [ "vault01" ]; # VMs du SPI/NPS/Whatever dmi01 = [ diff --git a/meta/members.nix b/meta/members.nix index 4c3f3c2..8f9b1b5 100644 --- a/meta/members.nix +++ b/meta/members.nix @@ -26,15 +26,25 @@ let groups = { # members of this group are root on all nodes - root = [ "thubrecht" "raito" "mdebray" ]; + root = [ + "thubrecht" + "raito" + "mdebray" + ]; # members of this group will have root access on the installation isos - iso = [ "thubrecht" "mdebray" "raito" ]; + iso = [ + "thubrecht" + "mdebray" + "raito" + ]; # members of this group can access netbox's secret - netbox = []; + netbox = [ ]; bureau = [ "gdd" ]; }; - -in { inherit groups members; } +in +{ + inherit groups members; +} diff --git a/meta/network.nix b/meta/network.nix index 9679b59..68b9c92 100644 --- a/meta/network.nix +++ b/meta/network.nix @@ -1,27 +1,47 @@ let - mkDefaultInterface = _: attrs: { ipv4 = [ ]; ipv6 = [ ]; gateways = [ ]; } // attrs; + mkDefaultInterface = + _: attrs: + { + ipv4 = [ ]; + ipv6 = [ ]; + gateways = [ ]; + } + // attrs; - mkBase = config: config // { interfaces = builtins.mapAttrs mkDefaultInterface (config.interfaces or { }); }; + mkBase = + config: config // { interfaces = builtins.mapAttrs mkDefaultInterface (config.interfaces or { }); }; getAddresses = version: interface: builtins.map (builtins.getAttr "address") interface.${version}; filterIPv4 = ip: builtins.substring 0 7 ip != "192.168"; filterIPv6 = _: true; - mkNet = _: value: - let base = mkBase value; in - base // { + mkNet = + _: value: + let + base = mkBase value; + in + base + // { addresses = let - _addresses = builtins.foldl' - ({ ipv4, ipv6 }: net: { - ipv4 = ipv4 ++ getAddresses "ipv4" net; - ipv6 = ipv6 ++ getAddresses "ipv6" net; - }) - { ipv4 = [ ]; ipv6 = [ ]; } - (builtins.attrValues base.interfaces); + _addresses = + builtins.foldl' + ( + { ipv4, ipv6 }: + net: { + ipv4 = ipv4 ++ getAddresses "ipv4" net; + ipv6 = ipv6 ++ getAddresses "ipv6" net; + } + ) + { + ipv4 = [ ]; + ipv6 = [ ]; + } + (builtins.attrValues base.interfaces); in - _addresses // rec { + _addresses + // rec { publicV4 = builtins.filter filterIPv4 _addresses.ipv4; publicV6 = builtins.filter filterIPv6 _addresses.ipv6; public = publicV4 ++ publicV6; @@ -34,8 +54,14 @@ builtins.mapAttrs mkNet { interfaces = { eno1 = { ipv4 = [ - { address = "129.199.146.147"; prefixLength = 24; } - { address = "192.168.1.147"; prefixLength = 24; } + { + address = "129.199.146.147"; + prefixLength = 24; + } + { + address = "192.168.1.147"; + prefixLength = 24; + } ]; gateways = [ "129.199.146.254" ]; @@ -49,8 +75,14 @@ builtins.mapAttrs mkNet { interfaces = { eno1 = { ipv4 = [ - { address = "129.199.146.148"; prefixLength = 24; } - { address = "192.168.1.148"; prefixLength = 24; } + { + address = "129.199.146.148"; + prefixLength = 24; + } + { + address = "192.168.1.148"; + prefixLength = 24; + } ]; gateways = [ "129.199.146.254" ]; @@ -64,7 +96,10 @@ builtins.mapAttrs mkNet { interfaces = { enp130s0f0 = { ipv4 = [ - { address = "129.199.210.85"; prefixLength = 24; } + { + address = "129.199.210.85"; + prefixLength = 24; + } ]; gateways = [ "129.199.210.254" ]; @@ -77,7 +112,12 @@ builtins.mapAttrs mkNet { web01 = { interfaces = { ens3 = { - ipv4 = [{ address = "129.199.129.53"; prefixLength = 24; }]; + ipv4 = [ + { + address = "129.199.129.53"; + prefixLength = 24; + } + ]; gateways = [ "129.199.129.1" ]; }; @@ -89,7 +129,12 @@ builtins.mapAttrs mkNet { web02 = { interfaces = { ens3 = { - ipv4 = [{ address = "129.199.129.235"; prefixLength = 24; }]; + ipv4 = [ + { + address = "129.199.129.235"; + prefixLength = 24; + } + ]; gateways = [ "129.199.129.1" ]; }; diff --git a/meta/nodes.nix b/meta/nodes.nix index 116b022..94ac890 100644 --- a/meta/nodes.nix +++ b/meta/nodes.nix @@ -11,14 +11,17 @@ # } let - mkNode = _: attrs: { - adminGroups = [ ]; - admins = [ ]; + mkNode = + _: attrs: + { + adminGroups = [ ]; + admins = [ ]; - deployment = { }; + deployment = { }; - nixpkgs = "23.11"; - } // attrs; + nixpkgs = "23.11"; + } + // attrs; in builtins.mapAttrs mkNode { diff --git a/modules/default.nix b/modules/default.nix index 41a0cbb..cb364e1 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -35,22 +35,25 @@ { lib, sources, ... }: { - imports = (lib.extra.mkImports ./. [ - "dgn-access-control" - "dgn-acme" - "dgn-console" - "dgn-fail2ban" - "dgn-hardware" - "dgn-network" - "dgn-ssh" - "dgn-web" - "dgn-vm-variant" - ]) ++ [ - "${sources.agenix}/modules/age.nix" - "${sources.attic}/nixos/atticd.nix" - ] ++ ((import sources.nix-modules { inherit lib; }).importModules [ - "age-secrets" - "services/crabfit" - "services/forgejo-nix-runners" - ]); + imports = + (lib.extra.mkImports ./. [ + "dgn-access-control" + "dgn-acme" + "dgn-console" + "dgn-fail2ban" + "dgn-hardware" + "dgn-network" + "dgn-ssh" + "dgn-web" + "dgn-vm-variant" + ]) + ++ [ + "${sources.agenix}/modules/age.nix" + "${sources.attic}/nixos/atticd.nix" + ] + ++ ((import sources.nix-modules { inherit lib; }).importModules [ + "age-secrets" + "services/crabfit" + "services/forgejo-nix-runners" + ]); } diff --git a/modules/dgn-access-control.nix b/modules/dgn-access-control.nix index 58394a9..b8f15f5 100644 --- a/modules/dgn-access-control.nix +++ b/modules/dgn-access-control.nix @@ -31,7 +31,13 @@ # pris connaissance de la licence CeCILL, et que vous en avez accepté les # termes. -{ config, lib, meta, name, ... }: +{ + config, + lib, + meta, + name, + ... +}: let inherit (lib) @@ -40,10 +46,13 @@ let mkIf mkOption - types; + types + ; nodeMeta = meta.nodes.${name}; - admins = meta.members.groups.root ++ nodeMeta.admins + admins = + meta.members.groups.root + ++ nodeMeta.admins ++ (builtins.concatMap (g: meta.members.groups.${g}) nodeMeta.adminGroups); cfg = config.dgn-access-control; @@ -51,7 +60,9 @@ in { options.dgn-access-control = { - enable = mkEnableOption "DGNum access control." // { default = true; }; + enable = mkEnableOption "DGNum access control." // { + default = true; + }; users = mkOption { type = with types; attrsOf (listOf str); @@ -72,8 +83,8 @@ in # Admins have root access to the node dgn-access-control.users.root = mkDefault admins; - users.users = builtins.mapAttrs - (u: members: { openssh.authorizedKeys.keys = lib.extra.getAllKeys members; }) - cfg.users; + users.users = + builtins.mapAttrs (_: members: { openssh.authorizedKeys.keys = lib.extra.getAllKeys members; }) + cfg.users; }; } diff --git a/modules/dgn-acme.nix b/modules/dgn-acme.nix index d9f4548..c629e1d 100644 --- a/modules/dgn-acme.nix +++ b/modules/dgn-acme.nix @@ -34,15 +34,15 @@ { config, lib, ... }: let - inherit (lib) - mkEnableOption - mkIf; + inherit (lib) mkEnableOption mkIf; cfg = config.dgn-acme; in { - options.dgn-acme.enable = mkEnableOption "ACME settings." // { default = true; }; + options.dgn-acme.enable = mkEnableOption "ACME settings." // { + default = true; + }; config = mkIf cfg.enable { security.acme = { diff --git a/modules/dgn-console.nix b/modules/dgn-console.nix index 38bab7d..fa07ac2 100644 --- a/modules/dgn-console.nix +++ b/modules/dgn-console.nix @@ -1,13 +1,20 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) mkEnableOption mkOption mkIf; cfg = config.dgn-console; - -in { +in +{ options.dgn-console = { - enable = mkEnableOption "DGNum console setup." // { default = true; }; + enable = mkEnableOption "DGNum console setup." // { + default = true; + }; pg-upgrade-to = mkOption { type = lib.types.package; @@ -18,7 +25,9 @@ in { config = mkIf cfg.enable { time.timeZone = "Europe/Paris"; - console = { keyMap = "fr"; }; + console = { + keyMap = "fr"; + }; environment.variables.EDITOR = "nvim"; @@ -26,7 +35,7 @@ in { # services.nscd.enableNsncd = false; nixpkgs.overlays = [ - (final: prev: { + (_: _: { nsncd = pkgs.rustPlatform.buildRustPackage { pname = "nsncd"; version = "unstable-2023-10-26"; @@ -70,29 +79,36 @@ in { hardware.enableRedistributableFirmware = true; - environment.systemPackages = (with pkgs; [ neovim wget kitty.terminfo ]) - ++ lib.optional (config.services.postgresql.enable - && config.services.postgresql.package != cfg.pg-upgrade-to) - (pkgs.writeScriptBin "upgrade-pg-cluster" '' - set -eux - # XXX it's perhaps advisable to stop all services that depend on postgresql - systemctl stop postgresql + environment.systemPackages = + (with pkgs; [ + neovim + wget + kitty.terminfo + ]) + ++ lib.optional + (config.services.postgresql.enable && config.services.postgresql.package != cfg.pg-upgrade-to) + ( + pkgs.writeScriptBin "upgrade-pg-cluster" '' + set -eux + # XXX it's perhaps advisable to stop all services that depend on postgresql + systemctl stop postgresql - export NEWDATA="/var/lib/postgresql/${cfg.pg-upgrade-to.psqlSchema}" + export NEWDATA="/var/lib/postgresql/${cfg.pg-upgrade-to.psqlSchema}" - export NEWBIN="${cfg.pg-upgrade-to}/bin" + export NEWBIN="${cfg.pg-upgrade-to}/bin" - export OLDDATA="${config.services.postgresql.dataDir}" - export OLDBIN="${config.services.postgresql.package}/bin" + export OLDDATA="${config.services.postgresql.dataDir}" + export OLDBIN="${config.services.postgresql.package}/bin" - install -d -m 0700 -o postgres -g postgres "$NEWDATA" - cd "$NEWDATA" - sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" + install -d -m 0700 -o postgres -g postgres "$NEWDATA" + cd "$NEWDATA" + sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" - sudo -u postgres $NEWBIN/pg_upgrade \ - --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ - --old-bindir $OLDBIN --new-bindir $NEWBIN \ - "$@" - ''); + sudo -u postgres $NEWBIN/pg_upgrade \ + --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ + --old-bindir $OLDBIN --new-bindir $NEWBIN \ + "$@" + '' + ); }; } diff --git a/modules/dgn-fail2ban/default.nix b/modules/dgn-fail2ban/default.nix index f0fb01c..b2f3fe6 100644 --- a/modules/dgn-fail2ban/default.nix +++ b/modules/dgn-fail2ban/default.nix @@ -1,10 +1,19 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) - mkDefault mkEnableOption mkIf mkOption + mkDefault + mkEnableOption + mkIf + mkOption - types; + types + ; cfg = config.dgn-fail2ban; @@ -22,8 +31,7 @@ let }; filter = mkOption { - type = - types.nullOr (types.submodule { freeformType = configFormat.type; }); + type = types.nullOr (types.submodule { freeformType = configFormat.type; }); description = "Content of the filter used for this jail."; }; @@ -36,8 +44,8 @@ let }; }; }; - -in { +in +{ options.dgn-fail2ban = { enable = mkEnableOption "fail2ban service."; @@ -50,9 +58,9 @@ in { }; config = mkIf cfg.enable { - dgn-fail2ban.jails = - builtins.mapAttrs (_: j: j // { enabled = mkDefault false; }) - (import ./jails.nix { }); + dgn-fail2ban.jails = builtins.mapAttrs (_: j: j // { enabled = mkDefault false; }) ( + import ./jails.nix { } + ); services.fail2ban = { enable = true; diff --git a/modules/dgn-fail2ban/jails.nix b/modules/dgn-fail2ban/jails.nix index 8562f6c..49a5d4b 100644 --- a/modules/dgn-fail2ban/jails.nix +++ b/modules/dgn-fail2ban/jails.nix @@ -33,8 +33,7 @@ _: { nginx-spam = { - filter.Definition.failregex = '' - ^.*GET.*(matrix/server|\.php|admin|wp\-).* HTTP/\d.\d\" 404.*$''; + filter.Definition.failregex = ''^.*GET.*(matrix/server|\.php|admin|wp\-).* HTTP/\d.\d\" 404.*$''; settings = { logpath = "/var/log/nginx/access.log"; diff --git a/modules/dgn-hardware.nix b/modules/dgn-hardware.nix index bac774d..4110489 100644 --- a/modules/dgn-hardware.nix +++ b/modules/dgn-hardware.nix @@ -1,11 +1,16 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let inherit (lib) mkEnableOption mkIf mkMerge; cfg = config.dgn-hardware; - -in { +in +{ options.dgn-hardware = { enable = mkEnableOption "default hardware configuration." // { default = true; @@ -19,45 +24,56 @@ in { useBcachefs = mkEnableOption "bcachefs configuration"; }; - config = mkIf cfg.enable (mkMerge [ - { - hardware.enableRedistributableFirmware = true; - hardware.cpu.intel.updateMicrocode = true; + config = mkIf cfg.enable ( + mkMerge [ + { + hardware.enableRedistributableFirmware = true; + hardware.cpu.intel.updateMicrocode = true; - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - boot = { - initrd.availableKernelModules = - [ "ata_piix" "uhci_hcd" "ehci_pci" "virtio_pci" "ahci" "virtio_blk" ]; - kernelModules = [ "kvm-intel" ]; - kernelParams = [ - "cgroup_enable=cpu" - "cgroup_enable=cpuset" - "cgroup_enable=memory" - "cgroup_memory=1" - ]; - }; - } - - (mkIf cfg.useSystemd { - boot.loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - }) - - (mkIf cfg.useBcachefs { boot.supportedFilesystems = [ "bcachefs" ]; }) - - (mkIf cfg.useZfs { - boot = { - supportedFilesystems = [ "zfs" ]; - - zfs = { - forceImportRoot = false; - extraPools = [ "fast01" "work01" ]; - package = pkgs.zfs_2_1; + boot = { + initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "ehci_pci" + "virtio_pci" + "ahci" + "virtio_blk" + ]; + kernelModules = [ "kvm-intel" ]; + kernelParams = [ + "cgroup_enable=cpu" + "cgroup_enable=cpuset" + "cgroup_enable=memory" + "cgroup_memory=1" + ]; }; - }; - }) - ]); + } + + (mkIf cfg.useSystemd { + boot.loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }) + + (mkIf cfg.useBcachefs { boot.supportedFilesystems = [ "bcachefs" ]; }) + + (mkIf cfg.useZfs { + boot = { + supportedFilesystems = [ "zfs" ]; + + zfs = { + forceImportRoot = false; + extraPools = [ + "fast01" + "work01" + ]; + package = pkgs.zfs_2_1; + }; + }; + }) + ] + ); } diff --git a/modules/dgn-network.nix b/modules/dgn-network.nix index e03e7ba..11ce62a 100644 --- a/modules/dgn-network.nix +++ b/modules/dgn-network.nix @@ -1,12 +1,22 @@ -{ config, lib, meta, name, ... }: +{ + config, + lib, + meta, + name, + ... +}: let - inherit (lib) mapAttrs' mkEnableOption mkIf optionalAttrs; + inherit (lib) + mapAttrs' + mkEnableOption + mkIf + optionalAttrs + ; net = meta.network.${name}; - mkAddress = { address, prefixLength, ... }: - "${address}/${builtins.toString prefixLength}"; + mkAddress = { address, prefixLength, ... }: "${address}/${builtins.toString prefixLength}"; mkRoute = gateway: { routeConfig = { Gateway = gateway; @@ -38,12 +48,11 @@ let }; cfg = config.dgn-network; - -in { - options.dgn-network.enable = - mkEnableOption "automatic network configuration based on metadata" // { - default = true; - }; +in +{ + options.dgn-network.enable = mkEnableOption "automatic network configuration based on metadata" // { + default = true; + }; config = mkIf cfg.enable { networking = { diff --git a/modules/dgn-vm-variant.nix b/modules/dgn-vm-variant.nix index 23db171..4636f40 100644 --- a/modules/dgn-vm-variant.nix +++ b/modules/dgn-vm-variant.nix @@ -1,14 +1,14 @@ { config, lib, ... }: let - inherit (lib) - mkEnableOption - mkIf; + inherit (lib) mkEnableOption mkIf; cfg = config.dgn-vmVariant; in { - options.dgn-vmVariant.enable = mkEnableOption "ACME settings." // { default = true; }; + options.dgn-vmVariant.enable = mkEnableOption "ACME settings." // { + default = true; + }; config = mkIf cfg.enable { virtualisation.vmVariant = { @@ -16,4 +16,3 @@ in }; }; } - diff --git a/modules/dgn-web.nix b/modules/dgn-web.nix index bb68203..c3278eb 100644 --- a/modules/dgn-web.nix +++ b/modules/dgn-web.nix @@ -4,7 +4,8 @@ let inherit (lib) mkEnableOption mkIf; cfg = config.dgn-web; -in { +in +{ options.dgn-web = { enable = mkEnableOption "sane defaults for web services."; }; @@ -21,6 +22,9 @@ in { recommendedZstdSettings = true; }; - networking.firewall.allowedTCPPorts = [ 80 443 ]; + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; }; } diff --git a/npins/default.nix b/npins/default.nix index 4a7c372..43cead3 100644 --- a/npins/default.nix +++ b/npins/default.nix @@ -1,20 +1,34 @@ # Generated by npins. Do not modify; will be overwritten regularly let data = builtins.fromJSON (builtins.readFile ./sources.json); - version = data.version; + inherit (data) version; - mkSource = spec: - assert spec ? type; let + mkSource = + spec: + assert spec ? type; + let path = - if spec.type == "Git" then mkGitSource spec - else if spec.type == "GitRelease" then mkGitSource spec - else if spec.type == "PyPi" then mkPyPiSource spec - else if spec.type == "Channel" then mkChannelSource spec - else builtins.throw "Unknown source type ${spec.type}"; + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; in spec // { outPath = path; }; - mkGitSource = { repository, revision, url ? null, hash, ... }: + mkGitSource = + { + repository, + revision, + url ? null, + hash, + ... + }: assert repository ? type; # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository # In the latter case, there we will always be an url to the tarball @@ -23,19 +37,23 @@ let inherit url; sha256 = hash; # FIXME: check nix version & use SRI hashes }) - else assert repository.type == "Git"; builtins.fetchGit { - url = repository.url; - rev = revision; - # hash = hash; - }; + else + assert repository.type == "Git"; + builtins.fetchGit { + inherit (repository) url; + rev = revision; + # hash = hash; + }; - mkPyPiSource = { url, hash, ... }: + mkPyPiSource = + { url, hash, ... }: builtins.fetchurl { inherit url; sha256 = hash; }; - mkChannelSource = { url, hash, ... }: + mkChannelSource = + { url, hash, ... }: builtins.fetchTarball { inherit url; sha256 = hash; diff --git a/npins/sources.json b/npins/sources.json index 2fe25e7..823126c 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -118,6 +118,18 @@ "url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.05pre578430.5ad9903c1612/nixexprs.tar.xz", "hash": "1zg01pxmaf56gqxdf59mj1aanlvkpw5b3gmsx4mawxi6m1f2l6c6" }, + "pre-commit-hooks": { + "type": "Git", + "repository": { + "type": "GitHub", + "owner": "cachix", + "repo": "pre-commit-hooks.nix" + }, + "branch": "master", + "revision": "7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf", + "url": "https://github.com/cachix/pre-commit-hooks.nix/archive/7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf.tar.gz", + "hash": "0gj03fzsqcybzr4shj7x62l0xc34w20zhphd2jg7sd2rxaw42x23" + }, "wp4nix": { "type": "Git", "repository": { @@ -132,4 +144,4 @@ } }, "version": 3 -} \ No newline at end of file +} diff --git a/scripts/default.nix b/scripts/default.nix index 25dda9d..8b39a1c 100644 --- a/scripts/default.nix +++ b/scripts/default.nix @@ -8,19 +8,25 @@ let coreutils nvd git - jq; + jq + ; }; - mkShellScript = name: (pkgs.substituteAll ({ - inherit name; - src = ./. + "/${name}.sh"; - dir = "/bin/"; - isExecutable = true; + mkShellScript = + name: + (pkgs.substituteAll ( + { + inherit name; + src = ./. + "/${name}.sh"; + dir = "/bin/"; + isExecutable = true; - checkPhase = '' - ${pkgs.stdenv.shellDryRun} "$target" - ''; - } // substitutions)); + checkPhase = '' + ${pkgs.stdenv.shellDryRun} "$target" + ''; + } + // substitutions + )); scripts = [ "check-deployment" diff --git a/shell.nix b/shell.nix index 7f48806..2d126bb 100644 --- a/shell.nix +++ b/shell.nix @@ -1,52 +1 @@ -/* - Copyright : - - Maurice Debray 2023 - - Tom Hubrecht 2023 - - Ce logiciel est un programme informatique servant à déployer des - configurations de serveurs via NixOS. - - Ce logiciel est régi par la licence CeCILL soumise au droit français et - respectant les principes de diffusion des logiciels libres. Vous pouvez - utiliser, modifier et/ou redistribuer ce programme sous les conditions - de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA - sur le site "http://www.cecill.info". - - En contrepartie de l'accessibilité au code source et des droits de copie, - de modification et de redistribution accordés par cette licence, il n'est - offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, - seule une responsabilité restreinte pèse sur l'auteur du programme, le - titulaire des droits patrimoniaux et les concédants successifs. - - A cet égard l'attention de l'utilisateur est attirée sur les risques - associés au chargement, à l'utilisation, à la modification et/ou au - développement et à la reproduction du logiciel par l'utilisateur étant - donné sa spécificité de logiciel libre, qui peut le rendre complexe à - manipuler et qui le réserve donc à des développeurs et des professionnels - avertis possédant des connaissances informatiques approfondies. Les - utilisateurs sont donc invités à charger et tester l'adéquation du - logiciel à leurs besoins dans des conditions permettant d'assurer la - sécurité de leurs systèmes et ou de leurs données et, plus généralement, - à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. - - Le fait que vous puissiez accéder à cet en-tête signifie que vous avez - pris connaissance de la licence CeCILL, et que vous en avez accepté les - termes. -*/ - -let - sources = import ./npins; - pkgs = import sources.nixpkgs { }; -in - -pkgs.mkShell { - packages = (with pkgs; [ - npins - colmena - nixos-generators - ] ++ (builtins.map (p: callPackage p { }) [ - (sources.disko + "/package.nix") - ])) ++ (import ./scripts { inherit pkgs; }); - - preferLocalBuild = true; -} +(import ./.).shells.default