From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id yK4xJa3U+GN1ZgAAbAwnHQ (envelope-from ) for ; Fri, 24 Feb 2023 16:15:57 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id CAM+Ja3U+GMqbwAA9RJhRA (envelope-from ) for ; Fri, 24 Feb 2023 16:15:57 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 2FB311C133 for ; Fri, 24 Feb 2023 16:15:55 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pVZnI-0001nF-64; Fri, 24 Feb 2023 10:15:32 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pVJi2-0004ic-Sw for guix-patches@gnu.org; Thu, 23 Feb 2023 17:05:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pVJi2-0003Ma-KJ for guix-patches@gnu.org; Thu, 23 Feb 2023 17:05:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pVJi2-0004tO-0Z for guix-patches@gnu.org; Thu, 23 Feb 2023 17:05:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#61740] [PATCH] services: Add rspamd-service-type. Resent-From: Thomas Ieong Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Thu, 23 Feb 2023 22:05:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 61740 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 61740@debbugs.gnu.org Cc: Thomas Ieong X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.167718984318721 (code B ref -1); Thu, 23 Feb 2023 22:05:01 +0000 Received: (at submit) by debbugs.gnu.org; 23 Feb 2023 22:04:03 +0000 Received: from localhost ([127.0.0.1]:35485 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pVJh3-0004rh-NR for submit@debbugs.gnu.org; Thu, 23 Feb 2023 17:04:02 -0500 Received: from lists.gnu.org ([209.51.188.17]:58306) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pVI2e-00028w-Fo for submit@debbugs.gnu.org; Thu, 23 Feb 2023 15:18:13 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pVI2e-0003wE-2j for guix-patches@gnu.org; Thu, 23 Feb 2023 15:18:12 -0500 Received: from smtp3-g21.free.fr ([2a01:e0c:1:1599::12]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pVI2b-0000GW-Ft for guix-patches@gnu.org; Thu, 23 Feb 2023 15:18:11 -0500 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:260:e370:f4ab:5c98:aaa3:9b9e]) (Authenticated sender: th.ieong@free.fr) by smtp3-g21.free.fr (Postfix) with ESMTPSA id 65C5213F87F; Thu, 23 Feb 2023 21:18:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=free.fr; s=smtp-20201208; t=1677183484; bh=TmEskcxlfbx3d7UbITVt05fWiYoyp52wim02KAnC1UQ=; h=From:To:Cc:Subject:Date:From; b=h1tdUT5UyIywB5eD3GlEG2wmp7FCt5k4jK6EYlvMOI1jrooPTNdhRjKaB0LoSKot/ ABmokg14FMr6NMHWXgKg7s4Mwvba0Um1hlROugWif6mawcG4lr0GM2Hti2BoL2mTZM 4EkYz9SPfmpTAdGtKo7rvHYj+wFH7QV9cMkLEgkjel/MDiMjo9XMwd0hGfE+04BHVT OZI+W6BMLNfOpNu6+jv4WFE7v7lhEv5ie0RHaaudPgWTGoCG7jSpKgkP0DBTO7Rh5U I52PGSEl03/r4OUre0bjJ9mxcFBXFrOSOqHnz7bSr6P6ChlnYsgLDIM3l0SPba0Zdx lgkv0Gap7DWOg== From: Thomas Ieong Date: Thu, 23 Feb 2023 21:16:14 +0100 Message-Id: <68b32de839c2abda283be3539eef38aebd53d82e.1677183321.git.th.ieong@free.fr> X-Mailer: git-send-email 2.39.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2a01:e0c:1:1599::12; envelope-from=th.ieong@free.fr; helo=smtp3-g21.free.fr X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 23 Feb 2023 17:04:00 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-Mailman-Approved-At: Fri, 24 Feb 2023 10:15:23 -0500 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1677251757; a=rsa-sha256; cv=none; b=gMtxODN+Bb0mJt89bf/6ZQglxD14TCWO5IrAh8A3pC1tBG8owrUOdWcXek8yb4wIUnmfgB 80fxGsjjRA+HI3SXpwznH9NMCXt++TEaGs+RmFEoeBDSiDjsyUe5PD9eeKSmiDZ3t2Ff6p EsfvdRI3owwCiJTzVIuP1rj4DkVq7NHTQV4Ldma7UjjJYRCrKIu8Gi8TSmSptFJ9nkC6Mo Qd19kyZzhlIYfqUdiKH3cBt+XI+tAztXVHnHcnOCgldsngZd/De+RlhSqH6q1dBtXl8TiI A9bY/ObQ5iRNPq8jeFmOc/OSTHCQP0vEO3BP+lZhknUgrS7oNV5r2SfagD8Anw== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=free.fr header.s=smtp-20201208 header.b=h1tdUT5U; dmarc=fail reason="SPF not aligned (relaxed)" header.from=free.fr (policy=none); spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1677251757; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:resent-cc: resent-from:resent-sender:resent-message-id:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=4HUg56sEEmZS3Xna3pLvk/HoA8EqAkeRFJQT266UhOw=; b=Vn4d8JI71Il9bqfy3rsn5mEEhnPxIhQ4YS/+2wdyySlsARR1eLm4MHsR1iKV1PCsqNyw2U j7GsFag0+5pFQlikDd5KJ845oHLrXghSKoYxpsiSaajQqzJbt3HXq2m8ycvP6eb8oDQmih RZUXnAydMULa1i4y4qAie2Yh+riaDCKKcHZodZw6L9fU7Kvvl64NXMPI/jRwCzWZN7BnXi dBZPjiWefOQsh8DlO6iJwatOOZRWfBGwqz+qKADWgwq/wmZW6SWkLpHB4jek3WYnMQJZr+ nhstHaTRpZ9faEIyrhhGEMiwXJ0Q1Zxrfa+88dk59RBxoeDqsizj6KrUagDMug== X-Migadu-Queue-Id: 2FB311C133 X-Migadu-Scanner: scn1.migadu.com X-Migadu-Spam-Score: -2.02 Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=free.fr header.s=smtp-20201208 header.b=h1tdUT5U; dmarc=fail reason="SPF not aligned (relaxed)" header.from=free.fr (policy=none); spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org" X-Spam-Score: -2.02 X-TUID: I7vGq9JR/gPp * gnu/services/mail.scm (rspamd-service-type): New variable. * gnu/tests/mail.scm (%test-rspamd): New variable. * doc/guix.texi: Document it. --- Hey Guix! First time contributor here, this patch introduces some basic support for rspamd. I do need guidance on some points. How to handle the extra configs that a user can provide to rspamd? On your average linux distro rspamd does expects you to not touch the rspamd.conf and instead put your changes in the /etc/rspamd/{local.d,override.d} directories (local is enough to redefine most settings, but if there are changes made via the web ui, the web ui changes takes precedence, you need to use override.d if you want to freeze a setting.) For example to set the password of the web ui you're supposed to create /etc/rspamd/local.d/worker-controller.inc and then set password = "some_hash"; Then this will get merged with the config as something like: worker { type = "controller"; password = "some_hash"; } The point is we could ignore local.d/override.d and write these blocks directly to rspamd.conf. Of course it needs some additionals configuration records for the workers and the common options between them. And finally for the test I do plan to add integration test with opensmtpd when I get the time. Are there examples of such integration test? What do you think? doc/guix.texi | 43 ++++++++++ gnu/services/mail.scm | 191 +++++++++++++++++++++++++++++++++++++++++- gnu/tests/mail.scm | 87 ++++++++++++++++++- 3 files changed, 319 insertions(+), 2 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 05615b9549..c1070a5244 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -114,6 +114,7 @@ Copyright @copyright{} 2023 Giacomo Leidi@* Copyright @copyright{} 2022 Antero Mejr@* Copyright @copyright{} 2023 Bruno Victal@* +Copyright @copyright{} 2023 Thomas Ieong@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -26365,6 +26366,48 @@ Mail Services @end table @end deftp +@subsubheading Rspamd Service +@cindex email +@cindex spam + +@defvar rspamd-service-type +This is the type of the @uref{https://rspamd.com/, Rspamd} filtering +system whose value should be a @code{rspamd-configuration}. +@end defvar + +@deftp {Data Type} rspamd-configuration +Data type representing the configuration of @command{rspamd}. + +@table @asis +@item @code{package} (default: @code{rspamd}) +The package that provides @command{rspamd}. + +@item @code{config-file} (default: @code{%default-rspamd-config-file}) +File-like object of the configuration file to use. By default +all workers are enabled except fuzzy and they are binded +to their usual ports, e.g localhost:11334, localhost:11333 and so on. + +@item @code{user} (default: @code{"rspamd"}) +The user to run rspamd as. + +@item @code{group} (default: @code{"rspamd"}) +The user to run rspamd as. + +@item @code{pid-file} (default: @code{"/var/run/rspamd/rspamd.pid"}) +Where to store the PID file. + +@item @code{debug?} (default: @code{#f}) +Force debug output. + +@item @code{insecure?} (default: @code{#f}) +Ignore running workers as privileged users (insecure). + +@item @code{skip-template?} (default: @code{#f}) +Do not apply Jinja templates. + +@end table +@end deftp + @node Messaging Services @subsection Messaging Services diff --git a/gnu/services/mail.scm b/gnu/services/mail.scm index 6f588679b1..8a4af26f66 100644 --- a/gnu/services/mail.scm +++ b/gnu/services/mail.scm @@ -5,6 +5,7 @@ ;;; Copyright © 2017, 2020 Tobias Geerinckx-Rice ;;; Copyright © 2019 Kristofer Buffington ;;; Copyright © 2020 Jonathan Brielmaier +;;; Copyright © 2023 Thomas Ieong ;;; ;;; This file is part of GNU Guix. ;;; @@ -79,7 +80,11 @@ (define-module (gnu services mail) radicale-configuration radicale-configuration? radicale-service-type - %default-radicale-config-file)) + %default-radicale-config-file + + rspamd-configuration + rspamd-service-type + %default-rspamd-config-file)) ;;; Commentary: ;;; @@ -1984,3 +1989,187 @@ (define radicale-service-type (service-extension account-service-type (const %radicale-accounts)) (service-extension activation-service-type radicale-activation))) (default-value (radicale-configuration)))) + +;;; +;;; Rspamd. +;;; + +(define-maybe boolean) + +(define-configuration rspamd-configuration + (package + (file-like rspamd) + "The package that provides rspamd." + empty-serializer) + (config-file + (file-like %default-rspamd-config-file) + "File-like object of the configuration file to use. By default +all workers are enabled except fuzzy and they are binded +to their usual ports, e.g localhost:11334, localhost:11333 and so on") + (user + (string "rspamd") + "The user to run rspamd as." + empty-serializer) + (group + (string "rspamd") + "The group to run rspamd as." + empty-serializer) + (pid-file + (string "/var/run/rspamd/rspamd.pid") + "Where to store the PID file." + empty-serializer) + (debug? + maybe-boolean + "Force debug output." + empty-serializer) + (insecure? + maybe-boolean + "Ignore running workers as privileged users (insecure)." + empty-serializer) + (skip-template? + maybe-boolean + "Do not apply Jinja templates." + empty-serializer)) + +(define %default-rspamd-config-file + (plain-file "rspamd.conf" " +.include \"$CONFDIR/common.conf\" + +options { + pidfile = \"$RUNDIR/rspamd.pid\"; + .include \"$CONFDIR/options.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/options.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/options.inc\" +} + +logging { + type = \"file\"; + filename = \"$LOGDIR/rspamd.log\"; + .include \"$CONFDIR/logging.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/logging.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/logging.inc\" +} + +worker \"normal\" { + bind_socket = \"localhost:11333\"; + .include \"$CONFDIR/worker-normal.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-normal.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-normal.inc\" +} + +worker \"controller\" { + bind_socket = \"localhost:11334\"; + .include \"$CONFDIR/worker-controller.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-controller.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-controller.inc\" +} + +worker \"rspamd_proxy\" { + bind_socket = \"localhost:11332\"; + .include \"$CONFDIR/worker-proxy.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-proxy.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-proxy.inc\" +} + +# Local fuzzy storage is disabled by default + +worker \"fuzzy\" { + bind_socket = \"localhost:11335\"; + count = -1; # Disable by default + .include \"$CONFDIR/worker-fuzzy.inc\" + .include(try=true; priority=1,duplicate=merge) \"$LOCAL_CONFDIR/local.d/worker-fuzzy.inc\" + .include(try=true; priority=10) \"$LOCAL_CONFDIR/override.d/worker-fuzzy.inc\" +} +")) + +(define (rspamd-accounts config) + (match-record config + (user group) + (list (user-group + (name group) + (system? #t)) + (user-account + (name user) + (group group) + (system? #t) + (comment "Rspamd daemon") + (home-directory "/var/empty") + (shell (file-append shadow "/sbin/nologin")))))) + +(define (rspamd-shepherd-service config) + (match-record config + (package config-file user group pid-file debug? insecure? skip-template?) + (list (shepherd-service + (provision '(rspamd)) + (documentation "Run the rspamd daemon.") + (requirement '(networking)) + (start (let ((rspamd (file-append package "/bin/rspamd"))) + #~(make-forkexec-constructor + (list #$rspamd "-c" #$config-file + #$@(if debug? + '("--debug") + '()) + #$@(if insecure? + '("--insecure") + '()) + #$@(if skip-template? + '("--skip-template") + '())) + #:user #$user + #:group #$group + #:pid-file #$pid-file))) + (stop #~(make-kill-destructor)) + (actions + (list (shepherd-configuration-action config-file) + (shepherd-action + (name 'reload) + (documentation "Reload rspamd.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGHUP) + (display "Service rspamd has been reloaded")) + (format #t "Service rspamd is not running."))))) + (shepherd-action + (name 'reopenlog) + (documentation "Reopen log files.") + (procedure + #~(lambda (pid) + (if pid + (begin + (kill pid SIGUSR1) + (display "Reopening the logs for rspamd")) + (format #t "Service rspamd is not running."))))))))))) + +(define (rspamd-activation config) + (match-record config + (package config-file user) + #~(begin + (use-modules (guix build utils) + (ice-9 match)) + (let ((user (getpwnam #$user))) + (mkdir-p/perms "/etc/rspamd" user #o755) + (mkdir-p/perms "/etc/rspamd/local.d" user #o755) + (mkdir-p/perms "/etc/rspamd/override.d" user #o755) + (mkdir-p/perms "/var/run/rspamd" user #o755) + (mkdir-p/perms "/var/log/rspamd" user #o755) + (mkdir-p/perms "/var/lib/rspamd" user #o755)) + ;; Check configuration file syntax. + (system* (string-append #$package "/bin/rspamadm") + "configtest" + "-c" #$config-file)))) + +(define rspamd-profile + (compose list rspamd-configuration-package)) + +(define rspamd-service-type + (service-type + (name 'rspamd) + (description "Run the rapid spam filtering system") + (extensions + (list (service-extension shepherd-root-service-type rspamd-shepherd-service) + (service-extension account-service-type rspamd-accounts) + (service-extension activation-service-type rspamd-activation) + (service-extension profile-service-type rspamd-profile))) + (default-value (rspamd-configuration)))) diff --git a/gnu/tests/mail.scm b/gnu/tests/mail.scm index f13751b72f..f532d30805 100644 --- a/gnu/tests/mail.scm +++ b/gnu/tests/mail.scm @@ -6,6 +6,7 @@ ;;; Copyright © 2018 Clément Lassieur ;;; Copyright © 2019 Christopher Baines ;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice +;;; Copyright © 2023 Thomas Ieong ;;; ;;; This file is part of GNU Guix. ;;; @@ -40,7 +41,8 @@ (define-module (gnu tests mail) #:export (%test-opensmtpd %test-exim %test-dovecot - %test-getmail)) + %test-getmail + %test-rspamd)) (define %opensmtpd-os (simple-operating-system @@ -575,3 +577,86 @@ (define %test-getmail (name "getmail") (description "Connect to a running Getmail server.") (value (run-getmail-test)))) + +(define %rspamd-os + (simple-operating-system + (service dhcp-client-service-type) + (service rspamd-service-type))) + +(define (run-rspamd-test) + "Return a test of an OS running Rspamd service." + + (define rspamd-ports + '((22664 . 11332) ;; proxy worker + (22666 . 11333) ;; normal worker + (22668 . 11334) ;; web controller + (22670 . 11335))) ;; fuzzy worker + + (define vm + (virtual-machine + (operating-system (marionette-operating-system + %rspamd-os + #:imported-modules '((gnu services herd)))) + (port-forwardings rspamd-ports))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-64) + (srfi srfi-11) + (gnu build marionette) + (web uri) + (web client) + (web response)) + + (define marionette + (make-marionette '(#$vm))) + + (test-runner-current (system-test-runner #$output)) + (test-begin "rspamd") + + (test-assert "service is running" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (start-service 'rspamd)) + marionette)) + + + ;; Check mympd-service-type commit for reference + ;; TODO: For this test we need to authorize the controller to + ;; listen on other interfaces, e.g *:11334 instead of localhost:11334 + + ;; Check that we can access the web ui + (test-equal "http-get" + 200 + (begin + (let-values (((response text) + (http-get "http://localhost:22668/" + #:decode-body? #t))) + (response-code response)))) + + (test-assert "rspamd socket ready" + (wait-for-unix-socket + "/var/lib/rspamd/rspamd.sock" + marionette)) + + (test-assert "rspamd pid ready" + (marionette-eval + '(file-exists? "/var/run/rspamd/rspamd.pid") + marionette)) + + (test-assert "rspamd log file" + (marionette-eval + '(file-exists? "/var/log/rspamd/rspamd.log") + marionette)) + + (test-end)))) + + (gexp->derivation "rspamd-test" test)) + +(define %test-rspamd + (system-test + (name "rspamd") + (description "Send an email to a running rspamd server.") + (value (run-rspamd-test)))) base-commit: 5e7b0a7735d9956ee8b8c3763e4ce05e2855606f -- 2.39.1