1 { config, lib, pkgs, ... }:
4 cfg = config.programs.rust-motd;
5 format = pkgs.formats.toml { };
7 # Order the sections in the TOML according to the order of sections
9 motdConf = pkgs.runCommand "motd.conf"
11 __structuredAttrs = true;
12 inherit (cfg) order settings;
13 nativeBuildInputs = [ pkgs.remarshal pkgs.jq ];
16 cat "$NIX_ATTRS_JSON_FILE" \
17 | jq '.settings as $settings
19 | map({ key: ., value: $settings."\(.)" })
21 | json2toml /dev/stdin "$out"
24 options.programs.rust-motd = {
25 enable = lib.mkEnableOption "rust-motd, a Message Of The Day (MOTD) generator";
26 enableMotdInSSHD = lib.mkOption {
28 type = lib.types.bool;
30 Whether to let `openssh` print the
31 result when entering a new `ssh`-session.
32 By default either nothing or a static file defined via
33 [](#opt-users.motd) is printed. Because of that,
34 the latter option is incompatible with this module.
37 refreshInterval = lib.mkOption {
41 Interval in which the {manpage}`motd(5)` file is refreshed.
42 For possible formats, please refer to {manpage}`systemd.time(7)`.
45 order = lib.mkOption {
46 type = lib.types.listOf lib.types.str;
47 default = builtins.attrNames cfg.settings;
48 defaultText = lib.literalExpression "attrNames cfg.settings";
50 The order of the sections in [](#opt-programs.rust-motd.settings).
51 By default they are ordered alphabetically.
53 Context: since attribute sets in Nix are always
54 ordered alphabetically internally this means that
58 uptime = { /* ... */ };
59 banner = { /* ... */ };
63 will still have `banner` displayed before `uptime`.
65 To work around that, this option can be used to define the order of all keys,
77 makes sure that `uptime` is placed before `banner` in the motd.
80 settings = lib.mkOption {
81 type = lib.types.attrsOf format.type;
83 Settings on what to generate. Please read the
84 [upstream documentation](https://github.com/rust-motd/rust-motd/blob/main/README.md#configuration)
85 for further information.
89 config = lib.mkIf cfg.enable {
91 { assertion = config.users.motd == "";
93 `programs.rust-motd` is incompatible with `users.motd`!
96 { assertion = builtins.sort (a: b: a < b) cfg.order == builtins.attrNames cfg.settings;
98 Please ensure that every section from `programs.rust-motd.settings` is present in
99 `programs.rust-motd.order`.
103 systemd.services.rust-motd = {
104 path = with pkgs; [ bash ];
105 documentation = [ "https://github.com/rust-motd/rust-motd/blob/v${pkgs.rust-motd.version}/README.md" ];
106 description = "motd generator";
107 wantedBy = [ "multi-user.target" ];
109 ExecStart = "${pkgs.writeShellScript "update-motd" ''
110 ${pkgs.rust-motd}/bin/rust-motd ${motdConf} > motd
112 CapabilityBoundingSet = [ "" ];
113 LockPersonality = true;
114 MemoryDenyWriteExecute = true;
115 NoNewPrivileges = true;
116 PrivateDevices = true;
119 ProtectControlGroups = true;
121 ProtectHostname = true;
122 ProtectKernelModules = true;
123 ProtectKernelLogs = true;
124 ProtectKernelTunables = true;
125 ProtectSystem = "full";
126 StateDirectory = "rust-motd";
127 RestrictAddressFamilies = [ "AF_UNIX" ];
128 RestrictNamespaces = true;
129 RestrictRealtime = true;
130 RestrictSUIDSGID = true;
132 WorkingDirectory = "/var/lib/rust-motd";
135 systemd.timers.rust-motd = {
136 wantedBy = [ "timers.target" ];
137 timerConfig.OnCalendar = cfg.refreshInterval;
139 security.pam.services.sshd.text = lib.mkIf cfg.enableMotdInSSHD (lib.mkDefault (lib.mkAfter ''
140 session optional ${pkgs.pam}/lib/security/pam_motd.so motd=/var/lib/rust-motd/motd
142 services.openssh.extraConfig = lib.mkIf (cfg.settings ? last_login && cfg.settings.last_login != {}) ''
146 meta.maintainers = with lib.maintainers; [ ma27 ];