fix(ds-fr): Update module
All checks were successful
Build all the nodes / ap01 (push) Successful in 1m18s
Build all the nodes / bridge01 (push) Successful in 1m58s
Build all the nodes / geo01 (push) Successful in 2m2s
Build all the nodes / geo02 (push) Successful in 2m9s
Build all the nodes / hypervisor01 (push) Successful in 1m29s
Build all the nodes / netcore02 (push) Successful in 37s
Build all the nodes / hypervisor03 (push) Successful in 1m36s
Build all the nodes / hypervisor02 (push) Successful in 1m41s
Build all the nodes / storage01 (push) Successful in 2m8s
Build all the nodes / rescue01 (push) Successful in 2m10s
Build all the nodes / vault01 (push) Successful in 2m7s
Build all the nodes / web01 (push) Successful in 2m28s
Run pre-commit on all files / pre-commit (push) Successful in 42s
Build all the nodes / web02 (push) Successful in 1m44s
Build all the nodes / web03 (push) Successful in 1m46s
Build all the nodes / compute01 (push) Successful in 9m44s

This commit is contained in:
Tom Hubrecht 2024-12-17 22:17:12 +01:00
parent 324c37f884
commit f8df18f13c
Signed by: thubrecht
SSH key fingerprint: SHA256:r+nK/SIcWlJ0zFZJGHtlAoRwq1Rm+WcKAm5ADYMoQPc
3 changed files with 279 additions and 214 deletions

View file

@ -11,41 +11,47 @@
let let
host = "demarches.dgnum.eu"; host = "demarches.dgnum.eu";
port = 3000;
dgn-id = "1fbe81d211b18dae7b9c1727362997c62636f24a"; dgn-id = "8dfdc60d1aa66e7206461ed7a49199f624a66b4e";
patch = pkgs.fetchurl {
url = "https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${dgn-id}.patch";
hash = "sha256-6JdbUf2fc79E5F1wtYFnP1JLGJffhGbjaxysRFr8xN4=";
};
in in
{ {
imports = [ ./module.nix ]; imports = [ ./module.nix ];
dgn-web.internalPorts.ds-fr = 3000; dgn-web.internalPorts.ds-fr = port;
services.demarches-simplifiees = { services.demarches-simplifiees = {
enable = true; enable = true;
package = package = (import sources.nix-pkgs { inherit pkgs; }).demarches-simplifiees.overrideAttrs (old: {
((import sources.nix-pkgs { inherit pkgs; }).demarches-simplifiees.override { dsModules = old.dsModules.overrideAttrs {
initialDeploymentDate = "20230923"; prePatch = ''
}).overrideAttrs ${pkgs.lib.getExe pkgs.git} apply -p1 < ${patch}
(old: { '';
dsModules = old.dsModules.overrideAttrs { };
prePatch = ''
${pkgs.lib.getExe pkgs.git} apply -p1 < ${
pkgs.fetchurl {
url = "https://git.dgnum.eu/DGNum/demarches-normaliennes/commit/${dgn-id}.patch";
hash = "sha256-aCq/WkV4+PUSIzXgznwm2sAcaz12Y1zmUbh7QoXoMsM=";
}
}
'';
};
});
secretFile = config.age.secrets."ds-fr-secret_file".path; prePatch = ''
${pkgs.lib.getExe pkgs.git} apply -p1 < ${patch}
'';
postPatch = ''
rm -f lib/tasks/deployment/20240830192553_backfill_hide_instructeurs_email.rake
rm -f lib/tasks/deployment/20240912151317_clean_virtual_column_from_procedure_presentation.rake
rm -f lib/tasks/deployment/20240920130741_migrate_procedure_presentation_to_columns.rake
'';
});
inherit host port;
environmentFile = config.age.secrets."ds-fr-secret_file".path;
initialDeploymentDate = "20230923"; initialDeploymentDate = "20230923";
settings = { environment = {
APP_HOST = host;
# Disable France Connect and Agent Connect # Disable France Connect and Agent Connect
FRANCE_CONNECT_ENABLED = "disabled"; FRANCE_CONNECT_ENABLED = "disabled";
AGENT_CONNECT_ENABLED = "disabled"; AGENT_CONNECT_ENABLED = "disabled";
@ -87,18 +93,10 @@ in
RUBY_YJIT_ENABLE = "1"; RUBY_YJIT_ENABLE = "1";
STRICT_EMAIL_VALIDATION_STARTS_ON = "2024-02-23"; STRICT_EMAIL_VALIDATION_STARTS_ON = "2024-12-18";
WEASYPRINT_URL = "http://127.0.0.1:5000/pdf";
# Customization
# HEADER_LOGO_SRC = "logo_ens_psl_couleur.png";
# HEADER_LOGO_ALT = "Par la Recherche, pour la Recherche";
# PROCEDURE_DEFAULT_LOGO_SRC = "logo_ens_psl_couleur.png";
}; };
}; };
age-secrets.autoMatch = [ "ds-fr" ]; dgn-backups.jobs.ds-fr.settings.paths = [ "/var/lib/demarches-simplifiees" ];
dgn-backups.jobs.ds-fr.settings.paths = [ "/var/lib/ds-fr" ];
dgn-backups.postgresDatabases = [ "ds-fr" ]; dgn-backups.postgresDatabases = [ "ds-fr" ];
} }

