From 49e670229890c23d91cff180631e2240b85d83c9 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Thu, 9 Jan 2020 17:41:31 +0300 Subject: [PATCH 1/4] feat(Security): add security report --- composer.json | 3 ++ src/SecurityReport.php | 83 ++++++++++++++++++++++++++++++++++++ tests/SecurityReportTest.php | 63 +++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 src/SecurityReport.php create mode 100644 tests/SecurityReportTest.php diff --git a/composer.json b/composer.json index c54e2c0..6f1f050 100644 --- a/composer.json +++ b/composer.json @@ -33,5 +33,8 @@ "psr-4": { "Satesh\\Phpcs\\": "src" } + }, + "scripts": { + "test": "./vendor/bin/phpunit" } } diff --git a/src/SecurityReport.php b/src/SecurityReport.php new file mode 100644 index 0000000..ded88e2 --- /dev/null +++ b/src/SecurityReport.php @@ -0,0 +1,83 @@ + 'Undefined', + 1 => 'Info', + 2 => 'Unknown', + 3 => 'Low', + 4 => 'Medium', + 5 => 'High', + 6 => 'Critical', + ]; + + /** + * {@inheritDoc} + */ + public function generateFileReport($report, File $phpcsFile = null, $showSources = false, $width = 80): bool + { + foreach ($report['messages'] as $line => $lineErrors) { + foreach ($lineErrors as $column => $columnErrors) { + foreach ($columnErrors as $error) { + $gitLabError = [ + 'category' => 'sast', + 'name' => rtrim($error['message'], '.'), + 'message' => rtrim($error['message'], '.'), + 'severity' => $this->getSeverity($error), + 'scanner' => [ + 'id' => 'phpcs_security_audit', + 'name' => 'phpcs-security-audit native', + ], + 'location' => [ + 'file' => $report['filename'], + 'start_line' => $line, + ], + 'identifiers' => [ + "type" => "phpcs_security_audit_source", + 'name' => $error['source'], + 'value' => $error['source'], + ] + ]; + + echo json_encode($gitLabError) . ','; + } + } + } + + return true; + } + + protected function getSeverity($error) { + switch ($error['type']) { + case "ERROR": + return "High"; + case "WARNING": + return "Low"; + default: + return "Undefined"; + } + } + + /** + * {@inheritDoc} + */ + public function generate( + $cachedData, + $totalFiles, + $totalErrors, + $totalWarnings, + $totalFixable, + $showSources = false, + $width = 80, + $interactive = false, + $toScreen = true + ): void { + echo '[' . rtrim($cachedData, ',') . ']'; + } +} diff --git a/tests/SecurityReportTest.php b/tests/SecurityReportTest.php new file mode 100644 index 0000000..68fad48 --- /dev/null +++ b/tests/SecurityReportTest.php @@ -0,0 +1,63 @@ +getGitLabReport(); + + $this->expectOutputString($reportOutput); + + $gitLabReport = new SecurityReport(); + + $returnValue = $gitLabReport->generateFileReport($this->getPhpcsReport()); + + static::assertTrue($returnValue); + + return $reportOutput; + } + + /** + * @depends testGenerateFileReport + */ + public function testGenerate(string $fileReport): void + { + $this->expectOutputString('[' . rtrim($fileReport, ',') . ']'); + + $gitLabReport = new SecurityReport(); + + $gitLabReport->generate($fileReport, 1, 1, 1, 1); + } + + private function getGitLabReport(): string + { + return '{"category":"sast","name":"PHP files must only contain PHP code","message":"PHP files must only contain PHP code","severity":"High","scanner":{"id":"phpcs_security_audit","name":"phpcs-security-audit native"},"location":{"file":"files\/TestClass.php","start_line":3},"identifiers":{"type":"phpcs_security_audit_source","name":"Generic.Files.InlineHTML.Found","value":"Generic.Files.InlineHTML.Found"}},'; + } + + private function getPhpcsReport(): array + { + return [ + 'filename' => 'files/TestClass.php', + 'errors' => 1, + 'warnings' => 0, + 'fixable' => 0, + 'messages' => [ + 3 => [ + 1 => [ + [ + 'message' => 'PHP files must only contain PHP code.', + 'source' => 'Generic.Files.InlineHTML.Found', + 'severity' => 5, + 'fixable' => false, + 'type' => 'ERROR', + ], + ], + ], + ], + ]; + } +} From c00b1d03cb6f3f99f75d5abfb45ab04f12a328e0 Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Thu, 9 Jan 2020 19:00:26 +0300 Subject: [PATCH 2/4] refactor(CodeQuality): rename report class --- src/{GitLabReport.php => CodeQualityReport.php} | 2 +- tests/{GitLabReportTest.php => CodeQualityReportTest.php} | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/{GitLabReport.php => CodeQualityReport.php} (97%) rename tests/{GitLabReportTest.php => CodeQualityReportTest.php} (89%) diff --git a/src/GitLabReport.php b/src/CodeQualityReport.php similarity index 97% rename from src/GitLabReport.php rename to src/CodeQualityReport.php index 44e512d..c6a0cfd 100644 --- a/src/GitLabReport.php +++ b/src/CodeQualityReport.php @@ -5,7 +5,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Reports\Report; -class GitLabReport implements Report +class CodeQualityReport implements Report { /** * {@inheritDoc} diff --git a/tests/GitLabReportTest.php b/tests/CodeQualityReportTest.php similarity index 89% rename from tests/GitLabReportTest.php rename to tests/CodeQualityReportTest.php index ef812f0..f32d83d 100644 --- a/tests/GitLabReportTest.php +++ b/tests/CodeQualityReportTest.php @@ -1,9 +1,9 @@ expectOutputString($reportOutput); - $gitLabReport = new GitLabReport(); + $gitLabReport = new CodeQualityReport(); $returnValue = $gitLabReport->generateFileReport($this->getPhpcsReport()); @@ -27,7 +27,7 @@ public function testGenerate(string $fileReport): void { $this->expectOutputString('[' . rtrim($fileReport, ',') . ']'); - $gitLabReport = new GitLabReport(); + $gitLabReport = new CodeQualityReport(); $gitLabReport->generate($fileReport, 1, 1, 1, 1); } From 012c2b30753e4ded5437af7dfaad714c01d8bfca Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Thu, 9 Jan 2020 19:28:27 +0300 Subject: [PATCH 3/4] fix(Security): fix complete report generator --- src/SecurityReport.php | 6 +++++- tests/SecurityReportTest.php | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/SecurityReport.php b/src/SecurityReport.php index ded88e2..dd4d741 100644 --- a/src/SecurityReport.php +++ b/src/SecurityReport.php @@ -78,6 +78,10 @@ public function generate( $interactive = false, $toScreen = true ): void { - echo '[' . rtrim($cachedData, ',') . ']'; + echo '{'; + echo '"version": "2.0", '; + echo '"vulnerabilities": [' . rtrim($cachedData, ',') . '], '; + echo '"remediations": []'; + echo '}'; } } diff --git a/tests/SecurityReportTest.php b/tests/SecurityReportTest.php index 68fad48..6fed2f9 100644 --- a/tests/SecurityReportTest.php +++ b/tests/SecurityReportTest.php @@ -26,7 +26,7 @@ public function testGenerateFileReport(): string */ public function testGenerate(string $fileReport): void { - $this->expectOutputString('[' . rtrim($fileReport, ',') . ']'); + $this->expectOutputString($this->getGitLabCompleteReport()); $gitLabReport = new SecurityReport(); @@ -38,6 +38,11 @@ private function getGitLabReport(): string return '{"category":"sast","name":"PHP files must only contain PHP code","message":"PHP files must only contain PHP code","severity":"High","scanner":{"id":"phpcs_security_audit","name":"phpcs-security-audit native"},"location":{"file":"files\/TestClass.php","start_line":3},"identifiers":{"type":"phpcs_security_audit_source","name":"Generic.Files.InlineHTML.Found","value":"Generic.Files.InlineHTML.Found"}},'; } + private function getGitLabCompleteReport(): string + { + return '{"version": "2.0", "vulnerabilities": [' . rtrim($this->getGitLabReport(), ',') . '], "remediations": []}'; + } + private function getPhpcsReport(): array { return [ From db04c650f89d86e58084f9ac4e0be2017721279c Mon Sep 17 00:00:00 2001 From: Leonid Meleshin Date: Thu, 9 Jan 2020 20:23:06 +0300 Subject: [PATCH 4/4] docs(Readme): add usage --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/README.md b/README.md index d04f5d7..9ee641a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,53 @@ # PHPCS GitLab Report [![Build Status](https://travis-ci.org/sateshpersaud/phpcs-gitlab-report.svg?branch=master)](https://travis-ci.org/sateshpersaud/phpcs-gitlab-report) + +## Usage + +### Code Quality + +```yaml +# .gitlab-ci.yml + +code_quality: + image: lorisleiva/laravel-docker:7.2 + stage: test + script: + - php ./vendor/bin/phpcs \ + --report=\\Satesh\\Phpcs\\CodeQualityReport \ + --standard=PSR2 \ + --basepath=./ \ + --report-file=gl-code-quality-report.json \ + src + artifacts: + reports: + codequality: gl-code-quality-report.json + paths: + - ./gl-code-quality-report.json + allow_failure: true +``` + + +### SAST + +*Note: use with [pheromone/phpcs-security-audit](https://github.com/FloeDesignTechnologies/phpcs-security-audit)* + +```yaml +# .gitlab-ci.yml + +phpcs-security-audit-sast: + stage: test + script: + - php ./vendor/bin/phpcs \ + --report=\\Satesh\\Phpcs\\SecurityReport \ + --standard=./vendor/pheromone/phpcs-security-audit/example_base_ruleset.xml \ + --basepath=./ \ + --report-file=gl-sast-report.json \ + src + artifacts: + reports: + sast: gl-sast-report.json + paths: + - ./gl-sast-report.json + allow_failure: true +```