2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

test(xcatd): cover the secret set response classification

Extract secret_in_request, secret_in_response and the secret sets from
xcatd.pm, because the classifier and the finalizer consult them. Cover
the authentication key, the privacy key and the snmpc site value reads
as sensitive, the token, prodkey and site table dumps as sensitive, the
nodels expansion of a secret table as sensitive, the lsvm directory
listing as sensitive, and the implicit lsdef attribute listing as
redacted. Keep a plain site value, a benign table,
a benign object listing and a group named like a table as not
sensitive. Assert that the daemon redacts each request segment alone.
This commit is contained in:
Vinícius Ferrão
2026-08-20 19:37:57 -03:00
parent 031ad68a41
commit 5fb762f2b6
+48 -4
View File
@@ -3,14 +3,18 @@ use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";
use Test::More;
my $xcatd = "$FindBin::Bin/../../xCAT-server/sbin/xcatd";
use XCAT::Test::File qw(repo_path slurp_repo_file);
use xCAT::xcatd;
my $xcatd = repo_path('xCAT-server/sbin/xcatd');
plan skip_all => 'xcatd not found' unless -r $xcatd;
open my $fh, '<', $xcatd or die $!;
my $src = do { local $/; <$fh> };
close $fh;
my $src = slurp_repo_file('xCAT-server/sbin/xcatd');
# Extract the three command-log response subs and load them. xcatd is present,
# so a sub that cannot be extracted is a hard failure, not a skip.
@@ -36,6 +40,8 @@ die "eval of command-log subs failed: $@" if $@;
# Classification from the request.
ok(cmdlog_response_is_sensitive({ command => ['getcredentials'], arg => [] }, ''),
'getcredentials is a sensitive-response command');
ok(cmdlog_response_is_sensitive({ command => ['lsvm'], arg => [] }, 0),
'lsvm returns the directory entry with its passwords, so it is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['gettab'], arg => ['key=xcat', 'passwd.password'] }, ''),
'gettab of a passwd column is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['passwd'] }, ''),
@@ -45,6 +51,35 @@ ok(cmdlog_response_is_sensitive({ command => ['rspconfig'], arg => [] }, 1),
ok(!cmdlog_response_is_sensitive({ command => ['rpower'], arg => ['n1', 'stat'] }, 0),
'a benign request is not sensitive');
# A secret attribute with no "passw" in its name must classify through the
# shared secret set, not the text heuristic.
ok(cmdlog_response_is_sensitive({ command => ['gettab'], arg => ['node=pdu01', 'pdu.authkey'] }, 0),
'gettab of an authentication key is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['gettab'], arg => ['node=pdu01', 'pdu.privkey'] }, 0),
'gettab of a privacy key is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['gettab'], arg => ['key=snmpc', 'site.value'] }, 0),
'gettab of the snmpc site value is sensitive');
ok(!cmdlog_response_is_sensitive({ command => ['gettab'], arg => ['key=domain', 'site.value'] }, 0),
'gettab of a plain site value is not sensitive');
# A dump of a whole table that owns a secret column returns the bare values.
ok(cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['token'] }, 0),
'tabdump of the token table is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['prodkey'] }, 0),
'tabdump of the prodkey table is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['site'] }, 0),
'tabdump of the site table is sensitive');
ok(cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['-w', 'key==snmpc', 'site'] }, 0),
'a filtered site dump is sensitive');
ok(!cmdlog_response_is_sensitive({ command => ['tabdump'], arg => ['networks'] }, 0),
'tabdump of the networks table is not sensitive');
ok(cmdlog_response_is_sensitive({ command => ['nodels'], noderange => ['node01'], arg => ['prodkey'] }, 0),
'nodels of a whole secret table is sensitive');
ok(!cmdlog_response_is_sensitive({ command => ['nodels'], noderange => ['switches'], arg => [] }, 0),
'a group named like a secret table is not sensitive');
ok(!cmdlog_response_is_sensitive({ command => ['nodels'], noderange => ['node01'], arg => ['nodetype'] }, 0),
'nodels of a benign table is not sensitive');
# Drive collect(s) then finalize, returning what was appended to the log.
sub run {
my ($sensitive, @responses) = @_;
@@ -77,6 +112,15 @@ my $benign = run(0, "node01: on");
like($benign, qr/node01: on/, 'a benign response is logged verbatim');
unlike($benign, qr/\*REDACTED\*/, 'a benign response is not redacted');
# A detailed object listing expands attributes the request never named.
my $lsdef = run(0, 'Object name: pdu01', ' authkey=AUTH_SECRET', ' privkey=PRIV_SECRET');
unlike($lsdef, qr/AUTH_SECRET|PRIV_SECRET/, 'implicit lsdef secrets are not logged');
like($lsdef, qr/\*REDACTED\*/, 'lsdef response containing secret attributes is redacted');
my $colon = run(0, 'node01: prodkey.key: AAAAA-BBBBB');
unlike($colon, qr/AAAAA/, 'a colon separated secret column is redacted');
my $plain = run(0, 'Object name: node01', ' groups=compute', ' mgt=ipmi');
unlike($plain, qr/\*REDACTED\*/, 'a benign object listing is not redacted');
# Two requests on one connection: the finalizer runs at the next command's
# start. The earlier response must be preserved (redacted), the flag reset, and
# the next benign response neither lost nor over-redacted.