all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels
@ 2020-12-30 17:15 Stoiko Ivanov
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files Stoiko Ivanov
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Stoiko Ivanov @ 2020-12-30 17:15 UTC (permalink / raw)
  To: pmg-devel

v1->v2:
* addressed Fabian's feedback (where appropriate more details are added to the
individual patches)

original cover-letter:

With the recent announcement by KAM about the availability of a signed
update channel for the KAM.cf (and other) ruleset [0], I thought that this
might be a better suited way to provide regular updates to KAM.cf compared
to the initial patch I sent some time ago [1].

The upside of using sa-update is that it does lint the ruleset before trying
to pull the updates, and afterwards as well. GPG signed updates by KAM can
also be considered production worthy.

I tried to align the implementation to the channel.d mechanism mentioned in
[0] since it seems:
* somewhat sensible (these days my first choice would not be shell-code
  snippets)
* one mechanism of potentially having a distributable way of providing
  the necessary configuration for an external SA ruleset - and the only one
  I'm aware of, which is not a self-tailored script

The patchset was tested with the file provided at [0] on my test
installation

Should this be accepted we could ship
/etc/mail/spamassassin/channel.d/KAM_channel.conf in proxmox-spamassassin


[0] https://mcgrail.com/template/kam.cf_channel
[1] https://lists.proxmox.com/pipermail/pmg-devel/2020-November/001397.html


Stoiko Ivanov (4):
  add helper for parsing SA channel.d files
  api: spamassassin: read local channels
  api: spamassassin: update local channels
  pmg-daily: run sa-update for local channels

 src/PMG/API2/SpamAssassin.pm | 89 +++++++++++++++++++++---------------
 src/PMG/Utils.pm             | 58 +++++++++++++++++++++++
 src/bin/pmg-daily            |  9 +++-
 3 files changed, 118 insertions(+), 38 deletions(-)

