1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
#!/usr/bin/perl -w
use strict;
use warnings;
use File::Basename;
use YAML::XS qw/LoadFile/;
use XML::Writer;
use DateTime::HiRes;
use lib join("/", dirname($0), "lib");
use ExtRepoData;
use v5.36;
my @testcases;
my $tests = 0;
my $failures = 0;
my $full_start = DateTime::HiRes->now;
my $repos = {};
sub repotest($condition, $message) {
$tests++;
if($condition) {
return { result => 1 };
} else {
say STDERR $message;
$failures++;
return { result => 0, message => $message };
}
}
while(defined($ARGV[0])) {
my $filedata = LoadFile(shift);
foreach my $key(keys %$filedata) {
next if $key =~ /^\./;
die "duplicate repository name $key" if exists($repos->{$key});
$repos->{$key} = $filedata->{$key};
}
}
my %keys = (
description => { ref => "", req => 1 },
source => { ref => "HASH", req => 1 },
suites => { ref => "ARRAY", req => 1 },
components => { ref => "ARRAY", req => 0 },
policies => { ref => "HASH", req => 0 },
policy => { ref => "", req => 0 },
contact => { ref => "", req => 0 },
bugs => { ref => "", req => 0 },
"gpg-key" => { ref => "", req => 1 },
"onion-URIs" => { ref => "", req => 0 },
Disabled => { ref => "", req => 0 },
"post-enable-commands" => { ref => "ARRAY", req => 0 },
);
# These options mess with secure apt, and MUST NOT be used.
# Signed-By is added because it is managed by extrepo, and will be
# overridden if used.
my %forbidden = (
"allow-insecure" => 1,
"allow-weak" => 1,
"allow-downgrade-to-insecure" => 1,
"check-valid-until" => 1,
"check-date" => 1,
"trusted" => 1,
"signed-by" => 1,
);
foreach my $repo(sort(keys %$repos)) {
my $result = {
starttime => DateTime::HiRes->now,
name => "Check of repository $repo",
id => "checkrepos.repository.$repo",
tests => {},
};
my @component_keys = ( "components" );
print STDERR "Checking repository $repo...\n";
$result->{tests}{"repository name passes syntax check"} = repotest($repo =~ /^[a-z0-9_.-]+$/, "Invalid repository name $repo!");
tie my(%hash), 'ExtRepoData', $repos->{$repo};
$repos->{$repo} = \%hash;
my $have_components = 0;
foreach my $topkey(keys %{$repos->{$repo}}) {
if($topkey =~ /suite-[^-]+-components/) {
$have_components = 1;
push @component_keys, $topkey;
next;
}
$result->{tests}{"valid toplevel key $topkey"} = repotest(exists($keys{$topkey}), "invalid key $topkey");
$result->{tests}{"type correct for toplevel key $topkey"} = repotest(ref($repos->{$repo}{$topkey}) eq $keys{$topkey}{ref}, "invalid type of key $topkey");
}
if($have_components || exists($repos->{$repo}{components})) {
$have_components = 1;
$keys{policies}{req} = 1;
$keys{policy}{req} = 0;
} else {
$keys{policies}{req} = 0;
$keys{policy}{req} = 1;
}
foreach my $reqd(keys %keys) {
next unless $keys{$reqd}{req};
$result->{tests}{"required toplevel key $reqd exists"} = repotest(exists($repos->{$repo}{$reqd}), "missing required key $reqd");
}
if($have_components) {
foreach my $comp_key(@component_keys) {
foreach my $component(@{$repos->{$repo}{$comp_key}}) {
$result->{tests}{"policy for component $component is present"} = repotest(exists($repos->{$repo}{policies}{$component}), "no policy found for component $component");
}
}
}
my $types_found = 0;
foreach my $src(keys %{$repos->{$repo}{source}}) {
my $srcl = lc($src);
if($srcl =~ /suite-[^-]*-(.*)/) {
$srcl = $1;
}
$result->{tests}{"Deb822 field $src not forbidden"} = repotest(!exists($forbidden{$srcl}), "forbidden source option $src found");
$result->{tests}{"Deb822 field $src is a scalar"} = repotest(ref($repos->{$repo}{source}{$src}) eq "", "source option $src is not a scalar");
if ($srcl eq "types") {
$types_found = 1;
my $types_val = $repos->{$repo}{source}{$src};
$result->{tests}{"types Deb822 field format is acceptable"} = repotest(($types_val eq "deb" || $types_val eq "deb deb-src"), "wrong value for source Types option: $types_val");
}
}
$result->{tests}{"types Deb822 field present"} = repotest($types_found, "source Types option is missing");
$result->{"time"} = DateTime::HiRes->now->hires_epoch - $result->{"starttime"}->hires_epoch;
$result->{"timestamp"} = $result->{"starttime"}->iso8601;
delete $result->{starttime};
push @testcases, $result;
}
open my $junitfile, ">", "check-results-junit.xml";
my $junit = XML::Writer->new(OUTPUT => $junitfile);
$junit->startTag("testsuites", time => (DateTime::HiRes->now->hires_epoch - $full_start->hires_epoch), tests => $tests, failures => $failures);
foreach my $testcase(@testcases) {
$junit->startTag("testsuite", name => $testcase->{name}, tests => scalar(keys %{$testcase->{tests}}), time => $testcase->{time}, timestamp => $testcase->{timestamp}, id => $testcase->{id});
foreach my $testkey(keys %{$testcase->{tests}}) {
$junit->startTag("testcase", name => $testkey);
if(!$testcase->{tests}{$testkey}{result}) {
$junit->startTag("failure", message => $testcase->{tests}{$testkey}{message});
$junit->endTag("failure");
}
$junit->endTag("testcase");
}
$junit->endTag("testsuite");
}
$junit->endTag("testsuites");
$junit->end();
close $junitfile;
|