From 6a097f1d95b6d10df476e1e5a189f8175b79a3ee Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:36:17 -0300 Subject: [PATCH 01/10] remove tests/security-gate.t --- tests/security-gate.t | 179 ------------------------------------------ 1 file changed, 179 deletions(-) delete mode 100644 tests/security-gate.t diff --git a/tests/security-gate.t b/tests/security-gate.t deleted file mode 100644 index 146bf85..0000000 --- a/tests/security-gate.t +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use Test::More; -use Test::Exception; -use Test::MockObject; -use Test::Output; -use Carp qw(croak); -use Capture::Tiny qw(capture); -use Mojo::JSON qw(encode_json); - -local $ENV{TEST_MODE} = 1; - -my $mock_ua = Test::MockObject -> new(); -$mock_ua -> fake_module('Mojo::UserAgent'); -$mock_ua -> fake_new('Mojo::UserAgent'); - -require_ok('../security-gate.pl'); - -subtest 'Command-line argument parsing' => sub { - local @ARGV = (); - stdout_like( - sub { main() }, - qr/Security\ Gate\ v0\.0\.3/x, - 'Help message displayed when no arguments provided' - ); -}; - -subtest 'Severity counting' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', [ - { state => 'open', security_vulnerability => { severity => 'high' } }, - { state => 'open', security_vulnerability => { severity => 'critical' } }, - { state => 'open', security_vulnerability => { severity => 'medium' } }, - { state => 'closed', security_vulnerability => { severity => 'low' } }, - ]); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo'); - stdout_like( - sub { main() }, - qr/critical:\ 1.*high:\ 1.*medium:\ 1.*low:\ 0/xs, - 'Severity counts are correct' - ); -}; - -subtest 'Threshold checking' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', [ - { state => 'open', security_vulnerability => { severity => 'critical' } }, - { state => 'open', security_vulnerability => { severity => 'critical' } }, - ]); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo', '-c', '1'); - is( - scalar(main()), - 1, - 'Script exits with non-zero code when threshold is exceeded' - ); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo', '-c', '2'); - is( - scalar(main()), - 0, - 'Script exits with zero code when threshold is not exceeded' - ); -}; - -subtest 'Output formatting' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', [ - { state => 'open', security_vulnerability => { severity => 'high' } }, - { state => 'open', security_vulnerability => { severity => 'critical' } }, - ]); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo'); - - my $total_alerts_re = qr/\[!\]\ Total\ of\ security\ alerts:/x; - my $critical_alerts_re = qr/\[-\]\ critical:\ 1/x; - my $high_alerts_re = qr/\[-\]\ high:\ 1/x; - - stdout_like( - sub { main() }, - qr/$total_alerts_re.*$critical_alerts_re.*$high_alerts_re/xs, - 'Output is correctly formatted' - ); -}; - -subtest 'Invalid token or repository' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 401); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'invalid_token', '-r', 'invalid_repo'); - is( - scalar(main()), - 1, - 'Script exits with non-zero code when token or repository is invalid' - ); -}; - -subtest 'Empty response from GitHub API' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', []); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo'); - is( - scalar(main()), - 0, - 'Script exits with zero code when no alerts are found' - ); -}; - -subtest 'Multiple severity thresholds' => sub { - my $mock_response = Test::MockObject -> new(); - $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', [ - { state => 'open', security_vulnerability => { severity => 'high' } }, - { state => 'open', security_vulnerability => { severity => 'critical' } }, - { state => 'open', security_vulnerability => { severity => 'medium' } }, - ]); - - my $mock_tx = Test::MockObject -> new(); - $mock_tx -> set_always('result', $mock_response); - - $mock_ua -> set_always('get', $mock_tx); - - local @ARGV = ('-t', 'test_token', '-r', 'test_repo', '-c', '0', '-h', '0', '-m', '0', '-l', '0'); - - my ($stdout, $stderr, $result) = capture { - main(); - }; - - diag("STDOUT: $stdout"); - diag("STDERR: $stderr"); - diag("Result: $result"); - - is( - $result, - 1, - 'Script exits with non-zero code when multiple thresholds are exceeded' - ); - - like( - $stdout, - qr/Total\ of\ security\ alerts:/x, - 'Output contains expected content' - ); -}; - -done_testing(); From d6a889aa338fa813dccf94c69dbf9c3fa73d558d Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:37:25 -0300 Subject: [PATCH 02/10] test(no-open-secret-scanning-alerts): suppress 'used only once' warning for Mojo::UserAgent --- tests/no-open-secret-scanning-alerts.t | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/no-open-secret-scanning-alerts.t b/tests/no-open-secret-scanning-alerts.t index 0956440..2a42957 100644 --- a/tests/no-open-secret-scanning-alerts.t +++ b/tests/no-open-secret-scanning-alerts.t @@ -50,6 +50,7 @@ BEGIN { } } +no warnings 'once'; *Mojo::UserAgent::new = \&MockMojoUserAgent::new; subtest 'No open secret scanning alerts' => sub { From e9ed73c932f7e998e729f000d6e01112bc99fc8c Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:38:19 -0300 Subject: [PATCH 03/10] test(open-code-scanning-alerts): fix mock data to use correct severity field --- tests/open-code-scanning-alerts-exceeding-limits.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/open-code-scanning-alerts-exceeding-limits.t b/tests/open-code-scanning-alerts-exceeding-limits.t index cbe062b..bec2895 100644 --- a/tests/open-code-scanning-alerts-exceeding-limits.t +++ b/tests/open-code-scanning-alerts-exceeding-limits.t @@ -39,10 +39,10 @@ subtest 'Open code scanning alerts exceeding limits' => sub { my $mock_response = Mojo::UserAgent -> set_mock_response(Test::MockObject -> new); $mock_response -> set_always('code', 200); - $mock_response -> set_always('json', [ - { state => 'open', rule => { severity => 'high' } }, - { state => 'open', rule => { severity => 'high' } }, - { state => 'open', rule => { severity => 'medium' } }, + $mock_response->set_always('json', [ + { state => 'open', rule => { security_severity_level => 'high' } }, + { state => 'open', rule => { security_severity_level => 'high' } }, + { state => 'open', rule => { security_severity_level => 'medium' } }, ]); my %severity_limits = ( From b3bf36b4895a16f68856e5edd65bf5e9eb76d762 Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:39:56 -0300 Subject: [PATCH 04/10] test(open-secret-scanning-alerts-exceeding-limits): suppress 'used only once' warning for Mojo::UserAgent --- tests/open-secret-scanning-alerts-exceeding-limits.t | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/open-secret-scanning-alerts-exceeding-limits.t b/tests/open-secret-scanning-alerts-exceeding-limits.t index 9343b6e..2a7be62 100644 --- a/tests/open-secret-scanning-alerts-exceeding-limits.t +++ b/tests/open-secret-scanning-alerts-exceeding-limits.t @@ -50,6 +50,7 @@ BEGIN { } } +no warnings 'once'; *Mojo::UserAgent::new = \&MockMojoUserAgent::new; subtest 'Open secret scanning alerts exceeding limits' => sub { From 4d6756cfacc0fa0b69cb2764e73679f8ae69fd4c Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:41:39 -0300 Subject: [PATCH 05/10] test(open-secret-scanning-alerts-within-limits): suppress 'used only once' warning for Mojo::UserAgent - also renamed 'file1' to 'file' --- tests/open-secret-scanning-alerts-within-limits.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/open-secret-scanning-alerts-within-limits.t b/tests/open-secret-scanning-alerts-within-limits.t index 9deba7c..c6fb142 100644 --- a/tests/open-secret-scanning-alerts-within-limits.t +++ b/tests/open-secret-scanning-alerts-within-limits.t @@ -50,6 +50,7 @@ BEGIN { } } +no warnings 'once'; *Mojo::UserAgent::new = \&MockMojoUserAgent::new; subtest 'Open secret scanning alerts within limits' => sub { @@ -60,7 +61,7 @@ subtest 'Open secret scanning alerts within limits' => sub { ]); MockMojoUserAgent::setup_locations_response(200, [ - { path => 'file1.txt', start_line => 10 }, + { details => { path => 'file.txt', start_line => 10 } }, ]); my %severity_limits = ( @@ -73,7 +74,7 @@ subtest 'Open secret scanning alerts within limits' => sub { my $result; my $expected_output_part1 = qr/\[!\]\ Total\ of\ open\ secret\ scanning\ alerts:\ 1/xsm; my $expected_output_part2 = qr/\[-\]\ Alert\ 1\ found\ in\ the\ following\ locations:/xsm; - my $expected_output_part3 = qr/File:\ file1\.txt,\ Start\ line:\ 10/xsm; + my $expected_output_part3 = qr/File:\ file\.txt,\ Start\ line:\ 10/xsm; my $expected_output_part4_part1 = qr/\[-\]\ Number\ of\ secret\ scanning\ alerts\ \(/xsm; my $expected_output_part4_part2 = qr/1\)\ is\ within\ the\ acceptable\ limit\ \(/xsm; my $expected_output_part4_part3 = qr/1\)\./xsm; From d1c62f89d6bd9f4beea9d5522a55289f2c0b370e Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:44:27 -0300 Subject: [PATCH 06/10] test(secrets-api-error-handling): suppress 'used only once' warning for Mojo::UserAgent --- tests/secrets-api-error-handling.t | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/secrets-api-error-handling.t b/tests/secrets-api-error-handling.t index 1b60aef..e15735d 100644 --- a/tests/secrets-api-error-handling.t +++ b/tests/secrets-api-error-handling.t @@ -50,6 +50,7 @@ BEGIN { } } +no warnings 'once'; *Mojo::UserAgent::new = \&MockMojoUserAgent::new; subtest 'API error handling' => sub { From 6697cacbda094bbb89081bb39b8d0ed57560c948 Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 17:01:14 -0300 Subject: [PATCH 07/10] chore(linter): allow 'no warnings "once"' in .perlcriticrc - add TestingAndDebugging::ProhibitNoWarnings exception to .perlcriticrc - allow 'once' category to be disabled --- .perlcriticrc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.perlcriticrc b/.perlcriticrc index 61ab588..ff1aed2 100644 --- a/.perlcriticrc +++ b/.perlcriticrc @@ -1,4 +1,7 @@ severity = 3 [-TestingAndDebugging::RequireUseStrict] -[-TestingAndDebugging::RequireUseWarnings] \ No newline at end of file +[-TestingAndDebugging::RequireUseWarnings] + +[TestingAndDebugging::ProhibitNoWarnings] +allow = once From 95bd7078d131631e2b992a978bd1c1ecbdf0eeb7 Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Tue, 17 Sep 2024 17:19:50 -0300 Subject: [PATCH 08/10] chore: add test dependencies to cpanfile --- cpanfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpanfile b/cpanfile index 28a71c9..f447507 100644 --- a/cpanfile +++ b/cpanfile @@ -1,3 +1,11 @@ requires "Getopt::Long", "2.54"; requires "Mojo::JSON"; -requires "Mojo::UserAgent"; \ No newline at end of file +requires "Mojo::UserAgent"; + +on 'test' => sub { + requires "Test::More"; + requires "Test::Exception"; + requires "Test::MockObject"; + requires "Test::Output"; + requires "Capture::Tiny"; +}; From cf0154e2f4e3923967558b5cfaa084339adbc22c Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:57:45 -0300 Subject: [PATCH 09/10] =?UTF-8?q?ci:=20add=20workflow=20for=20running=20te?= =?UTF-8?q?st=C2=A0suite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-suite.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/test-suite.yml diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml new file mode 100644 index 0000000..ebb6352 --- /dev/null +++ b/.github/workflows/test-suite.yml @@ -0,0 +1,27 @@ +name: Test Suite + +on: + pull_request: + branches: + - main + - develop + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Perl + run: | + sudo apt-get update + sudo apt-get install -y perl + + - name: Install dependencies + run: cpanm --installdeps --with-test . + + - name: Run tests + working-directory: ./tests + run: prove -r From c866b3c2c53bd57708e151931b418e5ed4578342 Mon Sep 17 00:00:00 2001 From: priv <140729444+scriptprivate@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:08:14 -0300 Subject: [PATCH 10/10] update test-suite.yml --- .github/workflows/test-suite.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index ebb6352..89d2c1c 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -18,9 +18,10 @@ jobs: run: | sudo apt-get update sudo apt-get install -y perl + sudo apt-get install -y cpanminus - name: Install dependencies - run: cpanm --installdeps --with-test . + run: sudo cpanm --installdeps --with-test . - name: Run tests working-directory: ./tests