-- 
2.20.1





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files
  2020-12-30 17:15 [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels Stoiko Ivanov
@ 2020-12-30 17:15 ` Stoiko Ivanov
  2021-01-15  8:21   ` Thomas Lamprecht
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels Stoiko Ivanov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Stoiko Ivanov @ 2020-12-30 17:15 UTC (permalink / raw)
  To: pmg-devel

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.

[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@proxmox.com>
---
v1->v2:
* added anchors to all regex-matches

 src/PMG/Utils.pm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
index d3fae9e..ba6e839 100644
--- a/src/PMG/Utils.pm
+++ b/src/PMG/Utils.pm
@@ -1442,5 +1442,32 @@ sub domain_regex {
     return $regex;
 }
 
+sub local_spamassassin_channels {
+
+    my $res = [];
+
+    my $local_channel_dir = '/etc/mail/spamassassin/channel.d/';
+    my $read_sa_channel = sub {
+	my ($filename) = @_;
+
+	my $channel_file = $local_channel_dir.$filename;
+	my $content = PVE::Tools::file_get_contents($channel_file);
+	my $channel = {
+	    filename => $channel_file,
+	};
+
+	($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});
+
+	push(@$res, $channel);
+    };
+
+    PVE::Tools::dir_glob_foreach($local_channel_dir, '.*\.conf', $read_sa_channel);
+    return $res;
+}
 
 1;
-- 
2.20.1





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels
  2020-12-30 17:15 [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels Stoiko Ivanov
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files Stoiko Ivanov
@ 2020-12-30 17:15 ` Stoiko Ivanov
  2021-01-15 10:02   ` Thomas Lamprecht
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update " Stoiko Ivanov
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-daily: run sa-update for " Stoiko Ivanov
  3 siblings, 1 reply; 10+ messages in thread
From: Stoiko Ivanov @ 2020-12-30 17:15 UTC (permalink / raw)
  To: pmg-devel

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
v1->v2:
* changed the transliteration (tr///) to an equivalent more common s///

 src/PMG/API2/SpamAssassin.pm | 83 +++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 34 deletions(-)

diff --git a/src/PMG/API2/SpamAssassin.pm b/src/PMG/API2/SpamAssassin.pm
index eab02d9..6b9f8f9 100644
--- a/src/PMG/API2/SpamAssassin.pm
+++ b/src/PMG/API2/SpamAssassin.pm
@@ -80,50 +80,65 @@ __PACKAGE__->register_method({
 	my ($param) = @_;
 
 	my $saversion = $Mail::SpamAssassin::VERSION;
-	my $channelfile = "/var/lib/spamassassin/$saversion/updates_spamassassin_org.cf";
+	my $sa_update_dir = "/var/lib/spamassassin/$saversion/";
+
+	my $check_channel = sub {
+	    my ($channel) = @_;
+
+	    # see sa-update source:
+	    my $channel_file_base = $channel;
+	    $channel_file_base =~ s/[^A-Za-z0-9-]+/_/g;
+	    my $channelfile = "${sa_update_dir}${channel_file_base}.cf";
+
+	    my $mtime = -1;
+	    my $version = -1;
+	    my $newversion = -1;
+
+	    if (-f $channelfile) {
+		# stat metadata cf file
+		$mtime = (stat($channelfile))[9]; # 9 is mtime
+
+		# parse version from metadata cf file
+		my $metadata = PVE::Tools::file_read_firstline($channelfile);
+		if ($metadata =~ m/\s([0-9]+)$/) {
+		    $version = $1;
+		} else {
+		    warn "invalid metadata in '$channelfile'\n";
+		}
+	    }
+	    # call sa-update to see if updates are available
 
-	my $mtime = -1;
-	my $version = -1;
-	my $newversion = -1;
+	    my $cmd = "$SAUPDATE -v --checkonly --channel $channel";
+	    PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
+		my ($line) = @_;
 
-	if (-f $channelfile) {
-	    # stat metadata cf file
-	    $mtime = (stat($channelfile))[9]; # 9 is mtime
+		if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
+		    $newversion = $1;
+		}
+	    });
 
-	    # parse version from metadata cf file
-	    my $metadata = PVE::Tools::file_read_firstline($channelfile);
-	    if ($metadata =~ m/\s([0-9]+)$/) {
-		$version = $1;
-	    } else {
-		warn "invalid metadata in '$channelfile'\n";
-	    }
-	}
-	# call sa-update to see if updates are available
+	    my $result = {
+		channel => $channel,
+	    };
 
-	my $cmd = "$SAUPDATE -v --checkonly";
-	PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
-	    my ($line) = @_;
+	    $result->{version} = $version if $version > -1;
+	    $result->{update_version} = $newversion if $newversion > -1;
+	    $result->{last_updated} = $mtime if $mtime > -1;
 
-	    if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
-		$newversion = $1;
+	    if ($newversion > $version) {
+		$result->{update_avail} = 1;
+	    } else {
+		$result->{update_avail} = 0;
 	    }
-	});
-
-	my $result = {
-	    channel => 'updates.spamassassin.org',
+	    return $result;
 	};
 
-	$result->{version} = $version if $version > -1;
-	$result->{update_version} = $newversion if $newversion > -1;
-	$result->{last_updated} = $mtime if $mtime > -1;
+	my @channels = ('updates.spamassassin.org');
 
-	if ($newversion > $version) {
-	    $result->{update_avail} = 1;
-	} else {
-	    $result->{update_avail} = 0;
-	}
+	my $localchannels = PMG::Utils::local_spamassassin_channels();
+	push(@channels, map { $_->{channelurl} } @$localchannels);
 
-	return [$result];
+	return [ map { $check_channel->($_) } @channels];
     }});
 
 __PACKAGE__->register_method({
-- 
2.20.1





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update local channels
  2020-12-30 17:15 [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels Stoiko Ivanov
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files Stoiko Ivanov
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels Stoiko Ivanov
@ 2020-12-30 17:15 ` Stoiko Ivanov
  2021-01-15  9:58   ` Thomas Lamprecht
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-daily: run sa-update for " Stoiko Ivanov
  3 siblings, 1 reply; 10+ messages in thread
From: Stoiko Ivanov @ 2020-12-30 17:15 UTC (permalink / raw)
  To: pmg-devel

This patch adds a helper to loop over all present Spamassassin
channels files in /etc/mail/spamassassin/channel.d and:
* import the included gpg key into sa-update's keyring
* run sa-update for each channel separately

the verbose argument of the helper is for reusing the code in
pmg-daily (where we only want to log errors and be less informative)

In order to only hardcode the path of sa-update once the definition
was moved to PMG::Utils.

The choice of invoking sa-update for each channel separately, instead
of providing multiple '--channel' and '--gpgkey' options to a single
command was made to prevent downloading signatures, which were signed
by a key not configured for the channel.

Importing gpg-keys is also done with individual sa-update invocations,
because sa-update only imports the last present --import argument
(wrong use of Getopt::Long)

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 src/PMG/API2/SpamAssassin.pm |  6 +++---
 src/PMG/Utils.pm             | 31 +++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/PMG/API2/SpamAssassin.pm b/src/PMG/API2/SpamAssassin.pm
index 6b9f8f9..fa638c4 100644
--- a/src/PMG/API2/SpamAssassin.pm
+++ b/src/PMG/API2/SpamAssassin.pm
@@ -11,15 +11,13 @@ use PVE::RESTHandler;
 use PMG::RESTEnvironment;
 use PVE::JSONSchema qw(get_standard_option);
 
-use PMG::Utils;
+use PMG::Utils qw($SAUPDATE);
 use PMG::Config;
 
 use Mail::SpamAssassin;
 
 use base qw(PVE::RESTHandler);
 
-my $SAUPDATE = '/usr/bin/sa-update';
-
 __PACKAGE__->register_method ({
     name => 'index',
     path => '',
@@ -174,6 +172,8 @@ __PACKAGE__->register_method({
 	    my $cmd = "$SAUPDATE -v";
 
 	    PVE::Tools::run_command($cmd, noerr => 1);
+
+	    PMG::Utils::update_local_spamassassin_channels(1);
 	};
 
 	return $rpcenv->fork_worker('saupdate', undef, $authuser, $realcmd);
diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
index ba6e839..9992c64 100644
--- a/src/PMG/Utils.pm
+++ b/src/PMG/Utils.pm
@@ -44,6 +44,7 @@ use base 'Exporter';
 
 our @EXPORT_OK = qw(
 postgres_admin_cmd
+$SAUPDATE
 );
 
 my $valid_pmg_realms = ['pam', 'pmg', 'quarantine'];
@@ -1442,6 +1443,8 @@ sub domain_regex {
     return $regex;
 }
 
+our $SAUPDATE = '/usr/bin/sa-update';
+
 sub local_spamassassin_channels {
 
     my $res = [];
@@ -1470,4 +1473,32 @@ sub local_spamassassin_channels {
     return $res;
 }
 
+sub update_local_spamassassin_channels {
+    my ($verbose) = @_;
+    # import all configured channel's gpg-keys to sa-update's keyring
+    my $localchannels = PMG::Utils::local_spamassassin_channels();
+    for my $channel (@$localchannels) {
+	my $importcmd = [$SAUPDATE, '--import', $channel->{filename}];
+	push @$importcmd, '-v' if $verbose;
+
+	print "Importing gpg key from $channel->{filename}\n" if $verbose;
+	PVE::Tools::run_command($importcmd);
+    }
+
+    my $fresh_updates = 0;
+
+    for my $channel (@$localchannels) {
+	my $cmd = [$SAUPDATE, '--channel', $channel->{channelurl}, '--gpgkey', $channel->{keyid}];
+	push @$cmd, '-v' if $verbose;
+
+	print "Updating $channel->{channelurl}\n" if $verbose;
+	my $ret = PVE::Tools::run_command($cmd, noerr => 1);
+	die "updating $channel->{channelurl} failed - sa-update exited with $ret\n" if $ret >= 2;
+
+	$fresh_updates = 1 if $ret == 0;
+    }
+
+    return $fresh_updates
+}
+
 1;
-- 
2.20.1





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [pmg-devel] [PATCH pmg-api v2 4/4] pmg-daily: run sa-update for local channels
  2020-12-30 17:15 [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels Stoiko Ivanov
                   ` (2 preceding siblings ...)
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update " Stoiko Ivanov
@ 2020-12-30 17:15 ` Stoiko Ivanov
  3 siblings, 0 replies; 10+ messages in thread
From: Stoiko Ivanov @ 2020-12-30 17:15 UTC (permalink / raw)
  To: pmg-devel

Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
---
 src/bin/pmg-daily | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/bin/pmg-daily b/src/bin/pmg-daily
index 32ccb95..8865c94 100755
--- a/src/bin/pmg-daily
+++ b/src/bin/pmg-daily
@@ -73,12 +73,19 @@ if (my $http_proxy = $cfg->get('admin', 'http_proxy')) {
 }
 
 # update spamassassin rules
+my $restart_filter = 0;
 if (system('sa-update') == 0) {
     # if the exit code is 0, new updates were downloaded
     # then restart the pmg-smtp-filter to load the new rules
-    PMG::Utils::service_cmd('pmg-smtp-filter', 'restart');
+    $restart_filter = 1;
 }
 
+eval {
+    $restart_filter ||= PMG::Utils::update_local_spamassassin_channels(0);
+};
+syslog('err', "$@") if $@;
+
+PMG::Utils::service_cmd('pmg-smtp-filter', 'restart') if $restart_filter;
 # run bayes database maintainance
 system('sa-learn --force-expire >/dev/null 2>&1');
 
-- 
2.20.1





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files Stoiko Ivanov
@ 2021-01-15  8:21   ` Thomas Lamprecht
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Lamprecht @ 2021-01-15  8:21 UTC (permalink / raw)
  To: Stoiko Ivanov, pmg-devel

On 30.12.20 18:15, Stoiko Ivanov wrote:
> 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.

I'd like to have a, at least minimal, test for new parsers. Ideally a OK one and
problematic one per success or error condition, respectively.





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update local channels
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update " Stoiko Ivanov
@ 2021-01-15  9:58   ` Thomas Lamprecht
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Lamprecht @ 2021-01-15  9:58 UTC (permalink / raw)
  To: Stoiko Ivanov, pmg-devel

On 30.12.20 18:15, Stoiko Ivanov wrote:
> This patch adds a helper to loop over all present Spamassassin
> channels files in /etc/mail/spamassassin/channel.d and:
> * import the included gpg key into sa-update's keyring
> * run sa-update for each channel separately
> 
> the verbose argument of the helper is for reusing the code in
> pmg-daily (where we only want to log errors and be less informative)
> 
> In order to only hardcode the path of sa-update once the definition
> was moved to PMG::Utils.
> 
> The choice of invoking sa-update for each channel separately, instead
> of providing multiple '--channel' and '--gpgkey' options to a single
> command was made to prevent downloading signatures, which were signed
> by a key not configured for the channel.
> 
> Importing gpg-keys is also done with individual sa-update invocations,
> because sa-update only imports the last present --import argument
> (wrong use of Getopt::Long)
> 
> Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
> ---
>  src/PMG/API2/SpamAssassin.pm |  6 +++---
>  src/PMG/Utils.pm             | 31 +++++++++++++++++++++++++++++++
>  2 files changed, 34 insertions(+), 3 deletions(-)
> 
> diff --git a/src/PMG/API2/SpamAssassin.pm b/src/PMG/API2/SpamAssassin.pm
> index 6b9f8f9..fa638c4 100644
> --- a/src/PMG/API2/SpamAssassin.pm
> +++ b/src/PMG/API2/SpamAssassin.pm
> @@ -11,15 +11,13 @@ use PVE::RESTHandler;
>  use PMG::RESTEnvironment;
>  use PVE::JSONSchema qw(get_standard_option);
>  
> -use PMG::Utils;
> +use PMG::Utils qw($SAUPDATE);

can we please avoid the $SAUPDATE variable completely, either just directly use
"sa-updates" with no path prefixed as this is much cleaner and safer to do, we
have a sensible PATH env after all and having fixed paths made problems in the
past (especially with usr-merge in built systems).

If you must, add a sa_update helper method doing the actual run_command and some
possible other common things, maybe even having a clean, not overly general,
parameter signature.

>  use PMG::Config;
>  
>  use Mail::SpamAssassin;
>  
>  use base qw(PVE::RESTHandler);
>  
> -my $SAUPDATE = '/usr/bin/sa-update';
> -
>  __PACKAGE__->register_method ({
>      name => 'index',
>      path => '',
> @@ -174,6 +172,8 @@ __PACKAGE__->register_method({
>  	    my $cmd = "$SAUPDATE -v";
>  
>  	    PVE::Tools::run_command($cmd, noerr => 1);
> +
> +	    PMG::Utils::update_local_spamassassin_channels(1);
>  	};
>  
>  	return $rpcenv->fork_worker('saupdate', undef, $authuser, $realcmd);
> diff --git a/src/PMG/Utils.pm b/src/PMG/Utils.pm
> index ba6e839..9992c64 100644
> --- a/src/PMG/Utils.pm
> +++ b/src/PMG/Utils.pm
> @@ -44,6 +44,7 @@ use base 'Exporter';
>  
>  our @EXPORT_OK = qw(
>  postgres_admin_cmd
> +$SAUPDATE
>  );
>  
>  my $valid_pmg_realms = ['pam', 'pmg', 'quarantine'];
> @@ -1442,6 +1443,8 @@ sub domain_regex {
>      return $regex;
>  }
>  
> +our $SAUPDATE = '/usr/bin/sa-update';
> +
>  sub local_spamassassin_channels {
>  
>      my $res = [];
> @@ -1470,4 +1473,32 @@ sub local_spamassassin_channels {
>      return $res;
>  }
>  
> +sub update_local_spamassassin_channels {
> +    my ($verbose) = @_;
> +    # import all configured channel's gpg-keys to sa-update's keyring
> +    my $localchannels = PMG::Utils::local_spamassassin_channels();
> +    for my $channel (@$localchannels) {
> +	my $importcmd = [$SAUPDATE, '--import', $channel->{filename}];
> +	push @$importcmd, '-v' if $verbose;
> +
> +	print "Importing gpg key from $channel->{filename}\n" if $verbose;
> +	PVE::Tools::run_command($importcmd);
> +    }
> +
> +    my $fresh_updates = 0;
> +
> +    for my $channel (@$localchannels) {
> +	my $cmd = [$SAUPDATE, '--channel', $channel->{channelurl}, '--gpgkey', $channel->{keyid}];
> +	push @$cmd, '-v' if $verbose;
> +
> +	print "Updating $channel->{channelurl}\n" if $verbose;
> +	my $ret = PVE::Tools::run_command($cmd, noerr => 1);
> +	die "updating $channel->{channelurl} failed - sa-update exited with $ret\n" if $ret >= 2;
> +
> +	$fresh_updates = 1 if $ret == 0;
> +    }
> +
> +    return $fresh_updates
> +}
> +
>  1;
> 






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels
  2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels Stoiko Ivanov
@ 2021-01-15 10:02   ` Thomas Lamprecht
  2021-01-18 19:47     ` Stoiko Ivanov
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Lamprecht @ 2021-01-15 10:02 UTC (permalink / raw)
  To: Stoiko Ivanov, pmg-devel

On 30.12.20 18:15, Stoiko Ivanov wrote:
> Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
> ---
> v1->v2:
> * changed the transliteration (tr///) to an equivalent more common s///
> 
>  src/PMG/API2/SpamAssassin.pm | 83 +++++++++++++++++++++---------------
>  1 file changed, 49 insertions(+), 34 deletions(-)
> 
> diff --git a/src/PMG/API2/SpamAssassin.pm b/src/PMG/API2/SpamAssassin.pm
> index eab02d9..6b9f8f9 100644
> --- a/src/PMG/API2/SpamAssassin.pm
> +++ b/src/PMG/API2/SpamAssassin.pm
> @@ -80,50 +80,65 @@ __PACKAGE__->register_method({
>  	my ($param) = @_;
>  
>  	my $saversion = $Mail::SpamAssassin::VERSION;
> -	my $channelfile = "/var/lib/spamassassin/$saversion/updates_spamassassin_org.cf";
> +	my $sa_update_dir = "/var/lib/spamassassin/$saversion/";
> +
> +	my $check_channel = sub {
> +	    my ($channel) = @_;
> +
> +	    # see sa-update source:
> +	    my $channel_file_base = $channel;
> +	    $channel_file_base =~ s/[^A-Za-z0-9-]+/_/g;
> +	    my $channelfile = "${sa_update_dir}${channel_file_base}.cf";
> +
> +	    my $mtime = -1;
> +	    my $version = -1;
> +	    my $newversion = -1;
> +
> +	    if (-f $channelfile) {
> +		# stat metadata cf file
> +		$mtime = (stat($channelfile))[9]; # 9 is mtime
> +
> +		# parse version from metadata cf file
> +		my $metadata = PVE::Tools::file_read_firstline($channelfile);
> +		if ($metadata =~ m/\s([0-9]+)$/) {
> +		    $version = $1;
> +		} else {
> +		    warn "invalid metadata in '$channelfile'\n";

I know it was already there, but this  mayresults in a undef comparison
when checking `if ($newversion > $version) {` below.
I'd do a separate followup with that being fixed, e.g., by either prepending the
if check with a `!defined($version) || ...` check or setting it to -1000 or so.

> +		}
> +	    }
> +	    # call sa-update to see if updates are available
>  
> -	my $mtime = -1;
> -	my $version = -1;
> -	my $newversion = -1;
> +	    my $cmd = "$SAUPDATE -v --checkonly --channel $channel";
> +	    PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
> +		my ($line) = @_;
>  
> -	if (-f $channelfile) {
> -	    # stat metadata cf file
> -	    $mtime = (stat($channelfile))[9]; # 9 is mtime
> +		if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
> +		    $newversion = $1;
> +		}
> +	    });
>  
> -	    # parse version from metadata cf file
> -	    my $metadata = PVE::Tools::file_read_firstline($channelfile);
> -	    if ($metadata =~ m/\s([0-9]+)$/) {
> -		$version = $1;
> -	    } else {
> -		warn "invalid metadata in '$channelfile'\n";
> -	    }
> -	}
> -	# call sa-update to see if updates are available
> +	    my $result = {
> +		channel => $channel,
> +	    };
>  
> -	my $cmd = "$SAUPDATE -v --checkonly";
> -	PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
> -	    my ($line) = @_;
> +	    $result->{version} = $version if $version > -1;
> +	    $result->{update_version} = $newversion if $newversion > -1;
> +	    $result->{last_updated} = $mtime if $mtime > -1;
>  
> -	    if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
> -		$newversion = $1;
> +	    if ($newversion > $version) {
> +		$result->{update_avail} = 1;
> +	    } else {
> +		$result->{update_avail} = 0;
>  	    }
> -	});
> -
> -	my $result = {
> -	    channel => 'updates.spamassassin.org',
> +	    return $result;
>  	};
>  
> -	$result->{version} = $version if $version > -1;
> -	$result->{update_version} = $newversion if $newversion > -1;
> -	$result->{last_updated} = $mtime if $mtime > -1;
> +	my @channels = ('updates.spamassassin.org');
>  
> -	if ($newversion > $version) {
> -	    $result->{update_avail} = 1;
> -	} else {
> -	    $result->{update_avail} = 0;
> -	}
> +	my $localchannels = PMG::Utils::local_spamassassin_channels();
> +	push(@channels, map { $_->{channelurl} } @$localchannels);
>  
> -	return [$result];
> +	return [ map { $check_channel->($_) } @channels];

this reads a bit weird, but can be OK as $check_channel does seem to catch
all actual possible errors.

>      }});
>  
>  __PACKAGE__->register_method({
> 






^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels
  2021-01-15 10:02   ` Thomas Lamprecht
@ 2021-01-18 19:47     ` Stoiko Ivanov
  2021-01-19  9:10       ` Thomas Lamprecht
  0 siblings, 1 reply; 10+ messages in thread
From: Stoiko Ivanov @ 2021-01-18 19:47 UTC (permalink / raw)
  To: Thomas Lamprecht; +Cc: pmg-devel

On Fri, 15 Jan 2021 11:02:42 +0100
Thomas Lamprecht <t.lamprecht@proxmox.com> wrote:

> On 30.12.20 18:15, Stoiko Ivanov wrote:
> > Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
> > ---
> > v1->v2:
> > * changed the transliteration (tr///) to an equivalent more common s///
> > 
> >  src/PMG/API2/SpamAssassin.pm | 83 +++++++++++++++++++++---------------
> >  1 file changed, 49 insertions(+), 34 deletions(-)
> > 
> > diff --git a/src/PMG/API2/SpamAssassin.pm b/src/PMG/API2/SpamAssassin.pm
> > index eab02d9..6b9f8f9 100644
> > --- a/src/PMG/API2/SpamAssassin.pm
> > +++ b/src/PMG/API2/SpamAssassin.pm
> > @@ -80,50 +80,65 @@ __PACKAGE__->register_method({
> >  	my ($param) = @_;
> >  
> >  	my $saversion = $Mail::SpamAssassin::VERSION;
> > -	my $channelfile = "/var/lib/spamassassin/$saversion/updates_spamassassin_org.cf";
> > +	my $sa_update_dir = "/var/lib/spamassassin/$saversion/";
> > +
> > +	my $check_channel = sub {
> > +	    my ($channel) = @_;
> > +
> > +	    # see sa-update source:
> > +	    my $channel_file_base = $channel;
> > +	    $channel_file_base =~ s/[^A-Za-z0-9-]+/_/g;
> > +	    my $channelfile = "${sa_update_dir}${channel_file_base}.cf";
> > +
> > +	    my $mtime = -1;
> > +	    my $version = -1;
$version gets initialized to -1 here...
> > +	    my $newversion = -1;
> > +
> > +	    if (-f $channelfile) {
> > +		# stat metadata cf file
> > +		$mtime = (stat($channelfile))[9]; # 9 is mtime
> > +
> > +		# parse version from metadata cf file
> > +		my $metadata = PVE::Tools::file_read_firstline($channelfile);
> > +		if ($metadata =~ m/\s([0-9]+)$/) {
> > +		    $version = $1;
> > +		} else {
> > +		    warn "invalid metadata in '$channelfile'\n";  
> 
> I know it was already there, but this  mayresults in a undef comparison
> when checking `if ($newversion > $version) {` below.
> I'd do a separate followup with that being fixed, e.g., by either prepending the
> if check with a `!defined($version) || ...` check or setting it to -1000 or so.
so it should not be undefined if the metadata is not matching?
(I quickly tested in on my system - and if I drop the -1 I get a undef
comparison in the logs - but it works as is)
or am I missing something?

> 
> > +		}
> > +	    }
> > +	    # call sa-update to see if updates are available
> >  
> > -	my $mtime = -1;
> > -	my $version = -1;
> > -	my $newversion = -1;
> > +	    my $cmd = "$SAUPDATE -v --checkonly --channel $channel";
> > +	    PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
> > +		my ($line) = @_;
> >  
> > -	if (-f $channelfile) {
> > -	    # stat metadata cf file
> > -	    $mtime = (stat($channelfile))[9]; # 9 is mtime
> > +		if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
> > +		    $newversion = $1;
> > +		}
> > +	    });
> >  
> > -	    # parse version from metadata cf file
> > -	    my $metadata = PVE::Tools::file_read_firstline($channelfile);
> > -	    if ($metadata =~ m/\s([0-9]+)$/) {
> > -		$version = $1;
> > -	    } else {
> > -		warn "invalid metadata in '$channelfile'\n";
> > -	    }
> > -	}
> > -	# call sa-update to see if updates are available
> > +	    my $result = {
> > +		channel => $channel,
> > +	    };
> >  
> > -	my $cmd = "$SAUPDATE -v --checkonly";
> > -	PVE::Tools::run_command($cmd, noerr => 1, logfunc => sub {
> > -	    my ($line) = @_;
> > +	    $result->{version} = $version if $version > -1;
> > +	    $result->{update_version} = $newversion if $newversion > -1;
> > +	    $result->{last_updated} = $mtime if $mtime > -1;
> >  
> > -	    if ($line =~ m/Update available for channel \S+: -?[0-9]+ -> ([0-9]+)/) {
> > -		$newversion = $1;
> > +	    if ($newversion > $version) {
> > +		$result->{update_avail} = 1;
> > +	    } else {
> > +		$result->{update_avail} = 0;
> >  	    }
> > -	});
> > -
> > -	my $result = {
> > -	    channel => 'updates.spamassassin.org',
> > +	    return $result;
> >  	};
> >  
> > -	$result->{version} = $version if $version > -1;
> > -	$result->{update_version} = $newversion if $newversion > -1;
> > -	$result->{last_updated} = $mtime if $mtime > -1;
> > +	my @channels = ('updates.spamassassin.org');
> >  
> > -	if ($newversion > $version) {
> > -	    $result->{update_avail} = 1;
> > -	} else {
> > -	    $result->{update_avail} = 0;
> > -	}
> > +	my $localchannels = PMG::Utils::local_spamassassin_channels();
> > +	push(@channels, map { $_->{channelurl} } @$localchannels);
> >  
> > -	return [$result];
> > +	return [ map { $check_channel->($_) } @channels];  
> 
> this reads a bit weird, but can be OK as $check_channel does seem to catch
> all actual possible errors.
> 
> >      }});
> >  
> >  __PACKAGE__->register_method({
> >   
> 
> 





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels
  2021-01-18 19:47     ` Stoiko Ivanov
@ 2021-01-19  9:10       ` Thomas Lamprecht
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Lamprecht @ 2021-01-19  9:10 UTC (permalink / raw)
  To: Stoiko Ivanov; +Cc: pmg-devel

On 18.01.21 20:47, Stoiko Ivanov wrote:
>>> +	my $check_channel = sub {
>>> +	    my ($channel) = @_;
>>> +
>>> +	    # see sa-update source:
>>> +	    my $channel_file_base = $channel;
>>> +	    $channel_file_base =~ s/[^A-Za-z0-9-]+/_/g;
>>> +	    my $channelfile = "${sa_update_dir}${channel_file_base}.cf";
>>> +
>>> +	    my $mtime = -1;
>>> +	    my $version = -1;
> $version gets initialized to -1 here...
>>> +	    my $newversion = -1;
>>> +
>>> +	    if (-f $channelfile) {
>>> +		# stat metadata cf file
>>> +		$mtime = (stat($channelfile))[9]; # 9 is mtime
>>> +
>>> +		# parse version from metadata cf file
>>> +		my $metadata = PVE::Tools::file_read_firstline($channelfile);
>>> +		if ($metadata =~ m/\s([0-9]+)$/) {
>>> +		    $version = $1;
>>> +		} else {
>>> +		    warn "invalid metadata in '$channelfile'\n";  
>> I know it was already there, but this  mayresults in a undef comparison
>> when checking `if ($newversion > $version) {` below.
>> I'd do a separate followup with that being fixed, e.g., by either prepending the
>> if check with a `!defined($version) || ...` check or setting it to -1000 or so.
> so it should not be undefined if the metadata is not matching?
> (I quickly tested in on my system - and if I drop the -1 I get a undef
> comparison in the logs - but it works as is)
> or am I missing something?
> 

Ok, my bad then - sorry!




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-01-19  9:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-30 17:15 [pmg-devel] [PATCH pmg-api v2 0/4] add support for locally configured SA channels Stoiko Ivanov
2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 1/4] add helper for parsing SA channel.d files Stoiko Ivanov
2021-01-15  8:21   ` Thomas Lamprecht
2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 2/4] api: spamassassin: read local channels Stoiko Ivanov
2021-01-15 10:02   ` Thomas Lamprecht
2021-01-18 19:47     ` Stoiko Ivanov
2021-01-19  9:10       ` Thomas Lamprecht
2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 3/4] api: spamassassin: update " Stoiko Ivanov
2021-01-15  9:58   ` Thomas Lamprecht
2020-12-30 17:15 ` [pmg-devel] [PATCH pmg-api v2 4/4] pmg-daily: run sa-update for " Stoiko Ivanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal