diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/development/running-nixos-tests-interactively.xml | 10 | ||||
-rw-r--r-- | nixos/doc/manual/development/writing-nixos-tests.xml | 2 | ||||
-rw-r--r-- | nixos/modules/misc/ids.nix | 2 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/hardware/lirc.nix | 85 | ||||
-rw-r--r-- | nixos/modules/services/mail/exim.nix | 18 | ||||
-rw-r--r-- | nixos/modules/services/networking/epmd.nix | 56 | ||||
-rw-r--r-- | nixos/modules/services/networking/nullidentdmod.nix | 34 | ||||
-rw-r--r-- | nixos/modules/services/security/tor.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/codimd.nix | 958 | ||||
-rw-r--r-- | nixos/modules/services/x11/display-managers/default.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/x11/display-managers/lightdm.nix | 13 | ||||
-rw-r--r-- | nixos/release.nix | 1 | ||||
-rw-r--r-- | nixos/tests/codimd.nix | 56 | ||||
-rw-r--r-- | nixos/tests/installer.nix | 1 |
15 files changed, 1231 insertions, 13 deletions
diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixos/doc/manual/development/running-nixos-tests-interactively.xml index 862b364a6d79..b25d3dcb9116 100644 --- a/nixos/doc/manual/development/running-nixos-tests-interactively.xml +++ b/nixos/doc/manual/development/running-nixos-tests-interactively.xml @@ -19,6 +19,7 @@ starting VDE switch for network 1 > startAll > testScript > $machine->succeed("touch /tmp/foo") +> print($machine->succeed("pwd"), "\n") # Show stdout of command </screen> The function <command>testScript</command> executes the entire test script and drops you back into the test driver command line upon its completion. @@ -33,8 +34,11 @@ $ nix-build nixos/tests/login.nix -A driver $ ./result/bin/nixos-run-vms </screen> The script <command>nixos-run-vms</command> starts the virtual machines - defined by test. The root file system of the VMs is created on the fly and - kept across VM restarts in - <filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>. + defined by test. + </para> + + <para> + The machine state is kept across VM restarts in + <filename>/tmp/vm-state-</filename><varname>machinename</varname>. </para> </section> diff --git a/nixos/doc/manual/development/writing-nixos-tests.xml b/nixos/doc/manual/development/writing-nixos-tests.xml index 5935fbc049bd..983f8f9cbe3e 100644 --- a/nixos/doc/manual/development/writing-nixos-tests.xml +++ b/nixos/doc/manual/development/writing-nixos-tests.xml @@ -108,7 +108,7 @@ xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualis <programlisting> $machine->start; $machine->waitForUnit("default.target"); -$machine->succeed("uname") =~ /Linux/; +die unless $machine->succeed("uname") =~ /Linux/; </programlisting> The first line is actually unnecessary; machines are implicitly started when you first execute an action on them (such as <literal>waitForUnit</literal> diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index aafeb997c326..3d34fb973e74 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -329,6 +329,7 @@ # kvm = 302; # unused # render = 303; # unused zeronet = 304; + lirc = 305; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -618,6 +619,7 @@ kvm = 302; # default udev rules from systemd requires these render = 303; # default udev rules from systemd requires these zeronet = 304; + lirc = 305; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index f51a30aec2e9..b128568bdf51 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -272,6 +272,7 @@ ./services/hardware/interception-tools.nix ./services/hardware/irqbalance.nix ./services/hardware/lcd.nix + ./services/hardware/lirc.nix ./services/hardware/nvidia-optimus.nix ./services/hardware/pcscd.nix ./services/hardware/pommed.nix @@ -496,6 +497,7 @@ ./services/networking/dnsdist.nix ./services/networking/dnsmasq.nix ./services/networking/ejabberd.nix + ./services/networking/epmd.nix ./services/networking/fakeroute.nix ./services/networking/ferm.nix ./services/networking/firefox/sync-server.nix @@ -556,6 +558,7 @@ ./services/networking/nsd.nix ./services/networking/ntopng.nix ./services/networking/ntpd.nix + ./services/networking/nullidentdmod.nix ./services/networking/nylon.nix ./services/networking/ocserv.nix ./services/networking/oidentd.nix @@ -680,6 +683,7 @@ ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix + ./services/web-apps/codimd.nix ./services/web-apps/frab.nix ./services/web-apps/mattermost.nix ./services/web-apps/nexus.nix diff --git a/nixos/modules/services/hardware/lirc.nix b/nixos/modules/services/hardware/lirc.nix new file mode 100644 index 000000000000..a66a7fbf495f --- /dev/null +++ b/nixos/modules/services/hardware/lirc.nix @@ -0,0 +1,85 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.lirc; +in { + + ###### interface + + options = { + services.lirc = { + + enable = mkEnableOption "LIRC daemon"; + + options = mkOption { + type = types.lines; + example = '' + [lircd] + nodaemon = False + ''; + description = "LIRC default options descriped in man:lircd(8) (<filename>lirc_options.conf</filename>)"; + }; + + configs = mkOption { + type = types.listOf types.lines; + description = "Configurations for lircd to load, see man:lircd.conf(5) for details (<filename>lircd.conf</filename>)"; + }; + + extraArguments = mkOption { + type = types.listOf types.str; + default = []; + description = "Extra arguments to lircd."; + }; + + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + # Note: LIRC executables raises a warning, if lirc_options.conf do not exists + environment.etc."lirc/lirc_options.conf".text = cfg.options; + + environment.systemPackages = [ pkgs.lirc ]; + + systemd.sockets.lircd = { + description = "LIRC daemon socket"; + wantedBy = [ "sockets.target" ]; + socketConfig = { + ListenStream = "/run/lirc/lircd"; + SocketUser = "lirc"; + SocketMode = "0660"; + }; + }; + + systemd.services.lircd = let + configFile = pkgs.writeText "lircd.conf" (builtins.concatStringsSep "\n" cfg.configs); + in { + description = "LIRC daemon service"; + after = [ "network.target" ]; + + unitConfig.Documentation = [ "man:lircd(8)" ]; + + serviceConfig = { + RuntimeDirectory = "lirc"; + ExecStart = '' + ${pkgs.lirc}/bin/lircd --nodaemon \ + ${escapeShellArgs cfg.extraArguments} \ + ${configFile} + ''; + User = "lirc"; + }; + }; + + users.users.lirc = { + uid = config.ids.uids.lirc; + group = "lirc"; + description = "LIRC user for lircd"; + }; + + users.groups.lirc.gid = config.ids.gids.lirc; + }; +} diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix index 06c4b2811b3f..c05811291359 100644 --- a/nixos/modules/services/mail/exim.nix +++ b/nixos/modules/services/mail/exim.nix @@ -2,7 +2,7 @@ let inherit (lib) mkIf mkOption singleton types; - inherit (pkgs) coreutils exim; + inherit (pkgs) coreutils; cfg = config.services.exim; in @@ -57,6 +57,16 @@ in ''; }; + package = mkOption { + type = types.package; + default = pkgs.exim; + defaultText = "pkgs.exim"; + description = '' + The Exim derivation to use. + This can be used to enable features such as LDAP or PAM support. + ''; + }; + }; }; @@ -74,7 +84,7 @@ in spool_directory = ${cfg.spoolDir} ${cfg.config} ''; - systemPackages = [ exim ]; + systemPackages = [ cfg.package ]; }; users.users = singleton { @@ -89,14 +99,14 @@ in gid = config.ids.gids.exim; }; - security.wrappers.exim.source = "${exim}/bin/exim"; + security.wrappers.exim.source = "${cfg.package}/bin/exim"; systemd.services.exim = { description = "Exim Mail Daemon"; wantedBy = [ "multi-user.target" ]; restartTriggers = [ config.environment.etc."exim.conf".source ]; serviceConfig = { - ExecStart = "${exim}/bin/exim -bdf -q30m"; + ExecStart = "${cfg.package}/bin/exim -bdf -q30m"; ExecReload = "${coreutils}/bin/kill -HUP $MAINPID"; }; preStart = '' diff --git a/nixos/modules/services/networking/epmd.nix b/nixos/modules/services/networking/epmd.nix new file mode 100644 index 000000000000..692b75e4f086 --- /dev/null +++ b/nixos/modules/services/networking/epmd.nix @@ -0,0 +1,56 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.epmd; + +in + +{ + ###### interface + options.services.epmd = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable socket activation for Erlang Port Mapper Daemon (epmd), + which acts as a name server on all hosts involved in distributed + Erlang computations. + ''; + }; + package = mkOption { + type = types.package; + default = pkgs.erlang; + description = '' + The Erlang package to use to get epmd binary. That way you can re-use + an Erlang runtime that is already installed for other purposes. + ''; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + systemd.sockets.epmd = rec { + description = "Erlang Port Mapper Daemon Activation Socket"; + wantedBy = [ "sockets.target" ]; + before = wantedBy; + socketConfig = { + ListenStream = "4369"; + Accept = "false"; + }; + }; + + systemd.services.epmd = { + description = "Erlang Port Mapper Daemon"; + after = [ "network.target" ]; + requires = [ "epmd.socket" ]; + + serviceConfig = { + DynamicUser = true; + ExecStart = "${cfg.package}/bin/epmd -systemd"; + Type = "notify"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/nullidentdmod.nix b/nixos/modules/services/networking/nullidentdmod.nix new file mode 100644 index 000000000000..786b5227dbad --- /dev/null +++ b/nixos/modules/services/networking/nullidentdmod.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, ... }: with lib; let + cfg = config.services.nullidentdmod; + +in { + options.services.nullidentdmod = with types; { + enable = mkEnableOption "Enable the nullidentdmod identd daemon"; + + userid = mkOption { + type = nullOr str; + description = "User ID to return. Set to null to return a random string each time."; + default = null; + example = "alice"; + }; + }; + + config = mkIf cfg.enable { + systemd.sockets.nullidentdmod = { + description = "Socket for identd (NullidentdMod)"; + listenStreams = [ "113" ]; + socketConfig.Accept = true; + wantedBy = [ "sockets.target" ]; + }; + + systemd.services."nullidentdmod@" = { + description = "NullidentdMod service"; + serviceConfig = { + DynamicUser = true; + ExecStart = "${pkgs.nullidentdmod}/bin/nullidentdmod${optionalString (cfg.userid != null) " ${cfg.userid}"}"; + StandardInput = "socket"; + StandardOutput = "socket"; + }; + }; + }; +} diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index def77ba69e58..9b6d4be9bda8 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -208,7 +208,7 @@ in enable = mkOption { type = types.bool; default = false; - description = "Whether to enable tor transaprent proxy"; + description = "Whether to enable tor transparent proxy"; }; listenAddress = mkOption { diff --git a/nixos/modules/services/web-apps/codimd.nix b/nixos/modules/services/web-apps/codimd.nix new file mode 100644 index 000000000000..5368e8b0e664 --- /dev/null +++ b/nixos/modules/services/web-apps/codimd.nix @@ -0,0 +1,958 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.codimd; + + prettyJSON = conf: + pkgs.runCommand "codimd-config.json" { } '' + echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \ + '{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out + ''; +in +{ + options.services.codimd = { + enable = mkEnableOption "the CodiMD Markdown Editor"; + + groups = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Groups to which the codimd user should be added. + ''; + }; + + workDir = mkOption { + type = types.path; + default = "/var/lib/codimd"; + description = '' + Working directory for the CodiMD service. + ''; + }; + + configuration = { + debug = mkEnableOption "debug mode"; + domain = mkOption { + type = types.nullOr types.str; + default = null; + example = "codimd.org"; + description = '' + Domain name for the CodiMD instance. + ''; + }; + urlPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/url/path/to/codimd"; + description = '' + Path under which CodiMD is accessible. + ''; + }; + host = mkOption { + type = types.str; + default = "localhost"; + description = '' + Address to listen on. + ''; + }; + port = mkOption { + type = types.int; + default = 3000; + example = "80"; + description = '' + Port to listen on. + ''; + }; + path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/run/codimd.sock"; + description = '' + Specify where a UNIX domain socket should be placed. + ''; + }; + allowOrigin = mkOption { + type = types.listOf types.str; + default = []; + example = [ "localhost" "codimd.org" ]; + description = '' + List of domains to whitelist. + ''; + }; + useSSL = mkOption { + type = types.bool; + default = false; + description = '' + Enable to use SSL server. This will also enable + <option>protocolUseSSL</option>. + ''; + }; + hsts = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Wheter to enable HSTS if HTTPS is also enabled. + ''; + }; + maxAgeSeconds = mkOption { + type = types.int; + default = 31536000; + description = '' + Max duration for clients to keep the HSTS status. + ''; + }; + includeSubdomains = mkOption { + type = types.bool; + default = true; + description = '' + Whether to include subdomains in HSTS. + ''; + }; + preload = mkOption { + type = types.bool; + default = true; + description = '' + Whether to allow preloading of the site's HSTS status. + ''; + }; + }; + csp = mkOption { + type = types.nullOr types.attrs; + default = null; + example = literalExample '' + { + enable = true; + directives = { + scriptSrc = "trustworthy.scripts.example.com"; + }; + upgradeInsecureRequest = "auto"; + addDefaults = true; + } + ''; + description = '' + Specify the Content Security Policy which is passed to Helmet. + For configuration details see <link xlink:href="https://helmetjs.github.io/docs/csp/" + >https://helmetjs.github.io/docs/csp/</link>. + ''; + }; + protocolUseSSL = mkOption { + type = types.bool; + default = false; + description = '' + Enable to use TLS for resource paths. + This only applies when <option>domain</option> is set. + ''; + }; + urlAddPort = mkOption { + type = types.bool; + default = false; + description = '' + Enable to add the port to callback URLs. + This only applies when <option>domain</option> is set + and only for ports other than 80 and 443. + ''; + }; + useCDN = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use CDN resources or not. + ''; + }; + allowAnonymous = mkOption { + type = types.bool; + default = true; + description = '' + Whether to allow anonymous usage. + ''; + }; + allowAnonymousEdits = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow guests to edit existing notes with the `freely' permission, + when <option>allowAnonymous</option> is enabled. + ''; + }; + allowFreeURL = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow note creation by accessing a nonexistent note URL. + ''; + }; + defaultPermission = mkOption { + type = types.enum [ "freely" "editable" "limited" "locked" "private" ]; + default = "editable"; + description = '' + Default permissions for notes. + This only applies for signed-in users. + ''; + }; + dbURL = mkOption { + type = types.nullOr types.str; + default = null; + example = '' + postgres://user:pass@host:5432/dbname + ''; + description = '' + Specify which database to use. + CodiMD supports mysql, postgres, sqlite and mssql. + See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> + https://sequelize.readthedocs.io/en/v3/</link> for more information. + Note: This option overrides <option>db</option>. + ''; + }; + db = mkOption { + type = types.attrs; + default = {}; + example = literalExample '' + { + dialect = "sqlite"; + storage = "/var/lib/codimd/db.codimd.sqlite"; + } + ''; + description = '' + Specify the configuration for sequelize. + CodiMD supports mysql, postgres, sqlite and mssql. + See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> + https://sequelize.readthedocs.io/en/v3/</link> for more information. + Note: This option overrides <option>db</option>. + ''; + }; + sslKeyPath= mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/codimd.key"; + description = '' + Path to the SSL key. Needed when <option>useSSL</option> is enabled. + ''; + }; + sslCertPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/codimd.crt"; + description = '' + Path to the SSL cert. Needed when <option>useSSL</option> is enabled. + ''; + }; + sslCAPath = mkOption { + type = types.listOf types.str; + default = []; + example = [ "/var/lib/codimd/ca.crt" ]; + description = '' + SSL ca chain. Needed when <option>useSSL</option> is enabled. + ''; + }; + dhParamPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/dhparam.pem"; + description = '' + Path to the SSL dh params. Needed when <option>useSSL</option> is enabled. + ''; + }; + tmpPath = mkOption { + type = types.str; + default = "/tmp"; + description = '' + Path to the temp directory CodiMD should use. + Note that <option>serviceConfig.PrivateTmp</option> is enabled for + the CodiMD systemd service by default. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + defaultNotePath = mkOption { + type = types.nullOr types.str; + default = "./public/default.md"; + description = '' + Path to the default Note file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + docsPath = mkOption { + type = types.nullOr types.str; + default = "./public/docs"; + description = '' + Path to the docs directory. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + indexPath = mkOption { + type = types.nullOr types.str; + default = "./public/views/index.ejs"; + description = '' + Path to the index template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + hackmdPath = mkOption { + type = types.nullOr types.str; + default = "./public/views/hackmd.ejs"; + description = '' + Path to the hackmd template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + errorPath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/error.ejs"; + description = '' + Path to the error template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + prettyPath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/pretty.ejs"; + description = '' + Path to the pretty template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + slidePath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/slide.hbs"; + description = '' + Path to the slide template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + uploadsPath = mkOption { + type = types.str; + default = "${cfg.workDir}/uploads"; + defaultText = "/var/lib/codimd/uploads"; + description = '' + Path under which uploaded files are saved. + ''; + }; + sessionName = mkOption { + type = types.str; + default = "connect.sid"; + description = '' + Specify the name of the session cookie. + ''; + }; + sessionSecret = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Specify the secret used to sign the session cookie. + If unset, one will be generated on startup. + ''; + }; + sessionLife = mkOption { + type = types.int; + default = 1209600000; + description = '' + Session life time in milliseconds. + ''; + }; + heartbeatInterval = mkOption { + type = types.int; + default = 5000; + description = '' + Specify the socket.io heartbeat interval. + ''; + }; + heartbeatTimeout = mkOption { + type = types.int; + default = 10000; + description = '' + Specify the socket.io heartbeat timeout. + ''; + }; + documentMaxLength = mkOption { + type = types.int; + default = 100000; + description = '' + Specify the maximum document length. + ''; + }; + email = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable email sign-in. + ''; + }; + allowEmailRegister = mkOption { + type = types.bool; + default = true; + description = '' + Wether to enable email registration. + ''; + }; + allowGravatar = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use gravatar as profile picture source. + ''; + }; + imageUploadType = mkOption { + type = types.enum [ "imgur" "s3" "minio" "filesystem" ]; + default = "filesystem"; + description = '' + Specify where to upload images. + ''; + }; + minio = mkOption { + type = types.nullOr (types.submodule { + options = { + accessKey = mkOption { + type = types.str; + default = ""; + description = '' + Minio access key. + ''; + }; + secretKey = mkOption { + type = types.str; + default = ""; + description = '' + Minio secret key. + ''; + }; + endpoint = mkOption { + type = types.str; + default = ""; + description = '' + Minio endpoint. + ''; + }; + port = mkOption { + type = types.int; + default = 9000; + description = '' + Minio listen port. + ''; + }; + secure = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use HTTPS for Minio. + ''; + }; + }; + }); + default = null; + description = "Configure the minio third-party integration."; + }; + s3 = mkOption { + type = types.nullOr (types.submodule { + options = { + accessKeyId = mkOption { + type = types.str; + default = ""; + description = '' + AWS access key id. + ''; + }; + secretAccessKey = mkOption { + type = types.str; + default = ""; + description = '' + AWS access key. + ''; + }; + region = mkOption { + type = types.str; + default = ""; + description = '' + AWS S3 region. + ''; + }; + }; + }); + default = null; + description = "Configure the s3 third-party integration."; + }; + s3bucket = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Specify the bucket name for upload types <literal>s3</literal> and <literal>minio</literal>. + ''; + }; + allowPDFExport = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable PDF exports. + ''; + }; + imgur.clientId = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Imgur API client ID. + ''; + }; + azure = mkOption { + type = types.nullOr (types.submodule { + options = { + connectionString = mkOption { + type = types.str; + default = ""; + description = '' + Azure Blob Storage connection string. + ''; + }; + container = mkOption { + type = types.str; + default = ""; + description = '' + Azure Blob Storage container name. + It will be created if non-existent. + ''; + }; + }; + }); + default = null; + description = "Configure the azure third-party integration."; + }; + oauth2 = mkOption { + type = types.nullOr (types.submodule { + options = { + authorizationURL = mkOption { + type = types.str; + default = ""; + description = '' + Specify the OAuth authorization URL. + ''; + }; + tokenURL = mkOption { + type = types.str; + default = ""; + description = '' + Specify the OAuth token URL. + ''; + }; + clientID = mkOption { + type = types.str; + default = ""; + description = '' + Specify the OAuth client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Specify the OAuth client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the OAuth integration."; + }; + facebook = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + default = ""; + description = '' + Facebook API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Facebook API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the facebook third-party integration"; + }; + twitter = mkOption { + type = types.nullOr (types.submodule { + options = { + consumerKey = mkOption { + type = types.str; + default = ""; + description = '' + Twitter API consumer key. + ''; + }; + consumerSecret = mkOption { + type = types.str; + default = ""; + description = '' + Twitter API consumer secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Twitter third-party integration."; + }; + github = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + default = ""; + description = '' + GitHub API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Github API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the GitHub third-party integration."; + }; + gitlab = mkOption { + type = types.nullOr (types.submodule { + options = { + baseURL = mkOption { + type = types.str; + default = ""; + description = '' + GitLab API authentication endpoint. + Only needed for other endpoints than gitlab.com. + ''; + }; + clientID = mkOption { + type = types.str; + default = ""; + description = '' + GitLab API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + GitLab API client secret. + ''; + }; + scope = mkOption { + type = types.enum [ "api" "read_user" ]; + default = "api"; + description = '' + GitLab API requested scope. + GitLab snippet import/export requires api scope. + ''; + }; + }; + }); + default = null; + description = "Configure the GitLab third-party integration."; + }; + mattermost = mkOption { + type = types.nullOr (types.submodule { + options = { + baseURL = mkOption { + type = types.str; + default = ""; + description = '' + Mattermost authentication endpoint. + ''; + }; + clientID = mkOption { + type = types.str; + default = ""; + description = '' + Mattermost API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Mattermost API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Mattermost third-party integration."; + }; + dropbox = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + default = ""; + description = '' + Dropbox API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Dropbox API client secret. + ''; + }; + appKey = mkOption { + type = types.str; + default = ""; + description = '' + Dropbox app key. + ''; + }; + }; + }); + default = null; + description = "Configure the Dropbox third-party integration."; + }; + google = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + default = ""; + description = '' + Google API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + default = ""; + description = '' + Google API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Google third-party integration."; + }; + ldap = mkOption { + type = types.nullOr (types.submodule { + options = { + providerName = mkOption { + type = types.str; + default = ""; + description = '' + Optional name to be displayed at login form, indicating the LDAP provider. + ''; + }; + url = mkOption { + type = types.str; + default = ""; + example = "ldap://localhost"; + description = '' + URL of LDAP server. + ''; + }; + bindDn = mkOption { + type = types.str; + default = ""; + description = '' + Bind DN for LDAP access. + ''; + }; + bindCredentials = mkOption { + type = types.str; + default = ""; + description = '' + Bind credentials for LDAP access. + ''; + }; + searchBase = mkOption { + type = types.str; + default = ""; + example = "o=users,dc=example,dc=com"; + description = '' + LDAP directory to begin search from. + ''; + }; + searchFilter = mkOption { + type = types.str; + default = ""; + example = "(uid={{username}})"; + description = '' + LDAP filter to search with. + ''; + }; + searchAttributes = mkOption { + type = types.listOf types.str; + default = []; + example = [ "displayName" "mail" ]; + description = '' + LDAP attributes to search with. + ''; + }; + userNameField = mkOption { + type = types.str; + default = ""; + description = '' + LDAP field which is used as the username on CodiMD. + By default <option>useridField</option> is used. + ''; + }; + useridField = mkOption { + type = types.str; + default = ""; + example = "uid"; + description = '' + LDAP field which is a unique identifier for users on CodiMD. + ''; + }; + tlsca = mkOption { + type = types.str; + default = ""; + example = "server-cert.pem,root.pem"; + description = '' + Root CA for LDAP TLS in PEM format. + ''; + }; + }; + }); + default = null; + description = "Configure the LDAP integration."; + }; + saml = mkOption { + type = types.nullOr (types.submodule { + options = { + idpSsoUrl = mkOption { + type = types.str; + default = ""; + example = "https://idp.example.com/sso"; + description = '' + IdP authentication endpoint. + ''; + }; + idPCert = mkOption { + type = types.str; + default = ""; + example = "/path/to/cert.pem"; + description = '' + Path to IdP certificate file in PEM format. + ''; + }; + issuer = mkOption { + type = types.str; + default = ""; + description = '' + Optional identity of the service provider. + This defaults to the server URL. + ''; + }; + identifierFormat = mkOption { + type = types.str; + default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"; + description = '' + Optional name identifier format. + ''; + }; + groupAttribute = mkOption { + type = types.str; + default = ""; + example = "memberOf"; + description = '' + Optional attribute name for group list. + ''; + }; + externalGroups = mkOption { + type = types.listOf types.str; + default = []; + example = [ "Temporary-staff" "External-users" ]; + description = '' + Excluded group names. + ''; + }; + requiredGroups = mkOption { + type = types.listOf types.str; + default = []; + example = [ "Hackmd-users" "Codimd-users" ]; + description = '' + Required group names. + ''; + }; + attribute = { + id = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `id'. + Defaults to `NameID' of SAML response. + ''; + }; + username = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `username'. + Defaults to `NameID' of SAML response. + ''; + }; + email = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `email'. + Defaults to `NameID' of SAML response if + <option>identifierFormat</option> has + the default value. + ''; + }; + }; + }; + }); + default = null; + description = "Configure the SAML integration."; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { assertion = cfg.configuration.db == {} -> ( + cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null + ); + message = "Database configuration for CodiMD missing."; } + ]; + users.groups.codimd = {}; + users.users.codimd = { + description = "CodiMD service user"; + group = "codimd"; + extraGroups = cfg.groups; + home = cfg.workDir; + createHome = true; + }; + + systemd.services.codimd = { + description = "CodiMD Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "networking.target" ]; + preStart = '' + mkdir -p ${cfg.workDir} + chown -R codimd: ${cfg.workDir} + ''; + serviceConfig = { + WorkingDirectory = cfg.workDir; + ExecStart = "${pkgs.codimd}/bin/codimd"; + Environment = [ + "CMD_CONFIG_FILE=${prettyJSON cfg.configuration}" + "NODE_ENV=production" + ]; + Restart = "always"; + User = "codimd"; + PermissionsStartOnly = true; + PrivateTmp = true; + }; + }; + }; +} diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index f561c5f8b7a9..357fa8ce8f36 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -266,7 +266,7 @@ in session. Each session script can set the <varname>waitPID</varname> shell variable to make this script wait until the end of the user session. Each script is used - to define either a windows manager or a desktop manager. These + to define either a window manager or a desktop manager. These can be differentiated by setting the attribute <varname>manage</varname> either to <literal>"window"</literal> or <literal>"desktop"</literal>. diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index cd9c3d81a0fb..ae2b05797fd0 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -197,7 +197,7 @@ in # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH execCmd = '' export PATH=${lightdm}/sbin:$PATH - exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run + exec ${lightdm}/sbin/lightdm ''; }; @@ -246,12 +246,19 @@ in ''; users.users.lightdm = { - createHome = true; - home = "/var/lib/lightdm-data"; + home = "/var/lib/lightdm"; group = "lightdm"; uid = config.ids.uids.lightdm; }; + systemd.tmpfiles.rules = [ + "d /var/run/lightdm 0711 lightdm lightdm 0" + "d /var/cache/lightdm 0711 root lightdm -" + "d /var/lib/lightdm 1770 lightdm lightdm -" + "d /var/lib/lightdm-data 1775 lightdm lightdm -" + "d /var/log/lightdm 0711 root lightdm -" + ]; + users.groups.lightdm.gid = config.ids.gids.lightdm; services.xserver.tty = null; # We might start multiple X servers so let the tty increment themselves.. services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there diff --git a/nixos/release.nix b/nixos/release.nix index 0fd8d694641f..ee31564bcf74 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -261,6 +261,7 @@ in rec { tests.chromium = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {}; tests.cjdns = callTest tests/cjdns.nix {}; tests.cloud-init = callTest tests/cloud-init.nix {}; + tests.codimd = callTest tests/codimd.nix {}; tests.containers-ipv4 = callTest tests/containers-ipv4.nix {}; tests.containers-ipv6 = callTest tests/containers-ipv6.nix {}; tests.containers-bridge = callTest tests/containers-bridge.nix {}; diff --git a/nixos/tests/codimd.nix b/nixos/tests/codimd.nix new file mode 100644 index 000000000000..8f98d9f3fa72 --- /dev/null +++ b/nixos/tests/codimd.nix @@ -0,0 +1,56 @@ +import ./make-test.nix ({ pkgs, lib, ... }: +{ + name = "codimd"; + + meta = with lib.maintainers; { + maintainers = [ willibutz ]; + }; + + nodes = { + codimdSqlite = { ... }: { + services = { + codimd = { + enable = true; + configuration.dbURL = "sqlite:///var/lib/codimd/codimd.db"; + }; + }; + }; + + codimdPostgres = { ... }: { + systemd.services.codimd.after = [ "postgresql.service" ]; + services = { + codimd = { + enable = true; + configuration.dbURL = "postgres://codimd:snakeoilpassword@localhost:5432/codimddb"; + }; + postgresql = { + enable = true; + initialScript = pkgs.writeText "pg-init-script.sql" '' + CREATE ROLE codimd LOGIN PASSWORD 'snakeoilpassword'; + CREATE DATABASE codimddb OWNER codimd; + ''; + }; + }; + }; + }; + + testScript = '' + startAll(); + + subtest "CodiMD sqlite", sub { + $codimdSqlite->waitForUnit("codimd.service"); + $codimdSqlite->waitForOpenPort(3000); + $codimdPostgres->succeed("sleep 2"); # avoid 503 during startup + $codimdSqlite->succeed("curl -sSf http://localhost:3000/new"); + }; + + subtest "CodiMD postgres", sub { + $codimdPostgres->waitForUnit("postgresql.service"); + $codimdPostgres->waitForUnit("codimd.service"); + $codimdPostgres->waitForOpenPort(5432); + $codimdPostgres->waitForOpenPort(3000); + $codimdPostgres->succeed("sleep 2"); # avoid 503 during startup + $codimdPostgres->succeed("curl -sSf http://localhost:3000/new"); + }; + ''; +}) diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 3d31c8dc4457..610444f90e47 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -563,6 +563,7 @@ in { "swapon -L swap", "mkfs.ext3 -L nixos /dev/sda2", "mount LABEL=nixos /mnt", + "mkdir -p /mnt/tmp", ); ''; grubVersion = 1; |