Compare commits

..

1 commit

Author SHA1 Message Date
f389de9c55 nftables: use networking.firewall.allowed{TCP,UDP}Port{s,Ranges}
This is a no-op as far as actual config is concerned, but allows using
the usual networking options again, which before this commit were just
old unused code lying around.

There are still many other networking options which we set that
currently do nothing (e.g. the network bridge to lxc).
2024-04-06 14:55:48 +02:00
32 changed files with 476 additions and 717 deletions

View file

@ -15,7 +15,6 @@
SystemMaxUse=512M
MaxRetentionSec=48h
'';
nix.package = pkgs.lix;
nix.gc.automatic = lib.mkDefault true;
nix.gc.options = lib.mkDefault "--delete-older-than 7d";
nix.settings.trusted-users = [ "root" "@wheel" ];
@ -75,8 +74,6 @@
ffmpeg-full
bat
niv
sqlite-interactive
hacc-scripts
];
security.acme.defaults.email = "info+acme@hacc.space";

View file

@ -25,11 +25,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1727447169,
"narHash": "sha256-3KyjMPUKHkiWhwR91J1YchF6zb6gvckCAY1jOE+ne0U=",
"lastModified": 1711733382,
"narHash": "sha256-XuKlYhc9Hk6jMIIwWTP6CTQVUWi0Sq3nJApnUJk6bu8=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "aa07eb05537d4cd025e2310397a6adcedfe72c76",
"rev": "2bad21828ee2c5d1e42588d5f4c53f5b10300c6a",
"type": "github"
},
"original": {
@ -61,44 +61,58 @@
"deploy-rs",
"flake-compat"
],
"nixpkgs": [
"nixpkgs-unstable"
],
"nixpkgs-24_05": [
"nixpkgs": "nixpkgs",
"nixpkgs-23_05": [
"nixpkgs"
],
"nixpkgs-23_11": "nixpkgs-23_11",
"utils": [
"deploy-rs",
"utils"
]
},
"locked": {
"lastModified": 1718084203,
"narHash": "sha256-Cx1xoVfSMv1XDLgKg08CUd1EoTYWB45VmB9XIQzhmzI=",
"lastModified": 1706219574,
"narHash": "sha256-qO+8UErk+bXCq2ybHU4GzXG4Ejk4Tk0rnnTPNyypW4g=",
"owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver",
"rev": "29916981e7b3b5782dc5085ad18490113f8ff63b",
"rev": "e47f3719f1db3e0961a4358d4cb234a0acaa7baf",
"type": "gitlab"
},
"original": {
"owner": "simple-nixos-mailserver",
"ref": "nixos-24.05",
"ref": "nixos-23.11",
"repo": "nixos-mailserver",
"type": "gitlab"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1731842749,
"narHash": "sha256-aNc8irVBH7sM5cGDvqdOueg8S+fGakf0rEMRGfGwWZw=",
"lastModified": 1705856552,
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bf6132dc791dbdff8b6894c3a85eb27ad8255682",
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-24.05-small",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"nixpkgs-23_11": {
"locked": {
"lastModified": 1706098335,
"narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a77ab169a83a4175169d78684ddd2e54486ac651",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.11",
"type": "indirect"
}
},
@ -120,24 +134,55 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1732007104,
"narHash": "sha256-qaWPxgLAvtIHTDcm0qJuc+WNYjcy4ZKigOyn2ag4ihM=",
"lastModified": 1711703276,
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0705964c881cea8896474610188905ba41b59b08",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable-small",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1711668574,
"narHash": "sha256-u1dfs0ASQIEr1icTVrsKwg2xToIpn7ZXxW3RHfHxshg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "219951b495fc2eac67b1456824cc1ec1fd2ee659",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.11",
"type": "indirect"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1711200738,
"narHash": "sha256-dkJmk/ET/tRV4007O6kU101UEg1svUwiyk/zEEX9Tdg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "20bc93ca7b2158ebc99b8cef987a2173a81cde35",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"deploy-rs": "deploy-rs",
"nixos-mailserver": "nixos-mailserver",
"nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs_2",
"nixpkgs-oldstable": "nixpkgs-oldstable",
"nixpkgs-unstable": "nixpkgs-unstable",
"sops-nix": "sops-nix",
@ -146,16 +191,17 @@
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs-unstable"
"nixpkgs": "nixpkgs_3",
"nixpkgs-stable": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1731954233,
"narHash": "sha256-vvXx1m2Rsw7MkbKJdpcICzz4YPgZPApGKQGhNZfkhOI=",
"lastModified": 1711249319,
"narHash": "sha256-N+Pp3/8H+rd7cO71VNV/ovV/Kwt+XNeUHNhsmyTabdM=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "e39947d0ee8e341fa7108bd02a33cdfa24a1360e",
"rev": "405987a66cce9a4a82f321f11b205982a7127c88",
"type": "github"
},
"original": {
@ -182,11 +228,11 @@
"tracktrain": {
"flake": false,
"locked": {
"lastModified": 1720213096,
"narHash": "sha256-GrSXD6WvyiXcHx1s+48PEZVn/MTtBJAXpgds+NdEL2g=",
"lastModified": 1688154251,
"narHash": "sha256-iv2xUUYhjIcKWs1+l7h43z7v/a9/OamBKXi/gcl4ppI=",
"ref": "main",
"rev": "2943327863bfe5c6e793e5c40e473a2755d45642",
"revCount": 126,
"rev": "a995dabf07574a32c1ae62ad23b96ba7d8e076ee",
"revCount": 92,
"type": "git",
"url": "https://stuebinm.eu/git/tracktrain"
},

View file

@ -2,11 +2,11 @@
description = "hacc infra stuff";
inputs = {
nixpkgs.url = "nixpkgs/nixos-24.05-small";
nixpkgs-unstable.url = "nixpkgs/nixos-unstable-small";
nixpkgs.url = "nixpkgs/nixos-23.11";
nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
nixpkgs-oldstable.url = "github:/NixOS/nixpkgs?rev=c4aec3c021620d98861639946123214207e98344";
nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-24.05";
nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-23.11";
tracktrain.url = "git+https://stuebinm.eu/git/tracktrain?ref=main";
tracktrain.flake = false;
@ -14,13 +14,11 @@
deploy-rs.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs-stable.follows = "nixpkgs";
sops-nix.inputs.nixpkgs.follows = "nixpkgs-unstable";
# these exist mostly to make the flake.lock somewhat more human-friendly
# note that in theory doing this might break things, but it seems fairly unlikely
nixos-mailserver.inputs = {
"nixpkgs-24_05".follows = "nixpkgs";
nixpkgs.follows = "nixpkgs-unstable";
"nixpkgs-23_05".follows = "nixpkgs";
utils.follows = "/deploy-rs/utils";
flake-compat.follows = "/deploy-rs/flake-compat";
};
@ -39,22 +37,34 @@
sources = inputs;
system = "x86_64-linux";
config.allowUnfree = true;
config.permittedInsecurePackages = [ "nextcloud-27.1.11" ];
};
evalConfig = config: (nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config
{
nixpkgs.pkgs = pkgs.lib.mkForce pkgs;
imports = [ modules.nopersist profiles.container ];
}
];
specialArgs = {
# some of our modules import each other, and evalConfig is used for containers
inherit modules evalConfig;
sources = inputs;
};
}).config.system.build.toplevel;
in {
nixosConfigurations.parsons = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./parsons/configuration.nix
./modules/buildinfo.nix
./modules/containers.nix
sops-nix.nixosModules.sops
{ nixpkgs.pkgs = pkgs; }
{ environment.etc."haccfiles".source = self.outPath; }
];
specialArgs = {
sources = inputs;
inherit modules profiles;
inherit (nixpkgs.lib) nixosSystem;
inherit modules evalConfig;
};
};
@ -73,20 +83,11 @@
(system: deployLib: deployLib.deployChecks self.deploy)
deploy-rs.lib;
apps.x86_64-linux =
packages.x86_64-linux =
let
mkApp = pkg: {
type = "app";
program = pkgs.lib.getExe pkg;
};
websites = pkgs.lib.mapAttrs (name: mkApp)
self.nixosConfigurations.parsons.config.hacc.websites.builders;
websites = self.nixosConfigurations.parsons.config.hacc.websites.builders;
in
{ docs = websites."docs.hacc.space"; } // websites;
packages.x86_64-linux = {
inherit (pkgs) mattermost hacc-scripts;
};
};
}

