[pmg-devel] [PATCH pmg-api v3 3/6] add helper for parsing SA channel.d files
Stoiko Ivanov
s.ivanov at proxmox.com
Tue Jan 19 11:38:12 CET 2021
RHEL/CentOS based SpamAssassin implementations ship an update script,
which reads shell snippets from
/etc/mail/spamassassin/channel.d/*.conf and uses the information there
to update SA rules from the configured channels [0].
Noticed the existence of this directory/mechanism while reading the
announcement of the updatechannel for the KAM ruleset [1].
Parsing the file as text, instead of sourcing it in a shell, since I
hope that the channel files distributed don't rely on running commands
to get the ruleset url and gpg key.
The parser has some minimal tests added (inspired by the
convert_size_test.pl from pve-common)
[0] https://src.fedoraproject.org/rpms/spamassassin/blob/master/f/sa-update.cronscript
[1] https://mcgrail.com/template/kam.cf_channel
Signed-off-by: Stoiko Ivanov <s.ivanov at proxmox.com>
---
v2->v3:
* refactored read_sa_channel into a sub directly in PMG::Utils to make
it testable
* added tests (hopefully I copied from an appropriate place ;)
src/PMG/Utils.pm | 32 +++++++++++
src/tests/KAM_channel.conf | 34 ++++++++++++
src/tests/Makefile | 1 +
src/tests/missing_gpg_key_channel.conf | 2 +
src/tests/missing_keyid.conf | 7 +++
src/tests/test_sa_channel_parser.pl | 75 ++++++++++++++++++++++++++
6 files changed, 151 insertions(+)
create mode 100644 src/tests/KAM_channel.conf
create mode 100644 src/tests/missing_gpg_key_channel.conf
create mode 100644 src/tests/missing_keyid.conf
create mode 100755 src/tests/test_sa_channel_parser.pl
diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
index d3fae9e..e3863b0 100644
--- a/src/PMG/Utils.pm
+++ b/src/PMG/Utils.pm
@@ -1442,5 +1442,37 @@ sub domain_regex {
return $regex;
}
+sub read_sa_channel {
+ my ($filename) = @_;
+
+ my $content = PVE::Tools::file_get_contents($filename);
+ my $channel = {
+ filename => $filename,
+ };
+
+ ($channel->{keyid}) = ($content =~ /^KEYID=([a-fA-F0-9]+)$/m);
+ die "no KEYID in $filename!\n" if !defined($channel->{keyid});
+ ($channel->{channelurl}) = ($content =~ /^CHANNELURL=(.+)$/m);
+ die "no CHANNELURL in $filename!\n" if !defined($channel->{channelurl});
+ ($channel->{gpgkey}) = ($content =~ /(?:^|\n)(-----BEGIN PGP PUBLIC KEY BLOCK-----.+-----END PGP PUBLIC KEY BLOCK-----)(?:\n|$)/s);
+ die "no GPG public key in $filename!\n" if !defined($channel->{gpgkey});
+
+ return $channel;
+};
+
+sub local_spamassassin_channels {
+
+ my $res = [];
+
+ my $local_channel_dir = '/etc/mail/spamassassin/channel.d/';
+
+ PVE::Tools::dir_glob_foreach($local_channel_dir, '.*\.conf', sub {
+ my ($filename) = @_;
+ my $channel = read_sa_channel($local_channel_dir.$filename);
+ push(@$res, $channel);
+ });
+
+ return $res;
+}
1;
diff --git a/src/tests/KAM_channel.conf b/src/tests/KAM_channel.conf
new file mode 100644
index 0000000..50b8bc8
--- /dev/null
+++ b/src/tests/KAM_channel.conf
@@ -0,0 +1,34 @@
+CHANNELURL=kam.sa-channels.mcgrail.com
+KEYID=24C063D8
+# Ignore everything below.
+return 0
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBF96bE0BEADsT1xRD2l19kmUSg9XMfRUtJbMGa9YAQ0a2fayT9IdmR38J4o3
+Ln2fIR0CMa81Q+mi7pSdTpHGqR3t5GjmDGcCN8kwoHbmm0t5F9gK0tFAXThf+e40
+kMdzLNzled4+5D83VyKCNaPm1tmogzYKKIEzTHCqQ7TdahWZDRDFiZJWFkd/9miE
+kURY2uWLCttF+4Aa2AOHUg/7q00NSR8S0jWpLzpVNjbgi/jjkCafhpSZ56aqXHk3
+QrTwJj3sznrLb9TkVZoXFKbBCh15m7mf5VVJVEZpj3BsvbcZJPnBFkCrzPjfShRz
+lttRyiCFflOIcDrClg62tA/a1BmdUuIB5ktdCX8gB0F4t+9MhqgF89vT/OQpxywv
+/QmuvKZzl77TQcLFHDlS+TKjLI6RdM3xuto1B8aSIYpKslnVpYuMpxNsvouAiQig
+5qKBzYMbFCVge8Kjvcs6znxsPyjkCWgZVbf7ev7v+h71kkVfJ2TRR52ty/vsh82c
+LYEaIB8CKYTstf69EOEQEhqMVNfhzuEb22ueYtAQSsnpLgGii0PwAFfSB4puzEUI
+ItJVmD4DviD7ZfZnT8dR2bsysV4BF8s2dKX0KDnBAkzhlc30/iwt8j8bZXx3Evau
+Ci+sFvBRMbpJJbVH8AJT7/dImn1ZqbK7jaZkFMticGBBWaKee8NYmF+KKwARAQAB
+tDdLZXZpbiBBLiBNY0dyYWlsIChLQU0gQ2hhbm5lbCkgPGthbWNoYW5uZWxAbWNn
+cmFpbC5jb20+iQJOBBMBCAA4FiEEIdlxQicskGb8qnkrShVtpSTAY9gFAl96bE0C
+GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQShVtpSTAY9hQZRAA5i8RkBCH
+zjY/xHAoIUa4u9Di52I8t8IKHuIbH5a1TfShT8uj38ucmc/gRWMoOu1Tef9G2DdJ
+FQc7KOA9GcGyGl1C2gfoTJEqBSNJTgJVfmHQ1Ef0ucNSjYFD3H0eFGTIuoSFy3Mi
+g7CzxfhIJXIn4JW9sNwICH/7pOLke5Ihd5WvyOqU13FrfGemRbilviG73HYoy+Fh
+4R9A1MLF3I0zVG5nszfn5CjSVG3c+Buj7Gk1d67noINbhCs2IPnyuOSvfrZc5wx1
+ImCS8BpmGjXqaXZAIWLIhpMXvRiboGxX1zzRZLoz7Y5Y5h1MfnY2ASDMddmJpgOv
+Vey/acAB4+6TtCgXmA6Wy8xmsqlId4qBocxX/jCMJ8OsuueYE6eF2jzS/JfbTndA
+7pHOnCoR+ndMra5vaX8MYyGKqxxWyBoKWGgeBs8fSMwHAqRIo9GHWK67nBX0x39U
+x9G0yn/A2dhaGqhui8xrcAHg/OGJErOlDw7YBeVX0RiS6awPyk9fo0IsGN0po2VX
+bd9H8DKz1CXBLNZRG0vn5mViSOBzZeGU+K9aAs58GZ46LKA3YfWJ4s5W8BS+J3Ia
+TFpq8U+OO/BSmOkMHZ+OPKWSlxNitFTyQsIdtS1PfqqYc+MK312LdmvrG2KWXE3N
+EnuBffLm6uSOHJA6/0r6THJkffDSuvqM5yU=
+=GVCC
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/tests/Makefile b/src/tests/Makefile
index 79310b3..dc35796 100644
--- a/src/tests/Makefile
+++ b/src/tests/Makefile
@@ -10,6 +10,7 @@ check:
./print_testdb.pl > testdb.txt.new
diff -u testdb.txt testdb.txt.new
./test_greylist.pl
+ ./test_sa_channel_parser.pl
# test_config.pl \
# test_mimetype.pl \
diff --git a/src/tests/missing_gpg_key_channel.conf b/src/tests/missing_gpg_key_channel.conf
new file mode 100644
index 0000000..2bf59f3
--- /dev/null
+++ b/src/tests/missing_gpg_key_channel.conf
@@ -0,0 +1,2 @@
+CHANNELURL=missing.gpg.key.invalid
+KEYID=AAAAAAAA
diff --git a/src/tests/missing_keyid.conf b/src/tests/missing_keyid.conf
new file mode 100644
index 0000000..fe4eacf
--- /dev/null
+++ b/src/tests/missing_keyid.conf
@@ -0,0 +1,7 @@
+CHANNELURL=kam.sa-channels.mcgrail.com
+# Ignore everything below.
+return 0
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/tests/test_sa_channel_parser.pl b/src/tests/test_sa_channel_parser.pl
new file mode 100755
index 0000000..fcbb859
--- /dev/null
+++ b/src/tests/test_sa_channel_parser.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Test::More;
+
+use PMG::Utils;
+
+my $kam_key = qq{-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBF96bE0BEADsT1xRD2l19kmUSg9XMfRUtJbMGa9YAQ0a2fayT9IdmR38J4o3
+Ln2fIR0CMa81Q+mi7pSdTpHGqR3t5GjmDGcCN8kwoHbmm0t5F9gK0tFAXThf+e40
+kMdzLNzled4+5D83VyKCNaPm1tmogzYKKIEzTHCqQ7TdahWZDRDFiZJWFkd/9miE
+kURY2uWLCttF+4Aa2AOHUg/7q00NSR8S0jWpLzpVNjbgi/jjkCafhpSZ56aqXHk3
+QrTwJj3sznrLb9TkVZoXFKbBCh15m7mf5VVJVEZpj3BsvbcZJPnBFkCrzPjfShRz
+lttRyiCFflOIcDrClg62tA/a1BmdUuIB5ktdCX8gB0F4t+9MhqgF89vT/OQpxywv
+/QmuvKZzl77TQcLFHDlS+TKjLI6RdM3xuto1B8aSIYpKslnVpYuMpxNsvouAiQig
+5qKBzYMbFCVge8Kjvcs6znxsPyjkCWgZVbf7ev7v+h71kkVfJ2TRR52ty/vsh82c
+LYEaIB8CKYTstf69EOEQEhqMVNfhzuEb22ueYtAQSsnpLgGii0PwAFfSB4puzEUI
+ItJVmD4DviD7ZfZnT8dR2bsysV4BF8s2dKX0KDnBAkzhlc30/iwt8j8bZXx3Evau
+Ci+sFvBRMbpJJbVH8AJT7/dImn1ZqbK7jaZkFMticGBBWaKee8NYmF+KKwARAQAB
+tDdLZXZpbiBBLiBNY0dyYWlsIChLQU0gQ2hhbm5lbCkgPGthbWNoYW5uZWxAbWNn
+cmFpbC5jb20+iQJOBBMBCAA4FiEEIdlxQicskGb8qnkrShVtpSTAY9gFAl96bE0C
+GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQShVtpSTAY9hQZRAA5i8RkBCH
+zjY/xHAoIUa4u9Di52I8t8IKHuIbH5a1TfShT8uj38ucmc/gRWMoOu1Tef9G2DdJ
+FQc7KOA9GcGyGl1C2gfoTJEqBSNJTgJVfmHQ1Ef0ucNSjYFD3H0eFGTIuoSFy3Mi
+g7CzxfhIJXIn4JW9sNwICH/7pOLke5Ihd5WvyOqU13FrfGemRbilviG73HYoy+Fh
+4R9A1MLF3I0zVG5nszfn5CjSVG3c+Buj7Gk1d67noINbhCs2IPnyuOSvfrZc5wx1
+ImCS8BpmGjXqaXZAIWLIhpMXvRiboGxX1zzRZLoz7Y5Y5h1MfnY2ASDMddmJpgOv
+Vey/acAB4+6TtCgXmA6Wy8xmsqlId4qBocxX/jCMJ8OsuueYE6eF2jzS/JfbTndA
+7pHOnCoR+ndMra5vaX8MYyGKqxxWyBoKWGgeBs8fSMwHAqRIo9GHWK67nBX0x39U
+x9G0yn/A2dhaGqhui8xrcAHg/OGJErOlDw7YBeVX0RiS6awPyk9fo0IsGN0po2VX
+bd9H8DKz1CXBLNZRG0vn5mViSOBzZeGU+K9aAs58GZ46LKA3YfWJ4s5W8BS+J3Ia
+TFpq8U+OO/BSmOkMHZ+OPKWSlxNitFTyQsIdtS1PfqqYc+MK312LdmvrG2KWXE3N
+EnuBffLm6uSOHJA6/0r6THJkffDSuvqM5yU=
+=GVCC
+-----END PGP PUBLIC KEY BLOCK-----};
+
+my $tests = [
+ [
+ './KAM_channel.conf', # input filename
+ { # result structure
+ filename => './KAM_channel.conf',
+ channelurl => 'kam.sa-channels.mcgrail.com',
+ keyid => '24C063D8',
+ gpgkey => $kam_key,
+ },
+ undef, # error string
+ ],
+ [
+ './missing_gpg_key_channel.conf',
+ undef,
+ 'no GPG public key in ./missing_gpg_key_channel.conf!',
+ ],
+ [
+ './missing_keyid.conf',
+ undef,
+ 'no KEYID in ./missing_keyid.conf!',
+ ],
+];
+
+foreach my $test (@$tests) {
+ my ($filename, $expect, $error) = @$test;
+
+ my $result = eval { PMG::Utils::read_sa_channel($filename); };
+ my $err = $@;
+
+ if ($error) {
+ like($err, qr/^\Q$error\E/, "expected error for $filename: $error");
+ } else {
+ is_deeply($result, $expect, "channel file: $filename parsed correctly");
+ }
+}
+
+done_testing();
--
2.20.1
More information about the pmg-devel
mailing list