diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-21 09:24:30 +0200 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-21 09:24:30 +0200 |
commit | 75695d3e42bfe15483cefa43f316a4ae11a3bcca (patch) | |
tree | b4c17493825d4d6894fed3ea89c2255a17d9e529 | |
parent | 861a04827a19facd4ce0eb4693de43f64507df52 (diff) | |
download | nixos-75695d3e42bfe15483cefa43f316a4ae11a3bcca.tar nixos-75695d3e42bfe15483cefa43f316a4ae11a3bcca.tar.gz nixos-75695d3e42bfe15483cefa43f316a4ae11a3bcca.tar.bz2 nixos-75695d3e42bfe15483cefa43f316a4ae11a3bcca.tar.xz nixos-75695d3e42bfe15483cefa43f316a4ae11a3bcca.zip |
...
-rw-r--r-- | accounts/gkleen@sif/niri/waybar.nix | 1 | ||||
-rw-r--r-- | flake.nix | 6 | ||||
-rw-r--r-- | home-modules/nixpkgs-release-check.nix | 4 | ||||
-rw-r--r-- | hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py | 7 | ||||
-rw-r--r-- | hosts/surtr/email/default.nix | 105 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/.envrc | 4 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/.gitignore | 2 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py | 0 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py | 106 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/pyproject.toml | 18 | ||||
-rw-r--r-- | hosts/surtr/email/internal-policy-server/uv.lock | 119 | ||||
-rw-r--r-- | hosts/surtr/postgresql/default.nix | 17 | ||||
-rw-r--r-- | lib/pythonSet.nix | 28 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/default.nix | 25 | ||||
-rw-r--r-- | overlays/waybar-systemd-inhibit/default.nix | 31 | ||||
-rw-r--r-- | shell.nix | 2 |
16 files changed, 408 insertions, 67 deletions
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix index 1de2e1fa..c02a9a76 100644 --- a/accounts/gkleen@sif/niri/waybar.nix +++ b/accounts/gkleen@sif/niri/waybar.nix | |||
@@ -350,6 +350,7 @@ in { | |||
350 | } | 350 | } |
351 | #clock { | 351 | #clock { |
352 | /* margin-right: 5px; */ | 352 | /* margin-right: 5px; */ |
353 | font-feature-settings: "tnum"; | ||
353 | } | 354 | } |
354 | ''; | 355 | ''; |
355 | }; | 356 | }; |
@@ -363,7 +363,7 @@ | |||
363 | 363 | ||
364 | overlays = mapAttrs (_name: path: mkOverlay path) overlayPaths; | 364 | overlays = mapAttrs (_name: path: mkOverlay path) overlayPaths; |
365 | 365 | ||
366 | packages = forAllSystems (system: systemPkgs: nixImport rec { dir = ./tools; _import = _path: name: import "${toString dir}/${name}" ({ inherit system; } // inputs); }); | 366 | packages = forAllSystems (system: systemPkgs: nixImport rec { dir = ./tools; _import = name: _base: import (dir + "/${name}") ({ inherit system; } // inputs); }); |
367 | 367 | ||
368 | # packages = mapAttrs (_name: filterAttrs (_name: isDerivation)) packages; | 368 | # packages = mapAttrs (_name: filterAttrs (_name: isDerivation)) packages; |
369 | # packages' = mapAttrs (_name: filterAttrs (_name: value: !(isDerivation value))) packages; | 369 | # packages' = mapAttrs (_name: filterAttrs (_name: value: !(isDerivation value))) packages; |
@@ -375,6 +375,8 @@ | |||
375 | activateNixosConfigurations activateHomeManagerConfigurations | 375 | activateNixosConfigurations activateHomeManagerConfigurations |
376 | ]; | 376 | ]; |
377 | 377 | ||
378 | lib = nixImport rec { dir = ./lib; _import = name: _base: import (dir + "/${name}") inputs; }; | ||
379 | |||
378 | devShells = forAllSystems (system: systemPkgs: { default = import ./shell.nix ({ inherit system; } // inputs); } // installerShells system systemPkgs); | 380 | devShells = forAllSystems (system: systemPkgs: { default = import ./shell.nix ({ inherit system; } // inputs); } // installerShells system systemPkgs); |
379 | 381 | ||
380 | templates.default = { | 382 | templates.default = { |
@@ -398,7 +400,7 @@ | |||
398 | # path = activateHomeManager (self.nixosConfigurations.${hostname}.config.nixpkgs.system) usercfg.home; | 400 | # path = activateHomeManager (self.nixosConfigurations.${hostname}.config.nixpkgs.system) usercfg.home; |
399 | # }) self.nixosConfigurations.${hostname}.config.home-manager.users); | 401 | # }) self.nixosConfigurations.${hostname}.config.home-manager.users); |
400 | }) (nixImport { dir = ./hosts; _import = (_path: name: name); }); | 402 | }) (nixImport { dir = ./hosts; _import = (_path: name: name); }); |
401 | overrides = if pathExists ./deploy then nixImport { dir = ./deploy; _import = path: _name: import (./deploy + "/${path}") inputs; } else {}; | 403 | overrides = if pathExists ./deploy then nixImport rec { dir = ./deploy; _import = path: _name: import (dir + "/${path}") inputs; } else {}; |
402 | filterEnabled = attrs: mapAttrs (_n: v: filterAttrs (n: _v: n != "enabled") v) (filterAttrs (_n: v: v.enabled or true) attrs); | 404 | filterEnabled = attrs: mapAttrs (_n: v: filterAttrs (n: _v: n != "enabled") v) (filterAttrs (_n: v: v.enabled or true) attrs); |
403 | in mapAttrs (_n: v: if v ? "profiles" then v // { profiles = filterEnabled v.profiles; } else v) (filterEnabled (recursiveUpdate defaults overrides)); | 405 | in mapAttrs (_n: v: if v ? "profiles" then v // { profiles = filterEnabled v.profiles; } else v) (filterEnabled (recursiveUpdate defaults overrides)); |
404 | 406 | ||
diff --git a/home-modules/nixpkgs-release-check.nix b/home-modules/nixpkgs-release-check.nix new file mode 100644 index 00000000..baf2713a --- /dev/null +++ b/home-modules/nixpkgs-release-check.nix | |||
@@ -0,0 +1,4 @@ | |||
1 | { ... }: | ||
2 | { | ||
3 | config.home.enableNixpkgsReleaseCheck = false; | ||
4 | } | ||
diff --git a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py index 00182523..7117eb63 100644 --- a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py +++ b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py | |||
@@ -44,10 +44,9 @@ class PolicyHandler(StreamRequestHandler): | |||
44 | 44 | ||
45 | with conn.cursor() as cur: | 45 | with conn.cursor() as cur: |
46 | cur.row_factory = namedtuple_row | 46 | cur.row_factory = namedtuple_row |
47 | cur.execute('SELECT "mailbox"."mailbox" as "user", "local", "extension", "domain" FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) | 47 | cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) |
48 | for record in cur: | 48 | if (row := cur.fetchone()) is not None: |
49 | logger.debug('Received result: %s', record) | 49 | allowed = row.exists |
50 | allowed = True | ||
51 | 50 | ||
52 | action = '550 5.7.0 Sender address not authorized for current user' | 51 | action = '550 5.7.0 Sender address not authorized for current user' |
53 | if allowed: | 52 | if allowed: |
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix index 845f6455..c6253e4c 100644 --- a/hosts/surtr/email/default.nix +++ b/hosts/surtr/email/default.nix | |||
@@ -1,4 +1,4 @@ | |||
1 | { config, pkgs, lib, flakeInputs, ... }: | 1 | { config, pkgs, lib, flake, flakeInputs, ... }: |
2 | 2 | ||
3 | with lib; | 3 | with lib; |
4 | 4 | ||
@@ -15,7 +15,7 @@ let | |||
15 | 15 | ||
16 | for file in $out/pipe/bin/*; do | 16 | for file in $out/pipe/bin/*; do |
17 | wrapProgram $file \ | 17 | wrapProgram $file \ |
18 | --set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin" | 18 | --set PATH "${makeBinPath (with pkgs; [coreutils rspamd])}" |
19 | done | 19 | done |
20 | ''; | 20 | ''; |
21 | }; | 21 | }; |
@@ -33,12 +33,28 @@ let | |||
33 | }); | 33 | }); |
34 | }); | 34 | }); |
35 | }; | 35 | }; |
36 | internal-policy-server = | ||
37 | let | ||
38 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./internal-policy-server; }; | ||
39 | pythonSet = flake.lib.pythonSet { | ||
40 | inherit pkgs; | ||
41 | python = pkgs.python312; | ||
42 | overlay = workspace.mkPyprojectOverlay { | ||
43 | sourcePreference = "wheel"; | ||
44 | }; | ||
45 | }; | ||
46 | virtualEnv = pythonSet.mkVirtualEnv "internal-policy-server-env" workspace.deps.default; | ||
47 | in virtualEnv.overrideAttrs (oldAttrs: { | ||
48 | meta = (oldAttrs.meta or {}) // { | ||
49 | mainProgram = "internal-policy-server"; | ||
50 | }; | ||
51 | }); | ||
36 | 52 | ||
37 | nftables-nologin-script = pkgs.writeScript "nftables-mail-nologin" '' | 53 | nftables-nologin-script = pkgs.resholve.writeScript "nftables-mail-nologin" { |
38 | #!${pkgs.zsh}/bin/zsh | 54 | inputs = with pkgs; [inetutils nftables gnugrep findutils]; |
39 | 55 | interpreter = lib.getExe pkgs.zsh; | |
56 | } '' | ||
40 | set -e | 57 | set -e |
41 | export PATH="${lib.makeBinPath (with pkgs; [inetutils nftables])}:$PATH" | ||
42 | 58 | ||
43 | typeset -a as_sets mnt_bys route route6 | 59 | typeset -a as_sets mnt_bys route route6 |
44 | as_sets=(${lib.escapeShellArgs config.services.email.nologin.ASSets}) | 60 | as_sets=(${lib.escapeShellArgs config.services.email.nologin.ASSets}) |
@@ -51,7 +67,7 @@ let | |||
51 | elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then | 67 | elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then |
52 | route6+=($match[1]) | 68 | route6+=($match[1]) |
53 | fi | 69 | fi |
54 | done < <(whois -h whois.radb.net "!i''${as_set},1" | egrep -o 'AS[0-9]+' | xargs -- whois -h whois.radb.net -- -i origin) | 70 | done < <(whois -h whois.radb.net "!i''${as_set},1" | grep -Eo 'AS[0-9]+' | xargs whois -h whois.radb.net -- -i origin) |
55 | done | 71 | done |
56 | for mnt_by in $mnt_bys; do | 72 | for mnt_by in $mnt_bys; do |
57 | while IFS=$'\n' read line; do | 73 | while IFS=$'\n' read line; do |
@@ -190,6 +206,7 @@ in { | |||
190 | "reject_unauth_destination" | 206 | "reject_unauth_destination" |
191 | "reject_unknown_recipient_domain" | 207 | "reject_unknown_recipient_domain" |
192 | "reject_unverified_recipient" | 208 | "reject_unverified_recipient" |
209 | "check_policy_service unix:/run/postfix-internal-policy.sock" | ||
193 | ]; | 210 | ]; |
194 | unverified_recipient_reject_code = "550"; | 211 | unverified_recipient_reject_code = "550"; |
195 | unverified_recipient_reject_reason = "Recipient address lookup failed"; | 212 | unverified_recipient_reject_reason = "Recipient address lookup failed"; |
@@ -251,7 +268,7 @@ in { | |||
251 | virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; | 268 | virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; |
252 | smtputf8_enable = false; | 269 | smtputf8_enable = false; |
253 | 270 | ||
254 | authorized_submit_users = "inline:{ root= postfwd= }"; | 271 | authorized_submit_users = "inline:{ root= postfwd= dovecot2= }"; |
255 | 272 | ||
256 | postscreen_access_list = ""; | 273 | postscreen_access_list = ""; |
257 | postscreen_denylist_action = "drop"; | 274 | postscreen_denylist_action = "drop"; |
@@ -280,7 +297,7 @@ in { | |||
280 | hosts = postgresql:///email | 297 | hosts = postgresql:///email |
281 | dbname = email | 298 | dbname = email |
282 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) | 299 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) |
283 | ''},permit_tls_all_clientcerts,reject}'' | 300 | ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_tls_all_clientcerts,reject}'' |
284 | "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject" | 301 | "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject" |
285 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" | 302 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" |
286 | "-o" "unverified_sender_reject_code=550" | 303 | "-o" "unverified_sender_reject_code=550" |
@@ -310,7 +327,7 @@ in { | |||
310 | hosts = postgresql:///email | 327 | hosts = postgresql:///email |
311 | dbname = email | 328 | dbname = email |
312 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) | 329 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) |
313 | ''},permit_sasl_authenticated,reject}'' | 330 | ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_sasl_authenticated,reject}'' |
314 | "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject" | 331 | "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject" |
315 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" | 332 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" |
316 | "-o" "unverified_sender_reject_code=550" | 333 | "-o" "unverified_sender_reject_code=550" |
@@ -672,7 +689,7 @@ in { | |||
672 | plugin { | 689 | plugin { |
673 | plugin = fts fts_xapian | 690 | plugin = fts fts_xapian |
674 | fts = xapian | 691 | fts = xapian |
675 | fts_xapian = partial=2 full=20 attachments=1 verbose=1 | 692 | fts_xapian = partial=3 full=20 attachments=1 verbose=1 |
676 | 693 | ||
677 | fts_autoindex = yes | 694 | fts_autoindex = yes |
678 | 695 | ||
@@ -692,7 +709,7 @@ in { | |||
692 | startAt = "*-*-* 22:00:00 Europe/Berlin"; | 709 | startAt = "*-*-* 22:00:00 Europe/Berlin"; |
693 | serviceConfig = { | 710 | serviceConfig = { |
694 | Type = "oneshot"; | 711 | Type = "oneshot"; |
695 | ExecStart = "${pkgs.dovecot}/bin/doveadm fts optimize -A"; | 712 | ExecStart = "${getExe' pkgs.dovecot "doveadm"} fts optimize -A"; |
696 | PrivateDevices = true; | 713 | PrivateDevices = true; |
697 | PrivateNetwork = true; | 714 | PrivateNetwork = true; |
698 | ProtectKernelTunables = true; | 715 | ProtectKernelTunables = true; |
@@ -777,7 +794,7 @@ in { | |||
777 | systemd.services.dovecot2 = { | 794 | systemd.services.dovecot2 = { |
778 | preStart = '' | 795 | preStart = '' |
779 | for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do | 796 | for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do |
780 | ${pkgs.dovecot_pigeonhole}/bin/sievec $f | 797 | ${getExe' pkgs.dovecot_pigeonhole "sievec"} $f |
781 | done | 798 | done |
782 | ''; | 799 | ''; |
783 | 800 | ||
@@ -844,15 +861,16 @@ in { | |||
844 | charset utf-8; | 861 | charset utf-8; |
845 | source_charset utf-8; | 862 | source_charset utf-8; |
846 | ''; | 863 | ''; |
847 | root = pkgs.runCommand "mta-sts.${domain}" {} '' | 864 | root = pkgs.writeTextFile { |
848 | mkdir -p $out/.well-known | 865 | name = "mta-sts.${domain}"; |
849 | cp ${pkgs.writeText "mta-sts.${domain}.txt" '' | 866 | destination = "/.well-known/mta-sts.txt"; |
867 | text = '' | ||
850 | version: STSv1 | 868 | version: STSv1 |
851 | mode: enforce | 869 | mode: enforce |
852 | max_age: 2419200 | 870 | max_age: 2419200 |
853 | mx: mailin.${domain} | 871 | mx: mailin.${domain} |
854 | ''} $out/.well-known/mta-sts.txt | 872 | ''; |
855 | ''; | 873 | }; |
856 | }; | 874 | }; |
857 | }) emailDomains); | 875 | }) emailDomains); |
858 | }; | 876 | }; |
@@ -869,7 +887,7 @@ in { | |||
869 | systemd.services.spm = { | 887 | systemd.services.spm = { |
870 | serviceConfig = { | 888 | serviceConfig = { |
871 | Type = "notify"; | 889 | Type = "notify"; |
872 | ExecStart = "${pkgs.spm}/bin/spm-server"; | 890 | ExecStart = getExe' pkgs.spm "spm-server"; |
873 | User = "spm"; | 891 | User = "spm"; |
874 | Group = "spm"; | 892 | Group = "spm"; |
875 | 893 | ||
@@ -927,7 +945,7 @@ in { | |||
927 | serviceConfig = { | 945 | serviceConfig = { |
928 | Type = "notify"; | 946 | Type = "notify"; |
929 | 947 | ||
930 | ExecStart = "${ccert-policy-server}/bin/ccert-policy-server"; | 948 | ExecStart = getExe' ccert-policy-server "ccert-policy-server"; |
931 | 949 | ||
932 | Environment = [ | 950 | Environment = [ |
933 | "PGDATABASE=email" | 951 | "PGDATABASE=email" |
@@ -960,6 +978,53 @@ in { | |||
960 | }; | 978 | }; |
961 | users.groups."postfix-ccert-sender-policy" = {}; | 979 | users.groups."postfix-ccert-sender-policy" = {}; |
962 | 980 | ||
981 | systemd.sockets."postfix-internal-policy" = { | ||
982 | requiredBy = ["postfix.service"]; | ||
983 | wants = ["postfix-internal-policy.service"]; | ||
984 | socketConfig = { | ||
985 | ListenStream = "/run/postfix-internal-policy.sock"; | ||
986 | }; | ||
987 | }; | ||
988 | systemd.services."postfix-internal-policy" = { | ||
989 | after = [ "postgresql.service" ]; | ||
990 | bindsTo = [ "postgresql.service" ]; | ||
991 | |||
992 | serviceConfig = { | ||
993 | Type = "notify"; | ||
994 | |||
995 | ExecStart = lib.getExe internal-policy-server; | ||
996 | |||
997 | Environment = [ | ||
998 | "PGDATABASE=email" | ||
999 | ]; | ||
1000 | |||
1001 | DynamicUser = false; | ||
1002 | User = "postfix-internal-policy"; | ||
1003 | Group = "postfix-internal-policy"; | ||
1004 | ProtectSystem = "strict"; | ||
1005 | SystemCallFilter = "@system-service"; | ||
1006 | NoNewPrivileges = true; | ||
1007 | ProtectKernelTunables = true; | ||
1008 | ProtectKernelModules = true; | ||
1009 | ProtectKernelLogs = true; | ||
1010 | ProtectControlGroups = true; | ||
1011 | MemoryDenyWriteExecute = true; | ||
1012 | RestrictSUIDSGID = true; | ||
1013 | KeyringMode = "private"; | ||
1014 | ProtectClock = true; | ||
1015 | RestrictRealtime = true; | ||
1016 | PrivateDevices = true; | ||
1017 | PrivateTmp = true; | ||
1018 | ProtectHostname = true; | ||
1019 | ReadWritePaths = ["/run/postgresql"]; | ||
1020 | }; | ||
1021 | }; | ||
1022 | users.users."postfix-internal-policy" = { | ||
1023 | isSystemUser = true; | ||
1024 | group = "postfix-internal-policy"; | ||
1025 | }; | ||
1026 | users.groups."postfix-internal-policy" = {}; | ||
1027 | |||
963 | services.postfwd = { | 1028 | services.postfwd = { |
964 | enable = true; | 1029 | enable = true; |
965 | cache = false; | 1030 | cache = false; |
diff --git a/hosts/surtr/email/internal-policy-server/.envrc b/hosts/surtr/email/internal-policy-server/.envrc new file mode 100644 index 00000000..2c909235 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/.envrc | |||
@@ -0,0 +1,4 @@ | |||
1 | use flake | ||
2 | |||
3 | [[ -d ".venv" ]] || ( uv venv && uv sync ) | ||
4 | . .venv/bin/activate | ||
diff --git a/hosts/surtr/email/internal-policy-server/.gitignore b/hosts/surtr/email/internal-policy-server/.gitignore new file mode 100644 index 00000000..4ccfae70 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | .venv | ||
2 | **/__pycache__ | ||
diff --git a/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py b/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py | |||
diff --git a/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py b/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py new file mode 100644 index 00000000..04f1a59a --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py | |||
@@ -0,0 +1,106 @@ | |||
1 | from systemd.daemon import listen_fds | ||
2 | from sdnotify import SystemdNotifier | ||
3 | from socketserver import StreamRequestHandler, ThreadingMixIn | ||
4 | from systemd_socketserver import SystemdSocketServer | ||
5 | import sys | ||
6 | from threading import Thread | ||
7 | from psycopg_pool import ConnectionPool | ||
8 | from psycopg.rows import namedtuple_row | ||
9 | |||
10 | import logging | ||
11 | |||
12 | |||
13 | class PolicyHandler(StreamRequestHandler): | ||
14 | def handle(self): | ||
15 | logger.debug('Handling new connection...') | ||
16 | |||
17 | self.args = dict() | ||
18 | |||
19 | line = None | ||
20 | while line := self.rfile.readline().removesuffix(b'\n'): | ||
21 | if b'=' not in line: | ||
22 | break | ||
23 | |||
24 | key, val = line.split(sep=b'=', maxsplit=1) | ||
25 | self.args[key.decode()] = val.decode() | ||
26 | |||
27 | logger.info('Connection parameters: %s', self.args) | ||
28 | |||
29 | allowed = False | ||
30 | user = None | ||
31 | if self.args['sasl_username']: | ||
32 | user = self.args['sasl_username'] | ||
33 | if self.args['ccert_subject']: | ||
34 | user = self.args['ccert_subject'] | ||
35 | |||
36 | with self.server.db_pool.connection() as conn: | ||
37 | local, domain = self.args['recipient'].split(sep='@', maxsplit=1) | ||
38 | extension = None | ||
39 | if '+' in local: | ||
40 | local, extension = local.split(sep='+', maxsplit=1) | ||
41 | |||
42 | logger.debug('Parsed recipient address: %s', {'local': local, 'extension': extension, 'domain': domain}) | ||
43 | |||
44 | with conn.cursor() as cur: | ||
45 | cur.row_factory = namedtuple_row | ||
46 | cur.execute('SELECT id, internal FROM "mailbox_mapping" WHERE ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare = True) | ||
47 | if (row := cur.fetchone()) is not None: | ||
48 | if not row.internal: | ||
49 | logger.debug('Recipient mailbox is not internal') | ||
50 | allowed = True | ||
51 | elif user: | ||
52 | cur.execute('SELECT EXISTS(SELECT true FROM "mailbox_mapping_access" INNER JOIN "mailbox" ON "mailbox".id = "mailbox_mapping_access"."mailbox" WHERE mailbox_mapping = %(mailbox_mapping)s AND "mailbox"."mailbox" = %(user)s) as "exists"', params = { 'mailbox_mapping': row.id, 'user': user }, prepare = True) | ||
53 | if (row := cur.fetchone()) is not None: | ||
54 | allowed = row.exists | ||
55 | else: | ||
56 | logger.debug('Recipient is not local') | ||
57 | allowed = True | ||
58 | |||
59 | action = '550 5.7.0 Recipient mailbox mapping not authorized for current user' | ||
60 | if allowed: | ||
61 | action = 'DUNNO' | ||
62 | |||
63 | logger.info('Reached verdict: %s', {'allowed': allowed, 'action': action}) | ||
64 | self.wfile.write(f'action={action}\n\n'.encode()) | ||
65 | |||
66 | class ThreadedSystemdSocketServer(ThreadingMixIn, SystemdSocketServer): | ||
67 | def __init__(self, fd, RequestHandlerClass): | ||
68 | super().__init__(fd, RequestHandlerClass) | ||
69 | |||
70 | self.db_pool = ConnectionPool(min_size=1) | ||
71 | self.db_pool.wait() | ||
72 | |||
73 | def main(): | ||
74 | global logger | ||
75 | logger = logging.getLogger(__name__) | ||
76 | console_handler = logging.StreamHandler() | ||
77 | console_handler.setFormatter( logging.Formatter('[%(levelname)s](%(name)s): %(message)s') ) | ||
78 | if sys.stderr.isatty(): | ||
79 | console_handler.setFormatter( logging.Formatter('%(asctime)s [%(levelname)s](%(name)s): %(message)s') ) | ||
80 | logger.addHandler(console_handler) | ||
81 | logger.setLevel(logging.DEBUG) | ||
82 | |||
83 | # log uncaught exceptions | ||
84 | def log_exceptions(type, value, tb): | ||
85 | global logger | ||
86 | |||
87 | logger.error(value) | ||
88 | sys.__excepthook__(type, value, tb) # calls default excepthook | ||
89 | |||
90 | sys.excepthook = log_exceptions | ||
91 | |||
92 | fds = listen_fds() | ||
93 | servers = [ThreadedSystemdSocketServer(fd, PolicyHandler) for fd in fds] | ||
94 | |||
95 | if servers: | ||
96 | for server in servers: | ||
97 | Thread(name=f'Server for fd{server.fileno()}', target=server.serve_forever).start() | ||
98 | else: | ||
99 | return 2 | ||
100 | |||
101 | SystemdNotifier().notify('READY=1') | ||
102 | |||
103 | return 0 | ||
104 | |||
105 | if __name__ == '__main__': | ||
106 | sys.exit(main()) | ||
diff --git a/hosts/surtr/email/internal-policy-server/pyproject.toml b/hosts/surtr/email/internal-policy-server/pyproject.toml new file mode 100644 index 00000000..c697cd01 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/pyproject.toml | |||
@@ -0,0 +1,18 @@ | |||
1 | [project] | ||
2 | name = "internal-policy-server" | ||
3 | version = "0.1.0" | ||
4 | requires-python = ">=3.12" | ||
5 | dependencies = [ | ||
6 | "psycopg>=3.2.9", | ||
7 | "psycopg-binary>=3.2.9", | ||
8 | "psycopg-pool>=3.2.6", | ||
9 | "sdnotify>=0.3.2", | ||
10 | "systemd-socketserver>=1.0", | ||
11 | ] | ||
12 | |||
13 | [project.scripts] | ||
14 | internal-policy-server = "internal_policy_server.__main__:main" | ||
15 | |||
16 | [build-system] | ||
17 | requires = ["hatchling"] | ||
18 | build-backend = "hatchling.build" | ||
diff --git a/hosts/surtr/email/internal-policy-server/uv.lock b/hosts/surtr/email/internal-policy-server/uv.lock new file mode 100644 index 00000000..f7a4e729 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/uv.lock | |||
@@ -0,0 +1,119 @@ | |||
1 | version = 1 | ||
2 | revision = 2 | ||
3 | requires-python = ">=3.12" | ||
4 | |||
5 | [[package]] | ||
6 | name = "internal-policy-server" | ||
7 | version = "0.1.0" | ||
8 | source = { editable = "." } | ||
9 | dependencies = [ | ||
10 | { name = "psycopg" }, | ||
11 | { name = "psycopg-binary" }, | ||
12 | { name = "psycopg-pool" }, | ||
13 | { name = "sdnotify" }, | ||
14 | { name = "systemd-socketserver" }, | ||
15 | ] | ||
16 | |||
17 | [package.metadata] | ||
18 | requires-dist = [ | ||
19 | { name = "psycopg", specifier = ">=3.2.9" }, | ||
20 | { name = "psycopg-binary", specifier = ">=3.2.9" }, | ||
21 | { name = "psycopg-pool", specifier = ">=3.2.6" }, | ||
22 | { name = "sdnotify", specifier = ">=0.3.2" }, | ||
23 | { name = "systemd-socketserver", specifier = ">=1.0" }, | ||
24 | ] | ||
25 | |||
26 | [[package]] | ||
27 | name = "psycopg" | ||
28 | version = "3.2.9" | ||
29 | source = { registry = "https://pypi.org/simple" } | ||
30 | dependencies = [ | ||
31 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, | ||
32 | { name = "tzdata", marker = "sys_platform == 'win32'" }, | ||
33 | ] | ||
34 | sdist = { url = "https://files.pythonhosted.org/packages/27/4a/93a6ab570a8d1a4ad171a1f4256e205ce48d828781312c0bbaff36380ecb/psycopg-3.2.9.tar.gz", hash = "sha256:2fbb46fcd17bc81f993f28c47f1ebea38d66ae97cc2dbc3cad73b37cefbff700", size = 158122, upload-time = "2025-05-13T16:11:15.533Z" } | ||
35 | wheels = [ | ||
36 | { url = "https://files.pythonhosted.org/packages/44/b0/a73c195a56eb6b92e937a5ca58521a5c3346fb233345adc80fd3e2f542e2/psycopg-3.2.9-py3-none-any.whl", hash = "sha256:01a8dadccdaac2123c916208c96e06631641c0566b22005493f09663c7a8d3b6", size = 202705, upload-time = "2025-05-13T16:06:26.584Z" }, | ||
37 | ] | ||
38 | |||
39 | [[package]] | ||
40 | name = "psycopg-binary" | ||
41 | version = "3.2.9" | ||
42 | source = { registry = "https://pypi.org/simple" } | ||
43 | wheels = [ | ||
44 | { url = "https://files.pythonhosted.org/packages/29/6f/ec9957e37a606cd7564412e03f41f1b3c3637a5be018d0849914cb06e674/psycopg_binary-3.2.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be7d650a434921a6b1ebe3fff324dbc2364393eb29d7672e638ce3e21076974e", size = 4022205, upload-time = "2025-05-13T16:07:48.195Z" }, | ||
45 | { url = "https://files.pythonhosted.org/packages/6b/ba/497b8bea72b20a862ac95a94386967b745a472d9ddc88bc3f32d5d5f0d43/psycopg_binary-3.2.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76b4722a529390683c0304501f238b365a46b1e5fb6b7249dbc0ad6fea51a0", size = 4083795, upload-time = "2025-05-13T16:07:50.917Z" }, | ||
46 | { url = "https://files.pythonhosted.org/packages/42/07/af9503e8e8bdad3911fd88e10e6a29240f9feaa99f57d6fac4a18b16f5a0/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a551e4683f1c307cfc3d9a05fec62c00a7264f320c9962a67a543e3ce0d8ff", size = 4655043, upload-time = "2025-05-13T16:07:54.857Z" }, | ||
47 | { url = "https://files.pythonhosted.org/packages/28/ed/aff8c9850df1648cc6a5cc7a381f11ee78d98a6b807edd4a5ae276ad60ad/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61d0a6ceed8f08c75a395bc28cb648a81cf8dee75ba4650093ad1a24a51c8724", size = 4477972, upload-time = "2025-05-13T16:07:57.925Z" }, | ||
48 | { url = "https://files.pythonhosted.org/packages/5c/bd/8e9d1b77ec1a632818fe2f457c3a65af83c68710c4c162d6866947d08cc5/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad280bbd409bf598683dda82232f5215cfc5f2b1bf0854e409b4d0c44a113b1d", size = 4737516, upload-time = "2025-05-13T16:08:01.616Z" }, | ||
49 | { url = "https://files.pythonhosted.org/packages/46/ec/222238f774cd5a0881f3f3b18fb86daceae89cc410f91ef6a9fb4556f236/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76eddaf7fef1d0994e3d536ad48aa75034663d3a07f6f7e3e601105ae73aeff6", size = 4436160, upload-time = "2025-05-13T16:08:04.278Z" }, | ||
50 | { url = "https://files.pythonhosted.org/packages/37/78/af5af2a1b296eeca54ea7592cd19284739a844974c9747e516707e7b3b39/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:52e239cd66c4158e412318fbe028cd94b0ef21b0707f56dcb4bdc250ee58fd40", size = 3753518, upload-time = "2025-05-13T16:08:07.567Z" }, | ||
51 | { url = "https://files.pythonhosted.org/packages/ec/ac/8a3ed39ea069402e9e6e6a2f79d81a71879708b31cc3454283314994b1ae/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:08bf9d5eabba160dd4f6ad247cf12f229cc19d2458511cab2eb9647f42fa6795", size = 3313598, upload-time = "2025-05-13T16:08:09.999Z" }, | ||
52 | { url = "https://files.pythonhosted.org/packages/da/43/26549af068347c808fbfe5f07d2fa8cef747cfff7c695136172991d2378b/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1b2cf018168cad87580e67bdde38ff5e51511112f1ce6ce9a8336871f465c19a", size = 3407289, upload-time = "2025-05-13T16:08:12.66Z" }, | ||
53 | { url = "https://files.pythonhosted.org/packages/67/55/ea8d227c77df8e8aec880ded398316735add8fda5eb4ff5cc96fac11e964/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:14f64d1ac6942ff089fc7e926440f7a5ced062e2ed0949d7d2d680dc5c00e2d4", size = 3472493, upload-time = "2025-05-13T16:08:15.672Z" }, | ||
54 | { url = "https://files.pythonhosted.org/packages/3c/02/6ff2a5bc53c3cd653d281666728e29121149179c73fddefb1e437024c192/psycopg_binary-3.2.9-cp312-cp312-win_amd64.whl", hash = "sha256:7a838852e5afb6b4126f93eb409516a8c02a49b788f4df8b6469a40c2157fa21", size = 2927400, upload-time = "2025-05-13T16:08:18.652Z" }, | ||
55 | { url = "https://files.pythonhosted.org/packages/28/0b/f61ff4e9f23396aca674ed4d5c9a5b7323738021d5d72d36d8b865b3deaf/psycopg_binary-3.2.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:98bbe35b5ad24a782c7bf267596638d78aa0e87abc7837bdac5b2a2ab954179e", size = 4017127, upload-time = "2025-05-13T16:08:21.391Z" }, | ||
56 | { url = "https://files.pythonhosted.org/packages/bc/00/7e181fb1179fbfc24493738b61efd0453d4b70a0c4b12728e2b82db355fd/psycopg_binary-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:72691a1615ebb42da8b636c5ca9f2b71f266be9e172f66209a361c175b7842c5", size = 4080322, upload-time = "2025-05-13T16:08:24.049Z" }, | ||
57 | { url = "https://files.pythonhosted.org/packages/58/fd/94fc267c1d1392c4211e54ccb943be96ea4032e761573cf1047951887494/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ab464bfba8c401f5536d5aa95f0ca1dd8257b5202eede04019b4415f491351", size = 4655097, upload-time = "2025-05-13T16:08:27.376Z" }, | ||
58 | { url = "https://files.pythonhosted.org/packages/41/17/31b3acf43de0b2ba83eac5878ff0dea5a608ca2a5c5dd48067999503a9de/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aeefebe752f46e3c4b769e53f1d4ad71208fe1150975ef7662c22cca80fab", size = 4482114, upload-time = "2025-05-13T16:08:30.781Z" }, | ||
59 | { url = "https://files.pythonhosted.org/packages/85/78/b4d75e5fd5a85e17f2beb977abbba3389d11a4536b116205846b0e1cf744/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7e4e4dd177a8665c9ce86bc9caae2ab3aa9360b7ce7ec01827ea1baea9ff748", size = 4737693, upload-time = "2025-05-13T16:08:34.625Z" }, | ||
60 | { url = "https://files.pythonhosted.org/packages/3b/95/7325a8550e3388b00b5e54f4ced5e7346b531eb4573bf054c3dbbfdc14fe/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc2915949e5c1ea27a851f7a472a7da7d0a40d679f0a31e42f1022f3c562e87", size = 4437423, upload-time = "2025-05-13T16:08:37.444Z" }, | ||
61 | { url = "https://files.pythonhosted.org/packages/1a/db/cef77d08e59910d483df4ee6da8af51c03bb597f500f1fe818f0f3b925d3/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1fa38a4687b14f517f049477178093c39c2a10fdcced21116f47c017516498f", size = 3758667, upload-time = "2025-05-13T16:08:40.116Z" }, | ||
62 | { url = "https://files.pythonhosted.org/packages/95/3e/252fcbffb47189aa84d723b54682e1bb6d05c8875fa50ce1ada914ae6e28/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5be8292d07a3ab828dc95b5ee6b69ca0a5b2e579a577b39671f4f5b47116dfd2", size = 3320576, upload-time = "2025-05-13T16:08:43.243Z" }, | ||
63 | { url = "https://files.pythonhosted.org/packages/1c/cd/9b5583936515d085a1bec32b45289ceb53b80d9ce1cea0fef4c782dc41a7/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:778588ca9897b6c6bab39b0d3034efff4c5438f5e3bd52fda3914175498202f9", size = 3411439, upload-time = "2025-05-13T16:08:47.321Z" }, | ||
64 | { url = "https://files.pythonhosted.org/packages/45/6b/6f1164ea1634c87956cdb6db759e0b8c5827f989ee3cdff0f5c70e8331f2/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0d5b3af045a187aedbd7ed5fc513bd933a97aaff78e61c3745b330792c4345b", size = 3477477, upload-time = "2025-05-13T16:08:51.166Z" }, | ||
65 | { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" }, | ||
66 | ] | ||
67 | |||
68 | [[package]] | ||
69 | name = "psycopg-pool" | ||
70 | version = "3.2.6" | ||
71 | source = { registry = "https://pypi.org/simple" } | ||
72 | dependencies = [ | ||
73 | { name = "typing-extensions" }, | ||
74 | ] | ||
75 | sdist = { url = "https://files.pythonhosted.org/packages/cf/13/1e7850bb2c69a63267c3dbf37387d3f71a00fd0e2fa55c5db14d64ba1af4/psycopg_pool-3.2.6.tar.gz", hash = "sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5", size = 29770, upload-time = "2025-02-26T12:03:47.129Z" } | ||
76 | wheels = [ | ||
77 | { url = "https://files.pythonhosted.org/packages/47/fd/4feb52a55c1a4bd748f2acaed1903ab54a723c47f6d0242780f4d97104d4/psycopg_pool-3.2.6-py3-none-any.whl", hash = "sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7", size = 38252, upload-time = "2025-02-26T12:03:45.073Z" }, | ||
78 | ] | ||
79 | |||
80 | [[package]] | ||
81 | name = "sdnotify" | ||
82 | version = "0.3.2" | ||
83 | source = { registry = "https://pypi.org/simple" } | ||
84 | sdist = { url = "https://files.pythonhosted.org/packages/ce/d8/9fdc36b2a912bf78106de4b3f0de3891ff8f369e7a6f80be842b8b0b6bd5/sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1", size = 2459, upload-time = "2017-08-02T20:03:44.395Z" } | ||
85 | |||
86 | [[package]] | ||
87 | name = "systemd-python" | ||
88 | version = "235" | ||
89 | source = { registry = "https://pypi.org/simple" } | ||
90 | sdist = { url = "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a", size = 61677, upload-time = "2023-02-11T13:42:16.588Z" } | ||
91 | |||
92 | [[package]] | ||
93 | name = "systemd-socketserver" | ||
94 | version = "1.0" | ||
95 | source = { registry = "https://pypi.org/simple" } | ||
96 | dependencies = [ | ||
97 | { name = "systemd-python" }, | ||
98 | ] | ||
99 | wheels = [ | ||
100 | { url = "https://files.pythonhosted.org/packages/d8/4f/b28b7f08880120a26669b080ca74487c8c67e8b54dcb0467a8f0c9f38ed6/systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8", size = 3248, upload-time = "2020-04-26T05:26:40.661Z" }, | ||
101 | ] | ||
102 | |||
103 | [[package]] | ||
104 | name = "typing-extensions" | ||
105 | version = "4.13.2" | ||
106 | source = { registry = "https://pypi.org/simple" } | ||
107 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } | ||
108 | wheels = [ | ||
109 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, | ||
110 | ] | ||
111 | |||
112 | [[package]] | ||
113 | name = "tzdata" | ||
114 | version = "2025.2" | ||
115 | source = { registry = "https://pypi.org/simple" } | ||
116 | sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } | ||
117 | wheels = [ | ||
118 | { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, | ||
119 | ] | ||
diff --git a/hosts/surtr/postgresql/default.nix b/hosts/surtr/postgresql/default.nix index 059f4088..0ae29058 100644 --- a/hosts/surtr/postgresql/default.nix +++ b/hosts/surtr/postgresql/default.nix | |||
@@ -280,6 +280,23 @@ in { | |||
280 | CREATE VIEW imap_user ("user", "password", quota_rule) AS SELECT mailbox.mailbox AS "user", "password", quota_rule FROM mailbox_quota_rule INNER JOIN mailbox ON mailbox_quota_rule.mailbox = mailbox.mailbox; | 280 | CREATE VIEW imap_user ("user", "password", quota_rule) AS SELECT mailbox.mailbox AS "user", "password", quota_rule FROM mailbox_quota_rule INNER JOIN mailbox ON mailbox_quota_rule.mailbox = mailbox.mailbox; |
281 | 281 | ||
282 | COMMIT; | 282 | COMMIT; |
283 | |||
284 | BEGIN; | ||
285 | SELECT _v.register_patch('013-internal', ARRAY['000-base'], null); | ||
286 | |||
287 | ALTER TABLE mailbox_mapping ADD COLUMN internal bool NOT NULL DEFAULT false; | ||
288 | CREATE TABLE mailbox_mapping_access ( | ||
289 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
290 | mailbox_mapping uuid REFERENCES mailbox_mapping(id), | ||
291 | mailbox uuid REFERENCES mailbox(id) | ||
292 | ); | ||
293 | CREATE USER "postfix-internal-policy"; | ||
294 | GRANT CONNECT ON DATABASE "email" TO "postfix-internal-policy"; | ||
295 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "postfix-internal-policy"; | ||
296 | GRANT SELECT ON ALL TABLES IN SCHEMA public TO "postfix-internal-policy"; | ||
297 | |||
298 | COMMIT; | ||
299 | |||
283 | ''} | 300 | ''} |
284 | 301 | ||
285 | psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" '' | 302 | psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" '' |
diff --git a/lib/pythonSet.nix b/lib/pythonSet.nix new file mode 100644 index 00000000..9dfb25ff --- /dev/null +++ b/lib/pythonSet.nix | |||
@@ -0,0 +1,28 @@ | |||
1 | { uv2nix, pyproject-nix, pyproject-build-systems, ... }: | ||
2 | { pkgs, python, overlay, lib ? pkgs.lib }: | ||
3 | (pkgs.callPackage pyproject-nix.build.packages { | ||
4 | inherit python; | ||
5 | }).overrideScope | ||
6 | ( | ||
7 | lib.composeManyExtensions [ | ||
8 | pyproject-build-systems.overlays.default | ||
9 | overlay | ||
10 | (final: prev: { | ||
11 | sdnotify = (prev.sdnotify.override { | ||
12 | sourcePreference = "sdist"; | ||
13 | }).overrideAttrs (oldAttrs: { | ||
14 | nativeBuildInputs = (oldAttrs.nativeBuildInputs or []) ++ [ | ||
15 | (final.resolveBuildSystem { setuptools = []; }) | ||
16 | ]; | ||
17 | }); | ||
18 | systemd-python = (prev.systemd-python.override { | ||
19 | sourcePreference = "sdist"; | ||
20 | }).overrideAttrs (oldAttrs: { | ||
21 | nativeBuildInputs = (oldAttrs.nativeBuildInputs or []) ++ [ | ||
22 | pkgs.pkg-config pkgs.systemd.dev | ||
23 | (final.resolveBuildSystem { setuptools = []; }) | ||
24 | ]; | ||
25 | }); | ||
26 | }) | ||
27 | ] | ||
28 | ) | ||
diff --git a/overlays/abs-podcast-autoplaylist/default.nix b/overlays/abs-podcast-autoplaylist/default.nix index 075e0ba0..843f1b65 100644 --- a/overlays/abs-podcast-autoplaylist/default.nix +++ b/overlays/abs-podcast-autoplaylist/default.nix | |||
@@ -1,23 +1,14 @@ | |||
1 | { prev, final, flakeInputs, ... }: | 1 | { prev, final, flake, flakeInputs, ... }: |
2 | |||
3 | with flakeInputs; | ||
4 | 2 | ||
5 | let | 3 | let |
6 | workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; | 4 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; |
7 | overlay = workspace.mkPyprojectOverlay { | 5 | pythonSet = flake.lib.pythonSet { |
8 | sourcePreference = "wheel"; | 6 | pkgs = final; |
7 | python = final.python312; | ||
8 | overlay = workspace.mkPyprojectOverlay { | ||
9 | sourcePreference = "wheel"; | ||
10 | }; | ||
9 | }; | 11 | }; |
10 | python = final.python312; | ||
11 | pythonSet = | ||
12 | (final.callPackage pyproject-nix.build.packages { | ||
13 | inherit python; | ||
14 | }).overrideScope | ||
15 | ( | ||
16 | prev.lib.composeManyExtensions [ | ||
17 | pyproject-build-systems.overlays.default | ||
18 | overlay | ||
19 | ] | ||
20 | ); | ||
21 | virtualEnv = pythonSet.mkVirtualEnv "abs-podcast-autoplaylist-env" workspace.deps.default; | 12 | virtualEnv = pythonSet.mkVirtualEnv "abs-podcast-autoplaylist-env" workspace.deps.default; |
22 | in { | 13 | in { |
23 | abs-podcast-autoplaylist = virtualEnv.overrideAttrs (oldAttrs: { | 14 | abs-podcast-autoplaylist = virtualEnv.overrideAttrs (oldAttrs: { |
diff --git a/overlays/waybar-systemd-inhibit/default.nix b/overlays/waybar-systemd-inhibit/default.nix index 88322ef5..ae6b8c75 100644 --- a/overlays/waybar-systemd-inhibit/default.nix +++ b/overlays/waybar-systemd-inhibit/default.nix | |||
@@ -1,29 +1,14 @@ | |||
1 | { prev, final, flakeInputs, ... }: | 1 | { prev, final, flake, flakeInputs, ... }: |
2 | |||
3 | with flakeInputs; | ||
4 | 2 | ||
5 | let | 3 | let |
6 | workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; | 4 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; |
7 | overlay = workspace.mkPyprojectOverlay { | 5 | pythonSet = flake.lib.pythonSet { |
8 | sourcePreference = "wheel"; | 6 | pkgs = final; |
7 | python = final.python312; | ||
8 | overlay = workspace.mkPyprojectOverlay { | ||
9 | sourcePreference = "wheel"; | ||
10 | }; | ||
9 | }; | 11 | }; |
10 | python = final.python312; | ||
11 | # hacks = final.callPackage pyproject-nix.build.hacks { }; | ||
12 | pythonSet = | ||
13 | (final.callPackage pyproject-nix.build.packages { | ||
14 | inherit python; | ||
15 | }).overrideScope | ||
16 | ( | ||
17 | prev.lib.composeManyExtensions [ | ||
18 | pyproject-build-systems.overlays.default | ||
19 | overlay | ||
20 | # (final: prev: { | ||
21 | # pygobject = hacks.nixpkgsPrebuilt { | ||
22 | # from = python.pkgs.pygobject3; | ||
23 | # }; | ||
24 | # }) | ||
25 | ] | ||
26 | ); | ||
27 | virtualEnv = pythonSet.mkVirtualEnv "waybar-systemd-inhibit-env" workspace.deps.default; | 12 | virtualEnv = pythonSet.mkVirtualEnv "waybar-systemd-inhibit-env" workspace.deps.default; |
28 | in { | 13 | in { |
29 | waybar-systemd-inhibit = virtualEnv.overrideAttrs (oldAttrs: { | 14 | waybar-systemd-inhibit = virtualEnv.overrideAttrs (oldAttrs: { |
@@ -21,7 +21,7 @@ in pkgs.mkShell { | |||
21 | nvfetcher.packages.${system}.default | 21 | nvfetcher.packages.${system}.default |
22 | ca-util.packages.${system}.ca | 22 | ca-util.packages.${system}.ca |
23 | poetry uv | 23 | poetry uv |
24 | ninja pkg-config cairo.dev | 24 | ninja pkg-config cairo.dev systemd.dev |
25 | ]); | 25 | ]); |
26 | shellHook = '' | 26 | shellHook = '' |
27 | export UV_FIND_LINKS=${uv-links}/lib/python3.12/site-packages | 27 | export UV_FIND_LINKS=${uv-links}/lib/python3.12/site-packages |