View file

@ -1,29 +0,0 @@
{ config, lib, pkgs, sources, ... }:
let
self = sources.self;
formatDate = date: with lib.strings;
let
year = substring 0 4 date;
month = substring 4 2 date;
day = substring 6 2 date;
hour = substring 8 2 date;
minute = substring 10 2 date;
second = substring 12 2 date;
in
"${year}-${month}-${day} ${hour}:${minute}:${second} UTC";
in
{
system.nixos.label = "${config.system.nixos.release}-haccfiles-${self.shortRev or self.dirtyShortRev}";
users.motd = ''
Welcome to ${config.networking.hostName}, running NixOS ${config.system.nixos.release}!
Built from haccfiles ${self.rev or self.dirtyRev}.
Last commit was at ${formatDate self.lastModifiedDate}.
${if self ? dirtyRev then "\nPlease remember to commit your changes.\n" else ""}
'';
# used by monit
environment.etc."haccfiles-commit".text = self.rev or self.dirtyRev;
environment.etc."haccfiles-timestamp".text = builtins.toString self.lastModified;
}

View file

@ -14,5 +14,12 @@
'';
};
# I /suspect/ this is not actually needed.
# TODO: find spoons to deal with potential breakage, test removing this
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
system.stateVersion = lib.mkDefault "21.05";
}

View file

@ -1,95 +0,0 @@
{ config, lib, pkgs, modules, profiles, sources, nixosSystem, ... }:
let
mkIPv4 = index: local:
"192.168.${if local then "100" else "101"}.${toString index}";
mkIPv6 = index: local:
"fd00::${if local then "100" else "101"}:${toString index}";
evalConfig = nixosConfig: (nixosSystem {
inherit (config.nixpkgs) system;
modules = [
nixosConfig
modules.nopersist
profiles.container
{ nixpkgs.pkgs = lib.mkForce pkgs; }
];
specialArgs = {
inherit modules sources;
};
}).config.system.build.toplevel;
in {
options.hacc.containers = with lib.options;
mkOption {
description = ''
hacc-specific containers. These are a thin wrapper around "normal" nixos containers:
- they automatically get an IPv4/IPv6 address assigned
(note that these are not guaranteed to be stable across config changes,
so please use {option}`containers.<name>.hostAddress` & friends to
reference them elsewhere)
- they set a couple default options (e.g. ephemeral, autoStart, privateNetwork)
- they are evaluated with our own version of {nix}`evalConfig`, which includes a
couple more modules by default, use our version of `nixpkgs`, and includes the
{nix}`profiles.containers` profile setting sane defaults for containers.
'';
default = { };
type = with lib.types;
types.attrsOf (types.submodule {
options = {
bindToPersist = mkOption {
default = true;
type = types.bool;
description =
"Wether to mount /persist/containers/<name> at /persist into this container.";
};
bindSecrets = mkOption {
default = false;
type = types.bool;
description =
"Whether to mount /run/secrets/<name> at /secrets into this container.";
};
config = mkOption {
type = types.unspecified;
description =
"The container's config, to be evaluated with our own {nix}`evalConfig`.";
};
};
});
};
# wrapped into imap1, which enumerates the containers; IP addresses are then
# simply assigned based on the order the containers are in the list.
config.containers = lib.mkMerge (lib.imap1
(index: { name, value }: let container = value; in {
${name} = {
hostAddress = mkIPv4 index false;
localAddress = mkIPv4 index true;
hostAddress6 = mkIPv6 index false;
localAddress6 = mkIPv6 index true;
privateNetwork = true;
autoStart = true;
ephemeral = true;
bindMounts = lib.mkMerge [
(lib.mkIf container.bindToPersist {
"/persist" = {
hostPath = "/persist/containers/${name}";
isReadOnly = false;
};
})
(lib.mkIf container.bindSecrets {
"/secrets" = {
hostPath = "/run/secrets/${name}";
isReadOnly = true;
};
})
];
path = evalConfig container.config;
};
}) (lib.attrsToList config.hacc.containers));
}

View file

