From f5d228e28e810f6ced8429bda2d1a0fe7c237918 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 20:05:30 +0200 Subject: [PATCH 01/15] Add Perl static analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Run perl -c on every t/*.t file as a fast pre-check before prove. * Add Perl::Critic (a curated policy set) and perltidy --check for the Perl test code — the repo lints its bash with shellcheck but has zero linting for its Perl. * Add Test::NoWarnings (and/or Test::Fatal) to the test harness so warnings/exceptions in the code under test fail the build. Not yet sure about using the hash / SHA-pinning. To be reconsidered later --- .github/workflows/perl-quality.yml | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/perl-quality.yml diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml new file mode 100644 index 0000000..be0be47 --- /dev/null +++ b/.github/workflows/perl-quality.yml @@ -0,0 +1,38 @@ +name: Perl quality + +on: + pull_request: + paths: + - 't/**' + - 'cpanfile' + - '.perlcritic' + - '.github/workflows/perl-quality.yml' + +permissions: + contents: read + +jobs: + perl: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: shivammathur/setup-perl@v14 + with: + perl-version: '5.38' + - name: Install dev modules + run: cpanm --notest Perl::Critic perltidy cpan-audit + - name: Syntax check all test files + run: | + find t -name '*.t' -o -name '*.pm' | while read -r f; do + perl -I t/lib -c "$f" + done + - name: Perl::Critic + run: perlcritic --verbose '%f:%l:%e:%m\n' t/ + - name: perltidy (fail on diff) + run: | + perltidy -p t/ + git diff --exit-code + - name: Audit CPAN modules for known CVEs + run: cpan-audit + From d58557b430a9ac4418d3e003217cfe0a2bba6838 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 20:30:35 +0200 Subject: [PATCH 02/15] Newer versions - use newer checkout hash - use appropriate perl version --- .github/workflows/perl-quality.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index be0be47..fbe9f73 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -1,5 +1,8 @@ name: Perl quality + +name: Perl quality + on: pull_request: paths: @@ -16,8 +19,8 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: shivammathur/setup-perl@v14 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: shogo82148/actions-setup-perl@v1.43.1 with: perl-version: '5.38' - name: Install dev modules @@ -35,4 +38,3 @@ jobs: git diff --exit-code - name: Audit CPAN modules for known CVEs run: cpan-audit - From f77dcbefd502c6b4ded2fa01a06b2ca47f27f560 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 20:35:02 +0200 Subject: [PATCH 03/15] Selfcheck removed (not sure whether that was right to try in the first place, probably not) --- .github/workflows/perl-quality.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index fbe9f73..ec04007 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -1,8 +1,5 @@ name: Perl quality - -name: Perl quality - on: pull_request: paths: From a2027d527ff858c17f230c6fff8ecec518a0add0 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 20:50:00 +0200 Subject: [PATCH 04/15] fix perttidy and cpan-audit --- .github/workflows/perl-quality.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index ec04007..90c38ac 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -21,7 +21,7 @@ jobs: with: perl-version: '5.38' - name: Install dev modules - run: cpanm --notest Perl::Critic perltidy cpan-audit + run: cpanm --notest Perl::Critic Perl::Tidy CPAN::Audit - name: Syntax check all test files run: | find t -name '*.t' -o -name '*.pm' | while read -r f; do @@ -35,3 +35,4 @@ jobs: git diff --exit-code - name: Audit CPAN modules for known CVEs run: cpan-audit + From 23129834b9f5a93ee2e99a34a614df2d87d5b111 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 21:26:16 +0200 Subject: [PATCH 05/15] Add all other perl modules too --- .github/workflows/perl-quality.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index 90c38ac..79de397 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -22,6 +22,9 @@ jobs: perl-version: '5.38' - name: Install dev modules run: cpanm --notest Perl::Critic Perl::Tidy CPAN::Audit + - name: Install dev modules + # add all perl modules from other modules tool, otherwise the next run fails + run: cpanm --notest Data::Dumper IPC::Run3 JSON Test::More Text::Diff - name: Syntax check all test files run: | find t -name '*.t' -o -name '*.pm' | while read -r f; do From d857e0fe60cabb026f90f4162cac65ced293cda7 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Mon, 31 Aug 2026 23:26:36 +0200 Subject: [PATCH 06/15] Add .perlcritic policy overrides for test suite --- .perlcritic | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .perlcritic diff --git a/.perlcritic b/.perlcritic new file mode 100644 index 0000000..1695d0a --- /dev/null +++ b/.perlcritic @@ -0,0 +1,17 @@ +# Perl::Critic policy overrides for the testssl.sh test suite (t/) +# +# see https://github.com/Perl-Critic/Perl-Critic + +# General setting: That would deliver way more +# severity = 3 + + +# Test helpers commonly use subroutine prototypes (e.g. sub helper ($$)); +# harmless in test code. +[Subroutines::ProhibitSubroutinePrototypes] +severity = 4 + +# Intentional octal file-permission literals (0400, 0100) in t/00_testssl_help.t. +[ValuesAndExpressions::ProhibitLeadingZeros] +severity = 4 + From 71322d89cb2dbd5151e7880592a68e70bbc87b03 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:07:52 +0200 Subject: [PATCH 07/15] Squash complains by perlcritic and enable warnings --- t/00_testssl_help.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/00_testssl_help.t b/t/00_testssl_help.t index c38ec69..d19b4fe 100755 --- a/t/00_testssl_help.t +++ b/t/00_testssl_help.t @@ -3,6 +3,7 @@ # Basics: is there a syntax error where already bash hiccups on? use strict; +use warnings; use Test::More; use File::stat; @@ -25,11 +26,11 @@ my $info = stat($prg); my $retMode = $info->mode; #1 -is($retMode & 0400, 0400, "Checking \"./testssl.sh\" for read permission"); +is($retMode & oct("400"), oct("0400"), "Checking \"./testssl.sh\" for read permission"); $tests++; #2 -is($retMode & 0100, 0100, "Checking \"./testssl.sh\" for execute permission"); +is($retMode & oct("0100"), oct("0100)", "Checking \"./testssl.sh\" for execute permission"); $tests++; $fileout = `bash $prg 2>&1`; From 8ab28557a15802a5c7d70e60ff7d1636355d9e15 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:18:46 +0200 Subject: [PATCH 08/15] Add "use warnings" --- t/02_clientsim_txt_parsable.t | 1 + t/03_syntax_check.t | 1 + t/12_diff_opensslversions.t | 1 + t/32_isHTML_valid.t | 1 + t/52_ocsp_revoked.t | 1 + t/53_hsts_preload.t | 1 + t/61_diff_testsslsh.t | 1 + 7 files changed, 7 insertions(+) diff --git a/t/02_clientsim_txt_parsable.t b/t/02_clientsim_txt_parsable.t index 6885ef8..b58210d 100755 --- a/t/02_clientsim_txt_parsable.t +++ b/t/02_clientsim_txt_parsable.t @@ -4,6 +4,7 @@ # doesn't have any syntax errors use strict; +use warnings; use Test::More; my $tests = 0; diff --git a/t/03_syntax_check.t b/t/03_syntax_check.t index cf27689..586f47c 100755 --- a/t/03_syntax_check.t +++ b/t/03_syntax_check.t @@ -3,6 +3,7 @@ # Basics: are there semantic errors which are easy to spot? use strict; +use warnings; use Test::More; my $tests = 0; diff --git a/t/12_diff_opensslversions.t b/t/12_diff_opensslversions.t index 8464133..5586847 100755 --- a/t/12_diff_opensslversions.t +++ b/t/12_diff_opensslversions.t @@ -5,6 +5,7 @@ # This runs a basic test with the supplied openssl vs /usr/bin/openssl use strict; +use warnings; use Test::More; use Data::Dumper; use Text::Diff; diff --git a/t/32_isHTML_valid.t b/t/32_isHTML_valid.t index 853cc1d..de78aca 100755 --- a/t/32_isHTML_valid.t +++ b/t/32_isHTML_valid.t @@ -4,6 +4,7 @@ # This could be amended by using HTML::Tidy or HTML::Valid use strict; +use warnings; use Test::More; use Data::Dumper; use Text::Diff; diff --git a/t/52_ocsp_revoked.t b/t/52_ocsp_revoked.t index 6b8e186..3d79864 100755 --- a/t/52_ocsp_revoked.t +++ b/t/52_ocsp_revoked.t @@ -7,6 +7,7 @@ # We don't use a full run, only the certificate section. use strict; +use warnings; use Test::More; use Data::Dumper; use Text::Diff; diff --git a/t/53_hsts_preload.t b/t/53_hsts_preload.t index 66a5552..9a63357 100755 --- a/t/53_hsts_preload.t +++ b/t/53_hsts_preload.t @@ -6,6 +6,7 @@ # We don't use a full run, only the HTTP header section. use strict; +use warnings; use Test::More; my $tests = 0; diff --git a/t/61_diff_testsslsh.t b/t/61_diff_testsslsh.t index 5e813eb..41421d2 100755 --- a/t/61_diff_testsslsh.t +++ b/t/61_diff_testsslsh.t @@ -9,6 +9,7 @@ # use strict; +use warnings; use Test::More; use Data::Dumper; use Text::Diff; From 7e1cd8a8c43d1916072775344433ea73b38d66f3 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:21:10 +0200 Subject: [PATCH 09/15] Add "use warnings" + correct subroutine prototypes declaration --- t/10_baseline_ipv4_http.t | 3 ++- t/21_baseline_starttls.t | 3 ++- t/23_client_simulation.t | 3 ++- t/31_isJSON_valid.t | 3 ++- t/33_isJSON_severitylevel_valid.t | 3 ++- t/51_badssl.com.t | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/t/10_baseline_ipv4_http.t b/t/10_baseline_ipv4_http.t index ec10bcd..1633945 100755 --- a/t/10_baseline_ipv4_http.t +++ b/t/10_baseline_ipv4_http.t @@ -7,6 +7,7 @@ # "finding" : "Scan interrupted" use strict; +use warnings; use Test::More; use Data::Dumper; use JSON; @@ -98,7 +99,7 @@ done_testing($tests); printf "\n\n"; -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; diff --git a/t/21_baseline_starttls.t b/t/21_baseline_starttls.t index ee1a0ac..a0360f7 100755 --- a/t/21_baseline_starttls.t +++ b/t/21_baseline_starttls.t @@ -10,6 +10,7 @@ # - Hosts which match the regex patterns should be avoided use strict; +use warnings; use Test::More; use Data::Dumper; # use JSON; @@ -150,7 +151,7 @@ if ( $os ne "darwin" ){ done_testing($tests); # unlink "tmp.json"; -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; diff --git a/t/23_client_simulation.t b/t/23_client_simulation.t index 107efcd..27fbcb9 100755 --- a/t/23_client_simulation.t +++ b/t/23_client_simulation.t @@ -7,6 +7,7 @@ # "finding" : "Scan interrupted" use strict; +use warnings; use Test::More; use Data::Dumper; # if needed: comment this and the lines below in: @@ -64,7 +65,7 @@ done_testing($tests); printf "\n"; -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; diff --git a/t/31_isJSON_valid.t b/t/31_isJSON_valid.t index 27ad4b2..07ac615 100755 --- a/t/31_isJSON_valid.t +++ b/t/31_isJSON_valid.t @@ -4,6 +4,7 @@ # use strict; +use warnings; use Test::More; use JSON; @@ -94,7 +95,7 @@ if ( $os eq "linux" ){ done_testing($tests); printf "\n\n"; -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; diff --git a/t/33_isJSON_severitylevel_valid.t b/t/33_isJSON_severitylevel_valid.t index a681507..d3c86e1 100755 --- a/t/33_isJSON_severitylevel_valid.t +++ b/t/33_isJSON_severitylevel_valid.t @@ -1,6 +1,7 @@ #!/usr/bin/env perl use strict; +use warnings; use Test::More; use Data::Dumper; use JSON; @@ -66,7 +67,7 @@ is($found,0,"We should not have any finding with INFO level"); $tests++; done_testing($tests); printf "\n\n"; -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; diff --git a/t/51_badssl.com.t b/t/51_badssl.com.t index 88c59fe..9ecaefc 100755 --- a/t/51_badssl.com.t +++ b/t/51_badssl.com.t @@ -1,6 +1,7 @@ #!/usr/bin/env perl use strict; +use warnings; use Test::More; use Data::Dumper; use JSON; @@ -154,7 +155,7 @@ is($found,1,"We should have a finding for this in the JSON output"); $tests++; done_testing($tests); -sub json($) { +sub json { my $file = shift; $file = `cat $file`; unlink $file; From 1880a06110ce7701a1ac8d29bbcf59aab2d004d3 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:27:44 +0200 Subject: [PATCH 10/15] Enable warnings --- t/01_testssl_banner.t | 1 + t/05_ca_hashes_up_to_date.t | 1 + 2 files changed, 2 insertions(+) diff --git a/t/01_testssl_banner.t b/t/01_testssl_banner.t index 4566655..4184010 100755 --- a/t/01_testssl_banner.t +++ b/t/01_testssl_banner.t @@ -4,6 +4,7 @@ # --banner is equal to --version use strict; +use warnings; use Test::More; my $tests = 0; diff --git a/t/05_ca_hashes_up_to_date.t b/t/05_ca_hashes_up_to_date.t index 4e58b40..2bba6c9 100755 --- a/t/05_ca_hashes_up_to_date.t +++ b/t/05_ca_hashes_up_to_date.t @@ -1,6 +1,7 @@ #!/usr/bin/env perl use strict; +use warnings; use Test::More; printf "\n%s\n", "Make sure CA certificate stores are older than their SPKI hashes \"~/etc/ca_hashes.txt\" ..."; From 4bab45231698e922471a428532f7f1416bbeb6d3 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:42:43 +0200 Subject: [PATCH 11/15] Fix syntax error --- t/00_testssl_help.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/00_testssl_help.t b/t/00_testssl_help.t index d19b4fe..19616b2 100755 --- a/t/00_testssl_help.t +++ b/t/00_testssl_help.t @@ -30,7 +30,7 @@ is($retMode & oct("400"), oct("0400"), "Checking \"./testssl.sh\" for read permi $tests++; #2 -is($retMode & oct("0100"), oct("0100)", "Checking \"./testssl.sh\" for execute permission"); +is($retMode & oct("0100"), oct("0100"), "Checking \"./testssl.sh\" for execute permission"); $tests++; $fileout = `bash $prg 2>&1`; From 6b1de564d85a884d80b5faf3ac3c90b6cb3c826a Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 15:49:31 +0200 Subject: [PATCH 12/15] Make the flow finally(TM) work --- .github/workflows/perl-quality.yml | 19 ++++++++++++------- .perlcritic | 17 ----------------- 2 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 .perlcritic diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index 79de397..695dc0f 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -20,22 +20,27 @@ jobs: - uses: shogo82148/actions-setup-perl@v1.43.1 with: perl-version: '5.38' + - name: Install dev modules run: cpanm --notest Perl::Critic Perl::Tidy CPAN::Audit - name: Install dev modules # add all perl modules from other modules tool, otherwise the next run fails run: cpanm --notest Data::Dumper IPC::Run3 JSON Test::More Text::Diff - - name: Syntax check all test files + + - name: 'Syntax check #1 w Perl::Tidy' + run: | + perltidy -se t/*.t + #TODO: we should as well reformat with the t(i)dy files generated + + - name: Syntax check all test files with perl itself run: | find t -name '*.t' -o -name '*.pm' | while read -r f; do perl -I t/lib -c "$f" done - - name: Perl::Critic - run: perlcritic --verbose '%f:%l:%e:%m\n' t/ - - name: perltidy (fail on diff) - run: | - perltidy -p t/ - git diff --exit-code + + - name: Use Perl::Critic for best practises + run: perlcritic -4 t/*.t + - name: Audit CPAN modules for known CVEs run: cpan-audit diff --git a/.perlcritic b/.perlcritic deleted file mode 100644 index 1695d0a..0000000 --- a/.perlcritic +++ /dev/null @@ -1,17 +0,0 @@ -# Perl::Critic policy overrides for the testssl.sh test suite (t/) -# -# see https://github.com/Perl-Critic/Perl-Critic - -# General setting: That would deliver way more -# severity = 3 - - -# Test helpers commonly use subroutine prototypes (e.g. sub helper ($$)); -# harmless in test code. -[Subroutines::ProhibitSubroutinePrototypes] -severity = 4 - -# Intentional octal file-permission literals (0400, 0100) in t/00_testssl_help.t. -[ValuesAndExpressions::ProhibitLeadingZeros] -severity = 4 - From bd67671fad8104df9322d44ef56c9787dd366ba2 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 16:19:52 +0200 Subject: [PATCH 13/15] double quoting needed in passed expression to grep --- t/03_syntax_check.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/03_syntax_check.t b/t/03_syntax_check.t index 586f47c..0d9fc1f 100755 --- a/t/03_syntax_check.t +++ b/t/03_syntax_check.t @@ -7,8 +7,8 @@ use warnings; use Test::More; my $tests = 0; -my $prg="testssl.sh"; -my $os="$^O"; +my $prg = "testssl.sh"; +my $os = "$^O"; if ( $os eq "darwin" ){ plan skip_all => 'No checks on MacOS'; @@ -28,7 +28,7 @@ $tests++; #2 printf "\n%s\n", "Testing for backticks ..."; -my @matches = qx(grep -nP '`[^`]*`' $prg); +@matches = qx(grep -nP '`[^`]*`' $prg); is(scalar(@matches), 0, "Checking bad backtick patterns") or diag(@matches); $tests++; @@ -36,7 +36,7 @@ $tests++; #3 printf "\n%s\n", "Sourcing without checking the file exists #1 ..."; -my @matches = qx(grep -nP '^\s*\.\s+\$' $prg); +@matches = qx(grep -nP '^\\s*\\.\\s+\\$' $prg); is(scalar(@matches), 0, "Checking bad sourcing pattern #1") or diag(@matches); $tests++; @@ -44,7 +44,7 @@ $tests++; #4 printf "\n%s\n", "Sourcing without checking the file exists #2 ..."; -my @matches = qx(grep -nP '^\s*source\s+\$' $prg); +@matches = qx(grep -nP '^\\s*source\\s+\\$' $prg); is(scalar(@matches), 0, "Checking bad sourcing pattern #2") or diag(@matches); $tests++; From c312fb82309fd5568c09171bc44cfbd18be5a3a5 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 16:29:16 +0200 Subject: [PATCH 14/15] Audit all modules but let for now exit the check always with zero --- .github/workflows/perl-quality.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/perl-quality.yml b/.github/workflows/perl-quality.yml index 695dc0f..a08e215 100644 --- a/.github/workflows/perl-quality.yml +++ b/.github/workflows/perl-quality.yml @@ -42,5 +42,6 @@ jobs: run: perlcritic -4 t/*.t - name: Audit CPAN modules for known CVEs - run: cpan-audit + run: cpan-audit installed --exit-zero + # logic is: in the container all should be fine. There are doubts though about deliberately unfixed ones From 8eb05bd8627e2d9117d24d66110d5373eb77cac2 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 1 Sep 2026 16:58:14 +0200 Subject: [PATCH 15/15] '$' should be passed to the shell not '\$' ... thus not double quoting like \\$ --- t/03_syntax_check.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/03_syntax_check.t b/t/03_syntax_check.t index 0d9fc1f..46872b4 100755 --- a/t/03_syntax_check.t +++ b/t/03_syntax_check.t @@ -36,7 +36,7 @@ $tests++; #3 printf "\n%s\n", "Sourcing without checking the file exists #1 ..."; -@matches = qx(grep -nP '^\\s*\\.\\s+\\$' $prg); +@matches = qx(grep -nP '^\\s*\\.\\s+\$' $prg); is(scalar(@matches), 0, "Checking bad sourcing pattern #1") or diag(@matches); $tests++; @@ -44,7 +44,7 @@ $tests++; #4 printf "\n%s\n", "Sourcing without checking the file exists #2 ..."; -@matches = qx(grep -nP '^\\s*source\\s+\\$' $prg); +@matches = qx(grep -nP '^\\s*source\\s+\$' $prg); is(scalar(@matches), 0, "Checking bad sourcing pattern #2") or diag(@matches); $tests++;