View file

@ -1,5 +1,4 @@
# Copyright Tom Hubrecht, (2023) # SPDX-FileCopyrightText: 2023-2024 Tom Hubrecht <tom.hubrecht@dgnum.eu>
# SPDX-FileCopyrightText: 2024 Tom Hubrecht <tom.hubrecht@dgnum.eu>
# #
# SPDX-License-Identifier: EUPL-1.2 # SPDX-License-Identifier: EUPL-1.2
@ -7,192 +6,290 @@
config, config,
lib, lib,
pkgs, pkgs,
utils,
... ...
}: }:
let let
inherit (lib) inherit (lib)
getExe
getExe'
mapAttrs
mkDefault mkDefault
mkEnableOption mkEnableOption
mkIf mkIf
mkOption mkOption
mkPackageOption
optional optional
optionalString
types
; ;
inherit (lib.types)
attrsOf
nullOr
oneOf
package
path
port
str
;
inherit (utils) escapeSystemdExecArgs;
cfg = config.services.demarches-simplifiees; cfg = config.services.demarches-simplifiees;
settingsFormat = pkgs.formats.keyValue { }; weasyprintEnv = pkgs.python3.withPackages (ps: [
ps.flask
env = settingsFormat.generate "ds-fr-env" cfg.settings; ps.sentry-sdk
ps.weasyprint
ds-fr = pkgs.writeShellScriptBin "ds-fr" '' ]);
set -a
cd ${cfg.package}
${optionalString (cfg.secretFile != null) "source ${cfg.secretFile}"}
source ${env}
BIN="$1"
shift
SUDO="exec"
if [[ $USER != ${cfg.user} ]]; then
SUDO='exec /run/wrappers/bin/sudo -u ${cfg.user} --preserve-env'
fi
$SUDO ${cfg.package}/bin/$BIN "$@"
'';
in in
{ {
options.services.demarches-simplifiees = { options.services.demarches-simplifiees = {
enable = mkEnableOption "demarches-simplifiees."; enable = mkEnableOption "Démarches Simplifiées";
package = mkOption { package = mkPackageOption pkgs "demarches-simplifiees" { };
type = types.package;
default = pkgs.callPackage ./package { inherit (cfg) initialDeploymentDate dataDir logDir; }; finalPackage = mkOption {
type = package;
default = cfg.package.override { inherit (cfg) initialDeploymentDate; };
}; };
user = mkOption { host = mkOption {
type = types.str; type = str;
default = "ds-fr"; description = ''
description = "User account under which DS runs."; Hostname of the web server.
'';
}; };
group = mkOption { port = mkOption {
type = types.str; type = port;
default = "ds-fr"; default = 3000;
description = "Group account under which DS runs."; description = ''
Listening port for the web server.
'';
}; };
dataDir = mkOption { weasyprintPort = mkOption {
type = types.str; type = port;
default = "/var/lib/ds-fr"; default = 5000;
description = ''
Port of the weasyprint server.
'';
}; };
logDir = mkOption { environment = mkOption {
type = types.str; type = attrsOf (
default = "/var/log/ds-fr"; nullOr (oneOf [
package
path
str
])
);
description = ''
Evironment variables available to Démarches Simplifiées.
'';
}; };
secretFile = mkOption { environmentFile = mkOption {
type = types.nullOr types.path; type = nullOr path;
default = null; default = null;
description = ''
Path to a file containing environment variables.
Required secrets are `SECRET_KEY_BASE` and `OTP_SECRET_KEY`,
which can be generated using `rails secret`.
'';
}; };
settings = mkOption { inherit (settingsFormat) type; };
initialDeploymentDate = mkOption { initialDeploymentDate = mkOption {
type = types.nullOr types.str; type = nullOr str;
default = null; default = null;
description = ''
Initial deployment date, used to ignore some migrations,
which are known to be buggy and are supposed to change old production data.
'';
};
interactScript = mkOption {
type = package;
default = pkgs.writeShellApplication {
name = "ds-fr";
runtimeInputs = [
cfg.finalPackage
config.systemd.package
pkgs.util-linux
];
text = ''
MainPID=$(systemctl show -p MainPID --value demarches-simplifiees.service)
nsenter -e -a -w -t "$MainPID" -G follow -S follow "$@"
'';
};
description = ''
Script to run ds-fr tasks.
'';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ ds-fr ]; environment.systemPackages = [ cfg.interactScript ];
systemd.tmpfiles.rules = [
"f '${cfg.logDir}/production.log' 0640 ${cfg.user} ${cfg.group} - -"
"f '${cfg.dataDir}/.env' 0600 ${cfg.user} ${cfg.group} - -"
"d '${cfg.dataDir}/tmp' 0700 ${cfg.user} ${cfg.group} 10d -"
"d '${cfg.dataDir}/storage' 0700 ${cfg.user} ${cfg.group} - -"
];
systemd.services = {
ds-fr-setup = {
description = "Demarches Simplifiees setup";
wantedBy = [ "multi-user.target" ];
path = [
pkgs.bash
ds-fr
];
after = [ "postgresql.service" ];
systemd.services =
let
serviceConfig = { serviceConfig = {
Type = "oneshot"; User = "ds-fr";
User = cfg.user; DynamicUser = true;
Group = cfg.group; EnvironmentFile = optional (cfg.environmentFile != null) cfg.environmentFile;
EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile); CacheDirectory = "demarches-simplifiees";
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; LogsDirectory = "demarches-simplifiees";
LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr"; RuntimeDirectory = "demarches-simplifiees";
StateDirectory = "demarches-simplifiees";
WorkingDirectory = cfg.finalPackage;
};
in
{
demarches-simplifiees = {
description = "Démarches Simplifiées";
inherit (cfg) environment;
path = [
cfg.finalPackage
pkgs.imagemagick
];
after = [
"network.target"
"postgresql.target"
];
wantedBy = [ "multi-user.target" ];
preStart = ''
mkdir -p "$STATE_DIRECTORY/storage"
if [[ ! -f "$STATE_DIRECTORY/.version" ]]; then
# Run initial setup
rails db:environment:set
rails db:schema:load
rails db:seed
rails jobs:schedule
touch "$STATE_DIRECTORY/.version"
fi
if [[ $(cat "$STATE_DIRECTORY/.version") != "$__DS_VERSION" ]]; then
# Run migrations on version change
rake db:migrate
rake after_party:run
echo "$__DS_VERSION" > "$STATE_DIRECTORY/.version"
fi
'';
serviceConfig = serviceConfig // {
ExecStart = escapeSystemdExecArgs [
(getExe' cfg.finalPackage "rails")
"server"
"-b"
"127.0.0.1"
"-p"
cfg.port
];
};
}; };
script = '' demarches-simplifiees-work = {
[[ ! -f ${cfg.dataDir}/.initial-migration ]] \ description = "Démarches Simplifiées work service";
&& ds-fr rails db:environment:set \
&& ds-fr rails db:schema:load \
&& ds-fr rails db:seed \
&& touch ${cfg.dataDir}/.initial-migration
ds-fr rake db:migrate inherit (cfg) environment;
ds-fr rake after_party:run
'';
};
ds-fr-work = { after = [ "demarches-simplifiees.service" ];
description = "Demarches Simplifiees work service"; wantedBy = [ "multi-user.target" ];
bindsTo = [ "demarches-simplifiees.service" ];
partOf = [ "demarches-simplifiees.service" ];
wantedBy = [ serviceConfig = serviceConfig // {
"multi-user.target" ExecStart = escapeSystemdExecArgs [
"ds-fr.service" (getExe' cfg.finalPackage "rails")
]; "jobs:work"
after = [ ];
"network.target" };
"ds-fr-setup.service" };
];
requires = [ "ds-fr-setup.service" ];
serviceConfig = { weasyprint-server = {
ExecStart = "${ds-fr}/bin/ds-fr rails jobs:work"; description = "Weasyprint server";
EnvironmentFile = [ env ] ++ (optional (cfg.secretFile != null) cfg.secretFile);
User = cfg.user; wantedBy = [ "multi-user.target" ];
Group = cfg.group;
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr"; environment = {
LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr"; BASE_URL = "https://${cfg.host}";
LOG_DIR = "/var/log/weasyprint";
UWSGI_PYTHONPATH = weasyprintEnv;
UWSGI_MODULE = "wgsi:app";
};
serviceConfig = {
DynamicUser = true;
Type = "notify";
WorkingDirectory = cfg.finalPackage.weasyprint_server;
LogsDirectory = "weasyprint";
ExecStart = escapeSystemdExecArgs [
(getExe (pkgs.uwsgi.override { plugins = [ "python3" ]; }))
"--http-socket"
"127.0.0.1:${builtins.toString cfg.weasyprintPort}"
"--processes=4"
"--enable-threads"
];
NotifyAccess = "all";
KillSignal = "SIGQUIT";
ExecReload = "${getExe' pkgs.coreutils "kill"} -HUP $MainPID";
ExecStop = "${getExe' pkgs.coreutils "kill"} -INT $MainPID";
ProtectSystem = "full";
ProtectHome = true;
NoNewPrivileges = true;
PrivateDevices = true;
};
}; };
}; };
ds-fr = {
description = "Demarches Simplifiees web service";
wantedBy = [ "multi-user.target" ];
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);
User = cfg.user;
Group = cfg.group;
StateDirectory = mkIf (cfg.dataDir == "/var/lib/ds-fr") "ds-fr";
LogsDirectory = mkIf (cfg.logDir == "/var/log/ds-fr") "ds-fr";
};
};
};
services = { services = {
demarches-simplifiees.settings = demarches-simplifiees.environment =
(builtins.mapAttrs (_: mkDefault) { # Hardcoded values
RAILS_ENV = "production"; {
RAILS_ROOT = builtins.toString cfg.package;
# Application host name # Application host name
# #
# Examples: # Examples:
# * For local development: localhost:3000 # * For local development: localhost:3000
# * For preproduction: staging.ds.example.org # * For preproduction: staging.ds.example.org
# * For production: ds.example.org # * For production: ds.example.org
APP_HOST = "localhost:3000"; APP_HOST = cfg.host;
# Database credentials
DB_DATABASE = "ds-fr";
DB_USERNAME = "ds-fr";
DB_HOST = "/run/postgresql";
DB_PORT = "5432";
# The variables must be present even if empty...
DB_PASSWORD = "";
DB_POOL = "";
# Jobs configuration
RAILS_QUEUE_ADAPTER = "delayed_job";
# Log on stdout
RAILS_LOG_TO_STDOUT = "true";
# Package version
__DS_VERSION = cfg.finalPackage.version;
# Weasyprint endpoint generating attestations v2
# See https://github.com/demarches-simplifiees/weasyprint_server
WEASYPRINT_URL = "http://127.0.0.1:${builtins.toString cfg.weasyprintPort}/pdf";
}
// (mapAttrs (_: mkDefault) {
RAILS_ENV = "production";
RAILS_ROOT = builtins.toString cfg.finalPackage;
# Rails key for signing sensitive data # Rails key for signing sensitive data
# See https://guides.rubyonrails.org/security.html # See https://guides.rubyonrails.org/security.html
@ -227,18 +324,6 @@ in
# SAML # SAML
SAML_IDP_ENABLED = "disabled"; SAML_IDP_ENABLED = "disabled";
# 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: integration with HelpScout (optional) # External service: integration with HelpScout (optional)
HELPSCOUT_MAILBOX_ID = ""; HELPSCOUT_MAILBOX_ID = "";
HELPSCOUT_CLIENT_ID = ""; HELPSCOUT_CLIENT_ID = "";
@ -288,9 +373,6 @@ in
# https://api.gouv.fr/api/api-entreprise.html # https://api.gouv.fr/api/api-entreprise.html
API_ENTREPRISE_KEY = ""; API_ENTREPRISE_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 # Networks bypassing the email login token that verifies new devices, and rack-attack throttling
TRUSTED_NETWORKS = ""; TRUSTED_NETWORKS = "";
@ -299,7 +381,7 @@ in
# "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0"; # "sXaot-fKhBlkI8qaSirQyuZbrpv5sVFoOturQ0pFEh0";
# Enable or disable Lograge logs # Enable or disable Lograge logs
LOGRAGE_ENABLED = "disabled"; LOGRAGE_ENABLED = "enabled";
# Logs source for Lograge # Logs source for Lograge
# #
@ -336,57 +418,42 @@ in
# Siret number used for API Entreprise, by default we use SIRET from dinum # Siret number used for API Entreprise, by default we use SIRET from dinum
API_ENTREPRISE_DEFAULT_SIRET = "put_your_own_siret"; 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 # Date from which email validation requires a TLD in email adresses.
RAILS_LOG_TO_STDOUT = true; # This change had been introduced by : cc53946d221d6f64c365ad6c6c4c544802eb94b4
}; # Records (users, …) created before this date won't be affected. See #9978
# To set a date, we recommend using *the day after* you have deployed this commit,
# so existing records won't be invalid.
STRICT_EMAIL_VALIDATION_STARTS_ON = "2024-02-19";
});
postgresql = { postgresql = {
enable = true; enable = true;
ensureDatabases = [ "ds-fr" ]; ensureDatabases = [ "ds-fr" ];
ensureUsers = optional (cfg.user == "ds-fr") { ensureUsers = [
name = "ds-fr"; {
ensureDBOwnership = true; name = "ds-fr";
}; ensureDBOwnership = true;
}
];
extraPlugins = with config.services.postgresql.package.pkgs; [ postgis ]; extensions = [ config.services.postgresql.package.pkgs.postgis ];
}; };
nginx = { nginx = {
enable = true; enable = true;
virtualHosts.${cfg.settings.APP_HOST} = { virtualHosts.${cfg.host} = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
root = "${cfg.package}/public/"; root = "${cfg.finalPackage}/public/";
locations."/".tryFiles = "$uri @proxy"; locations."/".tryFiles = "$uri @proxy";
locations."@proxy" = { locations."@proxy".proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}";
proxyPass = "http://127.0.0.1:3000";
};
}; };
}; };
}; };
users.users = mkIf (cfg.user == "ds-fr") {
ds-fr = {
inherit (cfg) group;
isSystemUser = true;
home = cfg.package;
};
};
users.groups.${cfg.group} = { };
}; };
} }

View file

@ -262,9 +262,9 @@
"url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs" "url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs"
}, },
"branch": "main", "branch": "main",
"revision": "e8494b9d6110a97e2225b2fe43d29efa34cd9451", "revision": "476e657d9c285d91638b2a7c2bbbd9e6f9d0cfd4",
"url": null, "url": null,
"hash": "1r2g3jdr311cn8y0cxvawc6qyp58lbydscp5hxadya2vl810vpln" "hash": "1i1a46q2v465zfa8rcfk1xisb7ywd4as18q6n2842ncnm69fxqns"
}, },
"nix-reuse": { "nix-reuse": {
"type": "GitRelease", "type": "GitRelease",