@ -19,7 +19,6 @@
./tracktrain.nix
./uffd.nix
./lxc.nix
./monit.nix
];
hacc.bindToPersist = [ "/var/lib/acme" ];
@ -51,6 +50,13 @@
address = "fe80::1";
interface = "enp35s0";
};
boot = {
kernelModules = [ "nf_nat_ftp" ];
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = lib.mkOverride 90 true;
"net.ipv4.conf.default.forwarding" = lib.mkOverride 90 true;
};
};
services.nginx = {
enable = true;

View file

@ -1,8 +1,19 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
{
hacc.containers.forgejo = {
config = { lib, pkgs, ... }: {
containers.forgejo = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.10";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/forgejo";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
system.stateVersion = "21.11";
environment.systemPackages = [ pkgs.forgejo ];
@ -67,12 +78,16 @@
};
services.openssh = {
enable = true;
listenAddresses = [ {
addr = "192.168.100.10";
port = 22;
} ];
settings = {
PasswordAuthentication = false;
AcceptEnv = "GIT_PROTOCOL";
};
};
};
});
};
services.nginx.virtualHosts."git.infra4future.de" = {

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
{
@ -6,11 +6,20 @@
"hedgedoc-hacc/env" = {};
};
containers.pad-hacc.bindMounts = {
containers.pad-hacc = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.5";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-hacc";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/hedgedoc-hacc";
};
hacc.containers.pad-hacc = {
config = { config, lib, ... }: {
path = evalConfig ({ config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
@ -69,7 +78,7 @@
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
};
});
};
services.nginx.virtualHosts."pad.hacc.earth" = {
enableACME = true;

View file

@ -1,8 +1,19 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
{
hacc.containers.pad-i4f = {
config = { config, lib, ... }: {
containers.pad-i4f = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.6";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-i4f";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, ... }: {
services.hedgedoc = {
enable = true;
settings = {
@ -46,7 +57,7 @@
location = "/persist/backups/postgres";
};
hacc.bindToPersist = [ "/var/lib/hedgedoc" ];
};
});
};
services.nginx.virtualHosts."pad.infra4future.de" = {

View file

@ -8,6 +8,7 @@
prefixLength = 24;
}
];
networking.nat.internalInterfaces = [ "lxcbr0" ];
virtualisation.lxc.enable = true;
virtualisation.lxc.systemConfig = ''

View file

@ -20,6 +20,13 @@
monitoring = {
enable = true;
alertAddress = "admin@hacc.space";
config = (lib.replaceStrings ["port 22"] ["port ${toString (lib.head config.services.openssh.ports)}"] options.mailserver.monitoring.config.default) + ''
check host onlyoffice with address onlyoffice.infra4future.de
start program "/run/current-system/sw/bin/lxc-start onlyoffice"
stop program "/run/current-system/sw/bin/lxc-stop onlyoffice"
if failed port 443 protocol https status = 302
then restart
'';
};
domains = [
"hacc.space"

View file

@ -1,16 +1,26 @@
{ config, pkgs, lib, ...}:
{ config, pkgs, lib, evalConfig, ...}:
{
sops.secrets = {
"mattermost/env" = {};
};
hacc.containers.mattermost = {
bindSecrets = true;
containers.mattermost = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.3";
ephemeral = true;
config = { config, lib, pkgs, ... }: {
environment.systemPackages = [ pkgs.morph pkgs.pgloader ];
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/mattermost";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/mattermost";
};
path = evalConfig ({ config, lib, pkgs, ... }: {
systemd.services.mattermost.serviceConfig.EnvironmentFile =
lib.mkForce "/secrets/env";
@ -62,6 +72,8 @@
};
LogSettings = {
EnableConsole = true;
# note: for some reason this doesn't work (mattermost still sets it to DEBUG);
# it's also set in secrets.env, where for some reason it does
ConsoleLevel = "ERROR";
EnableDiagnostics = false;
EnableWebhookDebugging = false;
@ -144,12 +156,18 @@
Enable = true;
EnableUploads = true;
Plugins = {
bigbluebutton = {
adminonly = false;
base_url = "https://bbb.infra4future.de/bigbluebutton/api";
salt = "zKCsNeaEniC115ynHOsZopgA4iTiJjzgeiPNoCEc";
};
"com.github.matterpoll.matterpoll" = {
experimentalui = true;
trigger = "poll";
};
};
PluginStates = {
bigbluebutton.Enable = true;
"com.github.matterpoll.matterpoll".Enable = true;
};
};
@ -158,8 +176,6 @@
MetricsSettings.Enable = false;
GuestAccountsSettings.Enable = false;
FeatureFlags.CollapsedThreads = true;
SqlSettings.DriverName = "postgres";
SqlSettings.DataSource = "postgres:///mattermost?host=/run/postgresql";
};
# turn of the weirder parts of this module (which insist on passwords
@ -170,6 +186,17 @@
localDatabaseCreate = false;
};
services.mysql = {
enable = true;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensurePermissions = { "mattermost.*" = "ALL PRIVILEGES"; };
} ];
package = pkgs.mysql80;
dataDir = "/persist/mysql";
};
services.postgresql = {
enable = lib.mkForce true; # mattermost sets this to false. wtf.
package = pkgs.postgresql_15;
@ -182,16 +209,16 @@
authentication = lib.mkForce ''
# Generated file; do not edit!
local all all trust
host mattermost mattermost ::1/128 trust
'';
};
services.postgresqlBackup = {
enable = true;
databases = [ "mattermost" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
};
});
};
services.nginx.virtualHosts."mattermost.infra4future.de" = {

View file

@ -1,64 +0,0 @@
{ config, options, lib, pkgs, ... }:
let
checkHash = pkgs.writeScriptBin "check-commit-hash" ''
#!${lib.getExe pkgs.fish}
set wanted (${lib.getExe pkgs.curl} -s https://git.infra4future.de/api/v1/repos/hacc/haccfiles/branches/main \
-H 'accept: application/json' | jq -r .commit.id)
if test $status != 0
echo "could not reach git.infra4future.de"
exit 2
end
set actual (cat /etc/haccfiles-commit)
if test $status != 0
echo "/etc/haccfiles-commit does not exist??"
exit 2
end
if test $actual != $wanted
echo "parsons was built on $actual, but commit on main is $wanted"
exit 1
end
'';
checkDeployAge = pkgs.writeScriptBin "check-deploy-age" ''
#!${lib.getExe pkgs.fish}
set date (date +%s)
# we do this indirection here so monit's config won't change on each deploy
set deploytimestamp (cat /etc/haccfiles-timestamp)
set age (expr $date - $deploytimestamp)
if test $age -ge (expr 3600 \* 24 \* 10)
echo "${config.networking.hostName} has not been deployed since 10 days, perhaps someone should do updates?"
exit 1
end
'';
in
{
mailserver.monitoring = {
enable = true;
alertAddress = "admin@hacc.space";
config = (lib.replaceStrings ["port 22"] ["port ${toString (lib.head config.services.openssh.ports)}"] options.mailserver.monitoring.config.default);
};
services.monit.config = ''
check host onlyoffice with address onlyoffice.infra4future.de
start program "/run/current-system/sw/bin/lxc-start -n onlyoffice -f /persist/lxc/onlyoffice/config"
stop program "/run/current-system/sw/bin/lxc-stop -n onlyoffice"
if failed port 443 protocol https status = 302
then restart
check program deployed-commit-on-main path ${lib.getExe checkHash}
if status == 1 for 64 cycles then alert
if status == 2 for 3 cycles then alert
check program is-system-running path ${pkgs.systemd}/bin/systemctl is-system-running
if status != 0 then alert
check program check-deploy-age path ${lib.getExe checkDeployAge}
if status == 1 then alert
'';
}

View file

@ -1,9 +1,19 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
{
containers.nextcloud.timeoutStartSec = "10 min";
hacc.containers.nextcloud = {
config = { config, lib, pkgs, ... }: {
containers.nextcloud = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.2";
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/nextcloud";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
environment.systemPackages = [ pkgs.htop ];
services.nextcloud = {
@ -11,7 +21,7 @@
# must be set manually; may not be incremented by more than one at
# a time, otherwise nextcloud WILL break
package = pkgs.nextcloud29;
package = pkgs.nextcloud27;
home = "/persist/nextcloud";
https = true;
@ -39,7 +49,7 @@
"pm.start_servers" = "2";
};
settings = {
extraOptions = {
instanceid = "ocxlphb7fbju";
datadirectory = "/persist/nextcloud/data";
loglevel = 0;
@ -72,7 +82,7 @@
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
};
});
};
services.nginx.virtualHosts."cloud.infra4future.de" = {

View file

@ -1,14 +1,76 @@
{ config, lib, pkgs, ... }:
let
cfg = config.networking.firewall;
mkPorts = ports: ranges:
lib.strings.concatStringsSep ", "
(map ({from, to}: "${toString from}-${toString to}") ranges
++
map toString ports);
in
{
networking.firewall.enable = true;
networking.firewall.logRefusedConnections = false;
networking.nat.enable = true;
networking.firewall.enable = false;
networking.nat.enable = false;
boot = {
kernelModules = [ "nf_nat_ftp" ];
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = true;
"net.ipv4.conf.default.forwarding" = true;
};
};
networking.nftables.enable = true;
networking.nftables.tables.nat = {
family = "ip";
content = ''
networking.nftables = {
enable = true;
ruleset = ''
table inet filter {
chain input {
type filter hook input priority filter
policy drop
icmpv6 type {
echo-request,
echo-reply,
mld-listener-query,
mld-listener-report,
mld-listener-done,
nd-router-advert,
nd-neighbor-solicit,
nd-neighbor-advert,
packet-too-big
} accept
icmp type echo-request accept
ct state invalid drop
ct state established,related accept
iifname { lo } accept
tcp dport { ${mkPorts cfg.allowedTCPPorts cfg.allowedTCPPortRanges} } accept
udp dport { ${mkPorts cfg.allowedUDPPorts cfg.allowedUDPPortRanges} } accept
# DHCPv6
ip6 daddr fe80::/64 udp dport 546 accept
counter
}
chain output {
type filter hook output priority filter
policy accept
counter
}
chain forward {
type filter hook forward priority filter
policy accept
counter
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100
iifname enp35s0 tcp dport { 22 } dnat ${config.containers.forgejo.localAddress}:22
@ -18,6 +80,7 @@
iifname lxcbr0 oifname enp35s0 masquerade
iifname ve-* oifname enp35s0 masquerade
}
}
'';
};
}

View file

@ -1,137 +0,0 @@
{ config, lib, pkgs, ... }:
{
sops.secrets = {
"s4f-conference/env" = {};
};
hacc.containers.s4f-conference = {
bindSecrets = true;
config = { config, lib, pkgs, ... }: {
systemd.services.mattermost.serviceConfig.EnvironmentFile =
lib.mkForce "/secrets/env";
services.mattermost = {
enable = true;
siteUrl = "https://s4f-conference.infra4future.de";
siteName = "Scientists for Future Chat";
listenAddress = "0.0.0.0:3000";
mutableConfig = false;
statePath = "/persist/mattermost";
extraConfig = {
ServiceSettings = {
TrustedProxyIPHeader = [ "X-Forwarded-For" "X-Real-Ip" ];
EnableEmailInvitations = true;
};
TeamSettings = {
EnableUserCreation = true;
MaxUsersPerTeam = 2500;
EnableUserDeactivation = true;
EnableOpenServer = false;
};
PasswordSettings = {
MinimumLength = 10;
};
FileSettings = {
EnableFileAttachments = true;
MaxFileSize = 52428800;
DriverName = "local";
Directory = "/persist/upload-storage";
EnablePublicLink = true;
PublicLinkSalt = "3k7p3yxdhz6798b3b9openfr9rn3ymwu";
};
EmailSettings = {
EnableSignUpWithEmail = true;
EnableSignInWithEmail = true;
EnableSignInWithUsername = true;
SendEmailNotifications = true;
FeedbackName = "mattermost";
FeedbackEmail = "mattermost@infra4future.de";
ReplyToAddress = "mattermost@infra4future.de";
FeedbackOrganization = "infra4future.de";
EnableSMTPAuth = true;
SMTPUsername = "noreply@infra4future.de";
SMTPServer = "mail.hacc.space";
SMTPPort = "465";
SMTPServerTimeout = 10;
ConnectionSecurity = "TLS";
};
RateLimitSettings.Enable = false;
PrivacySettings = {
ShowEmailAddress = false;
ShowFullName = true;
};
# to disable the extra landing page advertising the app
NativeAppSettings = {
AppDownloadLink = "";
AndroidAppDownloadLink = "";
IosAppDownloadLink = "";
};
LogSettings = {
EnableConsole = true;
ConsoleLevel = "ERROR";
EnableDiagnostics = false;
EnableWebhookDebugging = false;
};
SupportSettings = {
TermsOfServiceLink = "https://infra4future.de/nutzungsbedingungen.html";
PrivacyPolicyLink = "https://infra4future.de/nutzungsbedingungen.html";
AboutLink = "https://infra4future.de";
SupportEmail = "info@infra4future.de";
CustomTermsOfServiceEnabled = false;
EnableAskCommunityLink = true;
};
AnnouncementSettings.EnableBanner = false;
ComplianceSettings.Enable = false;
ClusterSettings.Enable = false;
MetricsSettings.Enable = false;
GuestAccountsSettings.Enable = true;
};
localDatabaseCreate = false;
};
services.postgresql = {
enable = lib.mkForce true; # mattermost sets this to false. wtf.
package = pkgs.postgresql_15;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensureDBOwnership = true;
} ];
authentication = lib.mkForce ''
# Generated file; do not edit!
local all all trust
host mattermost mattermost ::1/128 trust
'';
};
services.postgresqlBackup = {
enable = true;
databases = [ "mattermost" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
};
};
services.nginx.virtualHosts."s4f-conference.infra4future.de" = {
locations."/" = {
proxyPass = "http://${config.containers.s4f-conference.localAddress}:3000";
proxyWebsockets = true;
extraConfig = ''
# Mattermost CSR Patch
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
proxy_redirect off;
client_max_body_size 100M;
'';
};
forceSSL = true;
enableACME = true;
};
}

View file

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
let
tracktrain-config = ''
@ -12,12 +12,8 @@ let
login:
enable: true
url: https://login.infra4future.de
clientName: tracktrain
# clientSecret defined in env file
logging:
ntfyTopic: ping.stuebinm.eu/monit
name: ilztalbahn
clientname: tracktrain
# clientsecret defined in env file
'';
in
{
@ -29,14 +25,14 @@ in
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${config.containers.tracktrain.localAddress}:4000";
proxyPass = "http://192.168.42.41:4000";
proxyWebsockets = true;
};
# note: this shadows the /metrics endpoint of tracktrain
# in case you remove this, please consider putting something
# else here to keep it from being publicly scrapable
locations."/metrics/" = {
proxyPass = "http://${config.containers.tracktrain.localAddress}:2342";
proxyPass = "http://192.168.42.41:2342";
proxyWebsockets = true;
extraConfig = ''
rewrite ^/metrics/(.*) /$1 break;
@ -44,10 +40,28 @@ in
};
};
hacc.containers.tracktrain = {
bindSecrets = true;
containers.tracktrain = {
privateNetwork = true;
hostAddress = "192.168.42.40";
localAddress = "192.168.42.41";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/tracktrain";
isReadOnly = false;
};
"/secrets".hostPath = "/run/secrets/tracktrain";
};
config = { config, lib, pkgs, ... }: {
path = evalConfig ({ config, lib, pkgs, ... }: {
system.stateVersion = "21.11";
users.users.tracktrain = {
group = "tracktrain";
isSystemUser = true;
};
users.groups.tracktrain = {};
systemd.services.tracktrain = {
enable = true;
@ -59,18 +73,22 @@ in
serviceConfig = {
Type = "simple";
EnvironmentFile = "/secrets/env";
DynamicUser = true;
User = "tracktrain";
Group = "tracktrain";
};
path = [ pkgs.wget pkgs.ntfy-sh ];
path = [ pkgs.wget ];
script = ''
cd /tmp
mkdir -p /persist/tracktrain
cd /persist/tracktrain
ln -sf ${pkgs.writeText "tracktrain-config.yaml" tracktrain-config} config.yaml
wget "https://ilztalbahn.eu/wp-content/uploads/2020/07/gtfs.zip" || sleep 4; wget "https://ilztalbahn.eu/wp-content/uploads/2020/07/gtfs.zip"
${pkgs.tracktrain}/bin/tracktrain +RTS -T
'';
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_15;
ensureDatabases = [ "tracktrain" ];
ensureUsers = [ {
@ -79,6 +97,7 @@ in
} ];
authentication = ''
local all all trust
host all all 127.0.0.1/32 trust
'';
};
@ -93,10 +112,46 @@ in
} ];
};
systemd.services.grafana.serviceConfig.EnvironmentFile =
"/secrets/env";
hacc.bindToPersist = [ "/var/lib/grafana" ];
services.grafana = {
enable = true;
settings.server = {
serve_from_sub_path = true;
domain = "tracktrain.ilztalbahn.eu";
root_url = "https://%(domain)s/metrics/";
http_port = 2342;
http_addr = "0.0.0.0";
};
settings."auth.generic_oauth" = {
name = "uffd";
enabled = true;
allow_sign_up = true;
empty_scopes = true;
client_id = "ilztalbahn-grafana";
client_secret = "\${GRAFANA_CLIENT_SECRET}";
auth_url = "https://login.infra4future.de/oauth2/authorize";
token_url = "https://login.infra4future.de/oauth2/token";
api_url = "https://login.infra4future.de/oauth2/userinfo";
};
# disables the default login screen. comment out if for some
# reason you do need it
settings.auth.oauth_auto_login = true;
settings.users.auto_assign_org_role = "Admin";
provision = {
enable = true;
datasources.settings.datasources = [ {
url = "http://localhost:9001";
type = "prometheus";
name = "prometheus";
} ];
};
};
systemd.services.grafana.serviceConfig.EnvironmentFile =
"/secrets/env";
hacc.bindToPersist = [ "/var/lib/grafana" ];
});
};
}

