From 751d237c13757d3543c3b7e64601b95d54eb5c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Tue, 25 Aug 2026 12:41:24 -0300 Subject: [PATCH 1/2] refactor: centralize policy string trimming --- perl-xCAT/xCAT/DHCP/Backend.pm | 4 +++- perl-xCAT/xCAT/DHCP/OmapiPolicy.pm | 8 +++++--- perl-xCAT/xCAT/DHCP/Range.pm | 3 ++- perl-xCAT/xCAT/StringUtils.pm | 20 ++++++++++++++++++++ perl-xCAT/xCAT/TLSPolicy.pm | 13 ++++++------- 5 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 perl-xCAT/xCAT/StringUtils.pm diff --git a/perl-xCAT/xCAT/DHCP/Backend.pm b/perl-xCAT/xCAT/DHCP/Backend.pm index 934b8828c..7ba20339b 100644 --- a/perl-xCAT/xCAT/DHCP/Backend.pm +++ b/perl-xCAT/xCAT/DHCP/Backend.pm @@ -3,13 +3,15 @@ package xCAT::DHCP::Backend; use strict; use warnings; +use xCAT::StringUtils qw(trim); + my %valid_backend = map { $_ => 1 } qw(auto isc kea); sub normalize { my ( $class, $backend ) = @_; $backend = 'auto' unless defined($backend) && $backend ne ''; - $backend =~ s/^\s+|\s+$//g; + $backend = trim($backend); $backend = lc($backend); return $backend if $valid_backend{$backend}; diff --git a/perl-xCAT/xCAT/DHCP/OmapiPolicy.pm b/perl-xCAT/xCAT/DHCP/OmapiPolicy.pm index a3621a3ce..38c808532 100644 --- a/perl-xCAT/xCAT/DHCP/OmapiPolicy.pm +++ b/perl-xCAT/xCAT/DHCP/OmapiPolicy.pm @@ -3,6 +3,8 @@ package xCAT::DHCP::OmapiPolicy; use strict; use warnings; +use xCAT::StringUtils qw(trim); + my %ALGORITHMS = ( 'hmac-md5' => 157, 'hmac-sha1' => 161, @@ -57,7 +59,7 @@ sub normalize_algorithm { my ( $class, $algorithm ) = @_; $algorithm = 'hmac-md5' unless defined($algorithm) && $algorithm ne ''; - $algorithm =~ s/^\s+|\s+$//g; + $algorithm = trim($algorithm); $algorithm = lc($algorithm); return $algorithm if $ALGORITHMS{$algorithm}; @@ -86,7 +88,7 @@ sub normalize_key_name { my ( $class, $key_name ) = @_; $key_name = 'xcat_key' unless defined($key_name) && $key_name ne ''; - $key_name =~ s/^\s+|\s+$//g; + $key_name = trim($key_name); return $key_name if $key_name =~ /\A[A-Za-z0-9_][A-Za-z0-9_.-]*\z/; return; @@ -96,7 +98,7 @@ sub normalize_omshell_path { my ( $class, $path ) = @_; $path = '/usr/bin/omshell' unless defined($path) && $path ne ''; - $path =~ s/^\s+|\s+$//g; + $path = trim($path); return $path if $path =~ m{\A/[A-Za-z0-9_.:/%+=@-]+\z}; return; diff --git a/perl-xCAT/xCAT/DHCP/Range.pm b/perl-xCAT/xCAT/DHCP/Range.pm index 21dc5da3b..8734516a2 100644 --- a/perl-xCAT/xCAT/DHCP/Range.pm +++ b/perl-xCAT/xCAT/DHCP/Range.pm @@ -6,6 +6,7 @@ use warnings; use Math::BigInt; use Socket; use xCAT::NetworkUtils qw/getipaddr/; +use xCAT::StringUtils qw(trim); sub parse_dynamic_ranges { my ( $class, $ranges ) = @_; @@ -25,7 +26,7 @@ sub parse { my ( $class, $range ) = @_; return unless defined($range); - $range =~ s/^\s+|\s+$//g; + $range = trim($range); return unless $range ne ''; if ( $range =~ m{/} ) { diff --git a/perl-xCAT/xCAT/StringUtils.pm b/perl-xCAT/xCAT/StringUtils.pm new file mode 100644 index 000000000..f420dee22 --- /dev/null +++ b/perl-xCAT/xCAT/StringUtils.pm @@ -0,0 +1,20 @@ +# IBM(c) 2026 EPL license http://www.eclipse.org/legal/epl-v10.html +package xCAT::StringUtils; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(trim); + +sub trim { + my ($value) = @_; + + return $value unless defined($value); + + $value =~ s/^\s+|\s+$//g; + return $value; +} + +1; diff --git a/perl-xCAT/xCAT/TLSPolicy.pm b/perl-xCAT/xCAT/TLSPolicy.pm index 947398d11..5e2f032ec 100644 --- a/perl-xCAT/xCAT/TLSPolicy.pm +++ b/perl-xCAT/xCAT/TLSPolicy.pm @@ -5,6 +5,7 @@ use strict; use warnings; use Exporter qw(import); +use xCAT::StringUtils qw(trim); our @EXPORT_OK = qw( MODERN_TLS_VERSION @@ -23,14 +24,12 @@ sub _site_value { return '' unless $site && defined $site->{$key}; - my $value = $site->{$key}; - $value =~ s/^\s+|\s+$//g; - return $value; + return trim($site->{$key}); } sub _normalize_policy { my $policy = shift || ''; - $policy =~ s/^\s+|\s+$//g; + $policy = trim($policy); return lc($policy); } @@ -71,7 +70,7 @@ sub _enabled_protocols { my %enabled; foreach my $token (split /:/, $ssl_version) { - $token =~ s/^\s+|\s+$//g; + $token = trim($token); next if $token eq ''; next if $token =~ /^!/; $enabled{lc($token)} = 1; @@ -84,7 +83,7 @@ sub _explicitly_disables { my ($ssl_version, $protocol) = @_; foreach my $token (split /:/, ($ssl_version || '')) { - $token =~ s/^\s+|\s+$//g; + $token = trim($token); return 1 if lc($token) eq '!' . lc($protocol); } @@ -111,7 +110,7 @@ sub _deprecated_cipher_enabled { my $ciphers = shift || ''; foreach my $token (split /:/, $ciphers) { - $token =~ s/^\s+|\s+$//g; + $token = trim($token); next if $token eq '' || $token =~ /^!/; return 1 if $token =~ /(?:^|[+_-])(?:3DES|DES-CBC3|RC4)(?:$|[+_-])/i; return 1 if $token =~ /^(?:LOW|EXP|EXPORT)$/i; From e8902990e294bb186a8a75f94a8df07e4cf3d5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Tue, 25 Aug 2026 12:42:45 -0300 Subject: [PATCH 2/2] test: cover shared string trimming --- xCAT-test/unit/dhcp_omapi_policy.t | 4 ++-- xCAT-test/unit/dhcp_range.t | 3 +++ xCAT-test/unit/string_utils.t | 34 ++++++++++++++++++++++++++++++ xCAT-test/unit/tls_policy.t | 9 ++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 xCAT-test/unit/string_utils.t diff --git a/xCAT-test/unit/dhcp_omapi_policy.t b/xCAT-test/unit/dhcp_omapi_policy.t index a871ade34..861e173bd 100644 --- a/xCAT-test/unit/dhcp_omapi_policy.t +++ b/xCAT-test/unit/dhcp_omapi_policy.t @@ -187,8 +187,8 @@ ok( !$explicit_md5->{needs_omshell_key_algorithm}, my $sha512 = omapi_settings( dhcpomapialgorithm => ' HMAC-SHA512 ', - dhcpomapikeyname => 'external.key-name', - dhcpomshellpath => '/opt/dhcp/bin/omshell', + dhcpomapikeyname => ' external.key-name ', + dhcpomshellpath => ' /opt/dhcp/bin/omshell ', ); is( $sha512->{algorithm}, 'hmac-sha512', 'algorithm is canonicalized' ); is( $sha512->{key_rr_type}, 165, 'SHA512 KEY RR type is mapped' ); diff --git a/xCAT-test/unit/dhcp_range.t b/xCAT-test/unit/dhcp_range.t index 4dad80558..70517ceb6 100644 --- a/xCAT-test/unit/dhcp_range.t +++ b/xCAT-test/unit/dhcp_range.t @@ -15,6 +15,9 @@ is( $pair->{end}, '10.0.0.20', 'range end is parsed' ); is( xCAT::DHCP::Range->isc_range($pair), '10.0.0.10 10.0.0.20', 'ISC range uses space separator' ); is( xCAT::DHCP::Range->kea_pool($pair), '10.0.0.10 - 10.0.0.20', 'Kea pool uses JSON pool syntax' ); +my $padded_pair = xCAT::DHCP::Range->parse(" \t10.0.0.10-10.0.0.20\r\n"); +is( $padded_pair->{source}, '10.0.0.10-10.0.0.20', 'surrounding range whitespace is removed' ); + is_deeply( [ xCAT::DHCP::Range->isc_ranges('10.0.0.10,10.0.0.20;10.0.1.10 10.0.1.20') ], [ '10.0.0.10 10.0.0.20', '10.0.1.10 10.0.1.20' ], diff --git a/xCAT-test/unit/string_utils.t b/xCAT-test/unit/string_utils.t new file mode 100644 index 000000000..2c751ffca --- /dev/null +++ b/xCAT-test/unit/string_utils.t @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use FindBin; +use lib "$FindBin::Bin/../../perl-xCAT"; + +use Test::More; + +use xCAT::StringUtils qw(trim); + +is( trim(undef), undef, 'undefined values remain undefined' ); +is_deeply( [ trim(undef) ], [undef], 'undefined values are preserved in list context' ); +is( trim(''), '', 'empty strings remain empty' ); +is( trim(" \t\n"), '', 'whitespace-only strings become empty' ); +is( trim('value'), 'value', 'strings without surrounding whitespace are unchanged' ); +is( trim(" \tvalue\r\n"), 'value', 'leading and trailing whitespace is removed' ); +is( + trim(" first line \n second line \n"), + "first line \n second line", + 'whitespace inside multiline content is preserved' +); +is( + trim("\x{2003}\x{03b1}\x{03b2}\x{2003}"), + "\x{03b1}\x{03b2}", + 'Unicode whitespace is removed without changing non-ASCII content' +); +is( trim(0), '0', 'defined false values are preserved' ); + +my $original = ' original '; +is( trim($original), 'original', 'trim returns the normalized value' ); +is( $original, ' original ', 'trim does not modify the caller value' ); + +done_testing(); diff --git a/xCAT-test/unit/tls_policy.t b/xCAT-test/unit/tls_policy.t index 518ea9ca6..ed0acef78 100644 --- a/xCAT-test/unit/tls_policy.t +++ b/xCAT-test/unit/tls_policy.t @@ -60,6 +60,12 @@ is(scalar @modern_override, 0, 'modern explicit override does not warn'); my @modern_override_tlsv11 = tls_setting_warnings({ xcatsslversion => 'SSLv23:!SSLv2:!SSLv3:!TLSv1:!TLSv11' }); is(scalar @modern_override_tlsv11, 0, 'modern explicit override accepts TLSv11 spelling'); +my @spaced_disabled_protocol = tls_setting_warnings({ xcatsslversion => 'SSLv23: !SSLv2:!SSLv3:!TLSv1:!TLSv1_1' }); +is(scalar @spaced_disabled_protocol, 0, 'disabled protocol selectors tolerate surrounding whitespace'); + +my @spaced_enabled_protocol = tls_setting_warnings({ xcatsslversion => 'TLSv12: TLSv1' }); +like($spaced_enabled_protocol[0], qr/deprecated protocols/, 'enabled protocol selectors tolerate surrounding whitespace'); + my @old_cipher = tls_setting_warnings({ xcatsslciphers => '3DES' }); like($old_cipher[0], qr/legacy cipher/, 'legacy cipher selector produces a warning'); @@ -72,4 +78,7 @@ like($openssl_3des_cipher[0], qr/legacy cipher/, 'OpenSSL 3DES cipher name produ my @disabled_old_cipher = tls_setting_warnings({ xcatsslciphers => 'HIGH:!RC4:!3DES:!LOW:!EXP:!EXPORT' }); is(scalar @disabled_old_cipher, 0, 'disabled legacy cipher selectors do not warn'); +my @spaced_old_cipher = tls_setting_warnings({ xcatsslciphers => 'HIGH: 3DES' }); +like($spaced_old_cipher[0], qr/legacy cipher/, 'cipher selectors tolerate surrounding whitespace'); + done_testing();