View file

@ -1,8 +1,19 @@
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, evalConfig, ... }:
{
hacc.containers.uffd = {
config = { config, lib, pkgs, ... }: {
containers.uffd = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.9";
autoStart = true;
ephemeral = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/uffd";
isReadOnly = false;
};
};
path = evalConfig ({ config, lib, pkgs, ... }: {
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
@ -18,7 +29,7 @@
hook-pre-app = "exec:FLASK_APP=${pkgs.uffd}/lib/python3.10/site-packages/uffd flask db upgrade";
};
};
};
});
};
services.nginx.virtualHosts."login.infra4future.de" = {
enableACME = true;
@ -43,21 +54,62 @@
after = [ "network.target" ];
serviceConfig.Type = "simple";
path = [ pkgs.fish pkgs.curl pkgs.jq ];
script = "${pkgs.hacc-scripts}/bin/uffd-sync-mattermost-groups.fish";
startAt = "*:0/15";
};
systemd.services.uffd-account-expiry-notification = {
enable = true;
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.Type = "simple";
path = [ pkgs.hacc-scripts pkgs.sqlite-interactive pkgs.postfix ];
script = ''
uffd-unused-accounts-notification.scm -v admin
script = (pkgs.writeTextFile {
name = "auamost.fish";
executable = true;
checkPhase = ''
${lib.getExe pkgs.fish} -n $target
'';
startAt = "weekly";
restartIfChanged = false;
text = ''
#!${lib.getExe pkgs.fish}
source /run/secrets/auamost/secrets.fish
for i in (seq 1 (count $groups))
set team $teams[$i]
set group $groups[$i]
set users (curl -u $uffd_token --basic https://login.infra4future.de/api/v1/getusers -d group="$group")
set usernames (echo "$users" | jq -c "[.[] | .loginname]")
for user in (echo "$users" | jq -c ".[]")
set id (echo "$user" | jq .id)
set username (echo "$user" | jq .loginname)
set email (echo "$user" | jq .email)
curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users \
-d '{"email": '"$email"', "username": '"$username"', "auth_service": "gitlab", "auth_data": "'"$id"'"}'
end
set userids (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/usernames \
-d "$usernames" | jq '[.[] | {user_id: .id, team_id: "'$team'"} ]')
curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/batch \
-d "$userids"
if test "$group" = "hacc"
continue
end
set current_members (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members | jq '[.[] | .user_id]')
# membership relations don't contain e.g. usernames, so fetch those, too
set current_users (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/ids \
-d "$current_members" | jq -c '.[]')
set userids (echo "$userids" | jq -c ".[].user_id")
for member in $current_users
set id (echo $member | jq .id)
if not contains -i $id $userids > /dev/null then
set id_unquoted (echo $member | jq -r .id)
echo removing $id_unquoted (echo $member | jq '.email') from $team \($group\)
curl -X DELETE -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/"$id_unquoted"
end
end
end
'';
}).outPath;
startAt = "*:0/15";
};
sops.secrets."auamost/secrets.fish" = { };

View file

@ -13,25 +13,14 @@ let
buildGoModule = unstable.buildGo122Module;
};
morph = callPackage ./morph.nix {
buildGoModule = unstable.buildGo122Module;
};
forgejo = unstable.forgejo;
tracktrain = import sources.tracktrain {
nixpkgs = unstable;
nixpkgs = pkgs;
compiler = "default";
};
uffd = oldstable.callPackage ./uffd { };
hacc-scripts = callPackage ./scripts {};
inherit (oldstable) uwsgi flask;
# TODO: once on nixos 24.05, remove this inherit
inherit (unstable) lix;
};
in pkgs.extend(_: _: newpkgs)

View file

@ -12,13 +12,13 @@ buildGoModule rec {
# See https://docs.mattermost.com/upgrade/extended-support-release.html
# When a new ESR version is available (e.g. 8.1.x -> 9.5.x), update
# the version regex in passthru.updateScript as well.
version = "9.11.5";
version = "9.5.3";
src = fetchFromGitHub {
owner = "mattermost";
repo = "mattermost";
rev = "v${version}";
hash = "sha256-bLZFeG6kBVP0ws50wtBam/bO206sQnz6va8PATAoRAQ=";
hash = "sha256-kqwRwo7eL9xfOyP54oS800L6bisVwJf9FpgTnwfmjAo=";
};
# Needed because buildGoModule does not support go workspaces yet.
@ -34,10 +34,10 @@ buildGoModule rec {
webapp = fetchurl {
url = "https://releases.mattermost.com/${version}/mattermost-${version}-linux-amd64.tar.gz";
hash = "sha256-jyaJUN8wpuBivKNdm7f1mYwygO8xC+Zxy0SdkDovdsA=";
hash = "sha256-f2Zap/15TOyzCP97BGGmXimwAa1mTP42w37RToNkAsQ=";
};
vendorHash = "sha256-Gwv6clnq7ihoFC8ox8iEM5xp/us9jWUrcmqA9/XbxBE=";
vendorHash = "sha256-TJCtgNf56A1U0EbV5gXjTro+YudVBRWiSZoBC3nJxnE=";
modRoot = "./server";
preBuild = ''
@ -45,7 +45,6 @@ buildGoModule rec {
'';
subPackages = [ "cmd/mattermost" ];
offlineCache = webapp;
tags = [ "production" ];
@ -70,7 +69,7 @@ buildGoModule rec {
passthru = {
updateScript = nix-update-script {
extraArgs = [ "--version-regex" "^v(9\.11\.([0-9.]+))" ];
extraArgs = [ "--version-regex" "^v(9\.5\.([0-9.]+))" ];
};
tests.mattermost = nixosTests.mattermost;
};
@ -78,7 +77,7 @@ buildGoModule rec {
meta = with lib; {
description = "Mattermost is an open source platform for secure collaboration across the entire software development lifecycle";
homepage = "https://www.mattermost.org";
license = with licenses; [ agpl3Only asl20 ];
license = with licenses; [ agpl3 asl20 ];
maintainers = with maintainers; [ ryantm numinit kranzes mgdelacroix ];
mainProgram = "mattermost";
};

View file

@ -1,33 +0,0 @@
{ buildGoModule
, fetchFromGitHub
}:
buildGoModule rec {
pname = "mattermost-morph";
version = "1.1.0";
src = fetchFromGitHub {
owner = "mattermost";
repo = "morph";
rev = "v${version}";
hash = "sha256-Orh/a9OlUVIlDdLXRpDAnHUmWRiM1N2oO+dijbuJzx8=";
};
vendorHash = null;
subPackages = [ "cmd/morph" ];
tags = [ "production" ];
ldflags = [
"-s"
"-w"
"-X github.com/mattermost/mattermost/server/public/model.Version=${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildNumber=${version}-nixpkgs"
"-X github.com/mattermost/mattermost/server/public/model.BuildDate=1970-01-01"
"-X github.com/mattermost/mattermost/server/public/model.BuildHash=v${version}"
"-X github.com/mattermost/mattermost/server/public/model.BuildHashEnterprise=none"
"-X github.com/mattermost/mattermost/server/public/model.BuildEnterpriseReady=false"
];
}

View file

@ -1,16 +0,0 @@
{ stdenvNoCC, gauche, fish }:
stdenvNoCC.mkDerivation {
name = "hacc-utility-scripts";
src = ./.;
buildInputs = [ gauche fish ];
installPhase = ''
mkdir -p $out/bin
fish -n $out/bin/*.fish
cp *.{scm,fish} $out/bin
chmod +x $out/bin/*
'';
}

View file

@ -1,47 +0,0 @@
#!/usr/bin/env fish
source /run/secrets/auamost/secrets.fish
for i in (seq 1 (count $groups))
set team $teams[$i]
set group $groups[$i]
set users (curl -u $uffd_token --basic https://login.infra4future.de/api/v1/getusers -d group="$group")
set usernames (echo "$users" | jq -c "[.[] | .loginname]")
for user in (echo "$users" | jq -c ".[]")
set id (echo "$user" | jq .id)
set username (echo "$user" | jq .loginname)
set email (echo "$user" | jq .email)
curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users \
-d '{"email": '"$email"', "username": '"$username"', "auth_service": "gitlab", "auth_data": "'"$id"'"}'
end
set userids (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/usernames \
-d "$usernames" | jq '[.[] | {user_id: .id, team_id: "'$team'"} ]')
curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/batch \
-d "$userids"
if test "$group" = "hacc"
continue
end
set current_members (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members | jq '[.[] | .user_id]')
# membership relations don't contain e.g. usernames, so fetch those, too
set current_users (curl -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/users/ids \
-d "$current_members" | jq -c '.[]')
set userids (echo "$userids" | jq -c ".[].user_id")
for member in $current_users
set id (echo $member | jq .id)
if not contains -i $id $userids > /dev/null then
set id_unquoted (echo $member | jq -r .id)
echo removing $id_unquoted (echo $member | jq '.email') from $team \($group\)
curl -X DELETE -H $mattermost_token \
-H "Content-Type: application/json" https://mattermost.infra4future.de/api/v4/teams/"$team"/members/"$id_unquoted"
end
end
end

View file

@ -1,121 +0,0 @@
#!/usr/bin/env gosh
(use gauche.process)
(use text.csv)
(use scheme.list)
(use gauche.parseopt)
(use util.match)
(define cutoff-date "2023-01-01")
(define sqlite-path "/persist/containers/uffd/uffd/db.sqlite")
(define sqlite-query
"select displayname, mail, max(expires) as last_login from oauth2token join user on user_id=user.id group by user_id having last_login < '2023-01-01'
union all select displayname, mail, '2022' from user where not exists (select * from oauth2token where user_id = user.id);")
(define dry #f)
(define verbose #f)
(define very-verbose #f)
(define (main args)
(let-args (cdr args)
((averbose "v|verbose")
(averyverbose "very-verbose")
(adry "n|dry-run")
(help "h|help" => (cut show-help (car args)))
. restargs
)
(set! dry adry)
(set! verbose averbose)
(when averyverbose
(set! verbose #t)
(set! very-verbose #t))
(match restargs
[("admin") (do-admin-mail)]
[("send-reminder") (send-reminder-mails)]
[("list-accounts") (do-list-accounts)]
[_ (display "unknown command") (exit 1)]))
0)
(define (do-admin-mail)
(send-email "admin@hacc.space" "unused accounts list" (mk-admin-mail unused-accounts))
(when verbose
(display "done")))
(define (do-list-accounts)
(display (string-join
(map
(lambda (row) (format "~a (~a)" (list-ref row 0) (list-ref row 1)))
unused-accounts)
"\n")))
(define (send-reminder-mails)
(map (lambda (row)
(send-email (list-ref row 1) "Unbenutzter infra4future.de Account" (mk-email (list-ref row 0) (list-ref row 2))))
unused-accounts)
(when verbose
(display "done")))
(define csv-reader
(make-csv-reader #\,))
(define unused-accounts
(map (lambda (str) (with-input-from-string str csv-reader))
;; (process-output->string-list `(cat example.csv))))
(process-output->string-list `(sqlite3 -csv ,sqlite-path ,sqlite-query))))
(define (mk-email displayname last-login)
#"
Hallo ~|displayname|!
Wir haben schon lange (seit über einem Jahr; dein letzter Login war um ~|last-login|)
nichts mehr von dir gehört und würden demnächst deinen Account löschen wollen.
Solltest du ihn noch benötigen logge dich bitte einfach auf https://login.infra4future.de ein.
Falls nicht, musst du weiter nichts tun und wir werden deine Account in ca. 3 Monaten löschen.
Viele Grüße,
das Infra4Future Team
")
(define (mk-admin-mail rows)
(format #"
Meow!
this is the uffd-unused-accounts-notification.scm script. There are currently
~~s accounts which have not logged in since ~|cutoff-date|. To mass-send account
expiry reminders, invoke this script with the \"send-reminder\" option. To see a
list of these accounts, invoke it with the \"list-accounts\" option.
(invoke me,, 🥺)
" (length unused-accounts)))
; utility definitions
(define (send-email address subject text)
(when verbose
(display (format "sending email to ~a\n" address)))
(let ([text (string-append "from: admin@hacc.space\n" "subject: " subject "\n" text "\n")])
(when very-verbose
(display text))
(call-with-output-process
(if dry '(cat) `(sendmail ,address))
(lambda (port) (display text port))
:on-abnormal-exit :ignore)))
(define (show-help progname)
(display #"
~|progname|: unused account expiry helper script.
Invoke as `~|progname| [options] admin' to send a list of unused accounts to administrators.
Invoke as `~|progname| [options] send-reminder' to send a reminder email to all
currently unused accounts.
Options:
-v --verbose show which emails are being sent
--very-verbose also print emails to stdout
-n --dry-run print emails to stdout instead
-h --help show this help
"))

View file

@ -1,13 +1,13 @@
hedgedoc-hacc:
env: ENC[AES256_GCM,data:e2vSolxJNucya9QNs28gAVDBJQq5AJh7jS1nBh0UTkDnhNL8NPW1KTxcun4rM99EhiNZsz6Z9qHRMejmP4frQw==,iv:DqAGhGWYf/EpGnI79MxKmBlHMhK26zx50vXb1TbvESw=,tag:Xix499XAcAmxhNuGr2ApcA==,type:str]
mattermost:
env: ENC[AES256_GCM,data:ftWpGl6+sUMzJJKgfcPLvbFGGn16AKUPzPn8X6DNVMLrxZIkQ23Tk3ekKLKFpQEUtQfFjVlrTfFZezWKs4nVNLg2LmQqJNGMCCax5PRwAgoAsJ7pa9ewNmHT+EIXtZEjQgVfN5786Yno5n/6JJ1lz6EiGmdn7/0rF5TLGjzig17azazS1+lkIYY=,iv:SZvGGKpVRI/odHbmgY8M6t6zCk8RgM+7EQEgRiizglA=,tag:cInsVo/QD85m+LxldyRlnA==,type:str]
env: ENC[AES256_GCM,data:4GcV8UOYmVUjZoYc0Nq/vEWtxtYNV81zVTEyFnZIfY1k/Ar1MU+fn5A99JLIMc8U84/QupDU7TcneiN/wqPv2jYqGS7ixSNTk+x5uUPMarzKZ04ynav6FCWEvlSF0Sz4/5s/Pvp1Qi3zdv16ZVGUHbM8/wCcaZBkSS0ofwBTIXVsVYSRPFxLehtBgwjAnD46qS+YJmszmd7V5N/adWWF34vAdfLiO6Y7KDB3jnMLOPU6Drtw9L83AW6NuOtk8crZrI1dkTD/xUC07IvMhZpZVc9ktQJqIvlk/ADs5aIp/QYrjICdYvb8xC16oV7jC/7yzXzC/UuYbCvS5gnHGMK/CsBkmM9HXmQ6mWjrfuOJEkMHSefS7O8HyrNoNDSXq0ivCr6KJmwrz7NXNAE6a6xx9LMjs5DJ8H5fda1l5TGVAdA2tg==,iv:dG4cnEtUgUxw7zS2k15p+6//Bl19WquTfFIiz5Vi/0M=,tag:cMBU8CtFBBjfcfpO709Kpg==,type:str]
tracktrain:
env: ENC[AES256_GCM,data:W3+8qWomPgGJt5u50aAm9x/dilMpqKY11I2AdaIBTz5posc25ts0LB5S/Sxe1ROz4itpDK3QvjoFUTRhS39k4dwMr5lqXV8Ln4B+sPpvh7oBM8A5zydP8Jj1J1YqRt8++RTUmb4z41DIwb/yaZKMu6z0guXIu1yuYzcbCuk0xe/iOp6UUpfjOzzWTvxY54zY6kWcjHLiCSwD31Cd+MxMPfbUEkHt+0W+sBmYXGeEFI/6ULSB6FnGjNW6F9g=,iv:3ymah8HG+Yg6VYZZA/MRRjHDYvYJz01ezvhfQiftegg=,tag:trht+PRYfKgWJkg2wRwISQ==,type:str]
env: ENC[AES256_GCM,data:jaq039FNxBrsPfG/q+InYpiyl1LBdY++DlLM6UpSAwKlINucooTrHz51QrdRWhAZDqXhVTHM55Q/Zm4wazweCABiNjkXDFoZgxc5YJX+pvBct6M533xl109yD6KiYOXDqPY03u71aop8OmOAnKDp1JlzPS1otdlaN8Vd56G+,iv:nYU2rgMMG4QcJo5DnZpYZm1zr82idd7r1uTsqNiXLdA=,tag:9rdxAneYUREacXNunpTuHw==,type:str]
vaultwarden:
env: ENC[AES256_GCM,data:hdm91tI8WBd3es+IUbdBO69kh1pNZTNvZNFIdSZO8lm4yYMPE+Jm7EzVqwOaZRbpQaVDBg7uh5P4ODc=,iv:no7U0wQCwZOeL2pwXf2pUIgrEsEOYwqOT04LvpCl614=,tag:AGSu5M7H69x6pDM062bC6g==,type:str]
auamost:
secrets.fish: ENC[AES256_GCM,data:QBteJdVPSWa4cmu1BVWJ3AMWWH4zIv2+G83fK0QsbA/fYoIU5jobCT3USyujNz+jQaAAxA45jmQbCWNAFLl1q8hP4i9EIikVECx0VKVXPXILBND+w7zPSLldAbOugRYt2iAt1dDADZPtulKlkz7usdafbB+2igLXdyFRLfIxDTOrBuqQ+5yeofQe5k0XWRcmQQ/1AV0JrRrmLmr69VKsR932JWD8XxmI/HFyZPzWdExBSOmvnj+m4K+DV4cVmN4t6XOY0dM3gRQ95DglEuGlp/V2o3GqwY0mXCvhM1eh81u8mPALKp6Pv2i2yU35F01Puf5t1FHGDfzp0bW0xuKEywfGjAOifFkSE/3JFir434B6G0DiJNpOIl6QJ6DA8rSKfuPdccm6Or0zX8iJGRHDJmREQ05V9l0jHAAxLNuNdbsxg+8kCWVVnW+d1YDn9KW7LbFlP+sx4Ef5leUYft/lYhF4Z5Xp3arqVrlebWjWIBEuZeJTnkE3y+TdUUCs360zzWHqsipGmo1+/88CEqL52FfUOlJ4VCR45/7nYZ3RaRBWDGFW8RvwmWSFSstEcEXQ01U8lCwyn40+blfltme3KJ1f+pWMrZAKhPlOlMHCYfjd7esWI2sYcQbTZqxH49GnW6dsW/W+eiLs3zlD/Deb2CugHe63zRdlivmVPOz4zD1PXcCVpEZHoTTiJl7Om9K2mPYq9wQN41wsDUrNL9p8m9UlhWKbjBh5UU7p6F6OhF5rKH/Fs8fIaPi6B8uamTvEmiOGTUWl3vmQjBvhM8fJWoIkRB8hgCisr9OZ,iv:8jVAImjeXbXfiLKg9G0PyLMTV8cAyDmukeittqjKFpQ=,tag:fLIcsWKbdFQ/vPCgi/W3Zw==,type:str]
secrets.fish: ENC[AES256_GCM,data:Dyb0Byigh4tmkmdz7KxkgvudO830x8+1qNQBOT+ohydOY3OeuJseJQ/rjaYhMTfh6tcKpu1aSarKRINbJp2u0yu+eazVV69CRzu9OlsXaMD6Rbvw4Cn0LttJhjK1za8+fXm7IZsAhErrV6WmU1/JryQkZf18hxMrO5EBmFy4ONHNj3lc4pApMUqXLiVL6xaW+Mix+jx4gT8r0/0lpAdT5oObPPBo+HIDJEGj+QPBvxNBJaURKVRX5+8fe4+hFzqBjU7QJ/LLPBo2lp2BLgo39qCeLaHogkWMXEYPb4/eaW0SZ8/Z56gh7dsO5X1r8kSAEMDoYVCC6KrXDh2M48/lYT+biid8iALCphatpZzH9CbV0FWIcZ5s0q8fApTZ1ubtiVqRNN1niGajgLGe5TSQcPAQs1yCBQ+9BJSDro9qNNXXlVpHO59Dfs2w+f2FBBQOnOIqhxQPbyhzIep3kRuIH42rowGG66uOJaC7g1W5fCwkdBNDZK8D01nj1+PA17j3xExqTT4+m1oUSlROhDRgxf+nYWkuxaAM1z+FsTswFHzdBJ8wtK56z+dpBH2f3SNW/5bwMif00uS1z+6U4yuCl0sdh0SF/yLjbIyvMwPiy7xzaBEZ+bve6ps0yh1sYvyLN7vxs7tRhtN0yLs28ZeT5BEwJAiKP1+KWhK86XbKh3fMtfl5V06xyW4aBkeYC4cg2wSNlvlDrbIrtPsJMHQt/swsHvIde4AfEyzhrTs8ezuVRbm/9glTVh1mzw==,iv:MpaFGYbcTXdFabV+vlGyGxexpfP7LUpYYBjF6GVEN7c=,tag:n8qTOhnbBT7Xxz21bU0bYQ==,type:str]
restic:
s3creds.env: ENC[AES256_GCM,data:9WNu5S4KmdMXdshSpawEjIexAKH6vZCPwb9xyq6xmerly1lxSfFZzgg60M0L3L+I4joLTVi23YBB8Eh6Xfx9GgxNww7w7BjMCQs/X16ecDWlb346TKf+,iv:Gu4CbXXJAlQYXRqOjIAUYmn8EU4mrvcOVc2eCh1Ikzs=,tag:1xpVIonHiAGHsXTY9liPQQ==,type:str]
system: ENC[AES256_GCM,data:RIgO0QHVjwp2D3LoU62vLzepASdsXxu0DqUTA6Voa3K1d4xFHX2u+UR8AcqR,iv:O0K8i5ivne7WU+ygDEUcrvKW6DIfXjVPY63gpfsxEFE=,tag:n/1atQ5qlyB0SMHrYiTCrA==,type:str]
@ -98,8 +98,8 @@ sops:
bndBTXJhQVE2OVlKeGNTbzJlL0duUzAKIWdesesYvBIN/m36fhzxq30+IT8qp/pF
S6i7QqZF75y2BpEoupRCqNIAsHrouUE+U9ZQJZO8m9J591mWvbVJIw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-07-26T13:05:44Z"
mac: ENC[AES256_GCM,data:9A8nX155dpCC1cvdH1hgeNKh0tt5FMaOKU7vZQ33jfWbiXOsJbp5iHKXxWOexFc70acyhdweoHwq61oJm2mzVufJIPA55ZAUItQcDXJCCeu6KswHug0tQtKHoCRSwdTdMTRNom4XjrpA/j4WWpuhoilyknycXqTpGHHVSdL2lYg=,iv:N0zwzGtGzAxhbmLzslbkXSr/iKmq5FeyT/iWeE4x2hQ=,tag:yIoLXpqlU2SlVRK5+S/qaw==,type:str]
lastmodified: "2024-01-28T14:09:53Z"
mac: ENC[AES256_GCM,data:d0DlofJdafS2t0FLd+3wb8XC6GIhGqHjT0kc6th2axirYCiFX22okD0MCWhDT2+T8NRe0c4wLOKuS1EOgmjZYjGIVZ2Hhf/at00VMkPM2koemCpR0zLSfrBGrcY8VkBQ2s5UgU2L9O7nD0KBdPoruRo0MRbcwrCzOX+sBk24yaQ=,iv:V5C1wK9zeMcT6E9sZSUtofNpToKi5xkiG/HesozOE5c=,tag:XihqjZnOB7G3gi2FpJHpJg==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1

View file

@ -1,21 +1,27 @@
{ copyPathToStore, stdenvNoCC, zola, writeShellScriptBin }:
{ stdenvNoCC, zola, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "docs.hacc.space-static";
src = ./.;
content = copyPathToStore ../../docs;
# HINT: this is cursed. Nix flakes have no optimisation to deal with ${./.},
# so we wind up having to do this to make the symlink to content/ work.
# (we still need to manually adjust it — but at least this way we can find
# its target without further hoops)
#
# This does also mean we now copy the entire flake into the Nix store twice.
# Yay for flakes!
src = "${../../.}/websites/docs.hacc.space";
phases = [ "buildPhase" ];
buildInputs = [ zola ];
buildPhase = ''
cp -r $src/* .
rm content
ln -s $content content
ln -s $src/../../docs content
zola build --output-dir $out
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/docs.hacc.space
${zola}/bin/zola serve --output-dir /tmp/hacc-docs "$@"
'';

View file

@ -1,4 +1,4 @@
{ stdenvNoCC, sfz, writeShellScriptBin }:
{ stdenvNoCC, sfz, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "hacc.earth-static";
@ -13,7 +13,7 @@ stdenvNoCC.mkDerivation rec {
rm $out/default.nix
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/hacc.earth
${sfz}/bin/sfz "$@"
'';

View file

@ -1,4 +1,4 @@
{ stdenvNoCC, sfz, writeShellScriptBin }:
{ stdenvNoCC, sfz, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "muc.hacc.earth-static";
@ -13,7 +13,7 @@ stdenvNoCC.mkDerivation rec {
rm $out/default.nix
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/help.studentsforfuture.info
${sfz}/bin/sfz "$@"
'';

View file

@ -1,4 +1,4 @@
{ jekyll, stdenvNoCC, writeShellScriptBin }:
{ jekyll, stdenvNoCC, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "infra4future.de-static";
@ -11,7 +11,7 @@ stdenvNoCC.mkDerivation rec {
${jekyll}/bin/jekyll build -d $out --disable-disk-cache
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/infra4future.de
rm -rf /tmp/hacc-website
${jekyll}/bin/jekyll serve --disable-disk-cache -d /tmp/hacc-website "$@"

View file

@ -1,4 +1,4 @@
{ stdenvNoCC, sfz, writeShellScriptBin }:
{ stdenvNoCC, sfz, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "muc.hacc.earth-static";
@ -13,7 +13,7 @@ stdenvNoCC.mkDerivation rec {
rm $out/default.nix
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/muc.hacc.earth
${sfz}/bin/sfz "$@"
'';

View file

@ -1,4 +1,4 @@
{ jekyll, stdenvNoCC, writeShellScriptBin }:
{ jekyll, stdenvNoCC, writeScriptBin }:
stdenvNoCC.mkDerivation rec {
name = "mumble.infra4future.de-static";
@ -11,7 +11,7 @@ stdenvNoCC.mkDerivation rec {
${jekyll}/bin/jekyll build -d $out --disable-disk-cache
'';
watch = writeShellScriptBin "watch" ''
watch = writeScriptBin "watch" ''
cd $(git rev-parse --show-toplevel)/websites/mumble.infra4future.de
rm -rf /tmp/hacc-website
${jekyll}/bin/jekyll serve --disable-disk-cache -d /tmp/hacc-website "$@"