Skip to content

Commit

Permalink
Add SARIF as report output
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasReschke committed Nov 17, 2020
1 parent 4e8fb9c commit 43d9237
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 2 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: "Upload SARIF"

# Run workflow each time code is pushed to your repository and on a schedule.
# The scheduled workflow runs every at 00:00 on Sunday UTC time.
on:
push:

jobs:
build:
runs-on: ubuntu-latest
steps:
# This step checks out a copy of your repository.
- name: Checkout repository
uses: actions/checkout@v2
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v1
with:
# Path to SARIF file relative to the root of the repository
sarif_file: foo.sarif
1 change: 1 addition & 0 deletions foo.sarif
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"2.1.0","runs":[{"tool":{"driver":{"name":"Psalm","version":"dev-master@4e8fb9c37f182f9f556f2d2d95d7e1d824490175","rules":[{"id":"205","name":"TaintedInput","shortDescription":{"text":"TaintedInput"},"properties":{"tags":["security"]},"help":{"markdown":"# TaintedInput\n\nEmitted when tainted input detection is turned on\n","text":"# TaintedInput\n\nEmitted when tainted input detection is turned on\n"}}]}},"results":[{"ruleId":"205","message":{"text":"Detected tainted shell"},"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":3,"endLine":3,"startColumn":12,"endColumn":24}}}],"codeFlows":[{"message":{"text":"Tracing the path from user input to insecure usage"},"threadFlows":[{"locations":[{"location":{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":3,"endLine":3,"startColumn":12,"endColumn":17}}}},{"location":{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":3,"endLine":3,"startColumn":12,"endColumn":24}}}}]}]}]},{"ruleId":"205","message":{"text":"Detected tainted html"},"level":"error","locations":[{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":4,"endLine":4,"startColumn":6,"endColumn":19}}}],"codeFlows":[{"message":{"text":"Tracing the path from user input to insecure usage"},"threadFlows":[{"locations":[{"location":{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":4,"endLine":4,"startColumn":6,"endColumn":12}}}},{"location":{"physicalLocation":{"artifactLocation":{"uri":"test.php"},"region":{"startLine":4,"endLine":4,"startColumn":6,"endColumn":19}}}}]}]}]}]}]}
1 change: 1 addition & 0 deletions src/Psalm/Internal/Analyzer/ProjectAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ public static function getFileReportOptions(array $report_file_paths, bool $show
'.emacs' => Report::TYPE_EMACS,
'.pylint' => Report::TYPE_PYLINT,
'.console' => Report::TYPE_CONSOLE,
'.sarif' => Report::TYPE_SARIF,
];

foreach ($report_file_paths as $report_file_path) {
Expand Down
5 changes: 5 additions & 0 deletions src/Psalm/IssueBuffer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use Psalm\Report\ConsoleReport;
use Psalm\Report\EmacsReport;
use Psalm\Report\GithubActionsReport;
use Psalm\Report\SarifReport;
use Psalm\Report\JsonReport;
use Psalm\Report\JsonSummaryReport;
use Psalm\Report\JunitReport;
Expand Down Expand Up @@ -755,6 +756,10 @@ public static function getOutput(
case Report::TYPE_PHP_STORM:
$output = new PhpStormReport($normalized_data, self::$fixable_issue_counts, $report_options);
break;

case Report::TYPE_SARIF:
$output = new SarifReport($normalized_data, self::$fixable_issue_counts, $report_options);
break;
}

return $output->create();
Expand Down
2 changes: 2 additions & 0 deletions src/Psalm/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ abstract class Report
public const TYPE_TEXT = 'text';
public const TYPE_GITHUB_ACTIONS = 'github';
public const TYPE_PHP_STORM = 'phpstorm';
public const TYPE_SARIF = 'sarif';

public const SUPPORTED_OUTPUT_TYPES = [
self::TYPE_COMPACT,
Expand All @@ -34,6 +35,7 @@ abstract class Report
self::TYPE_TEXT,
self::TYPE_GITHUB_ACTIONS,
self::TYPE_PHP_STORM,
self::TYPE_SARIF,
];

/**
Expand Down
129 changes: 129 additions & 0 deletions src/Psalm/Report/SarifReport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
namespace Psalm\Report;

use Psalm\Internal\Json\Json;
use function max;
use Psalm\Config;
use Psalm\Issue;
use Psalm\Report;
use function file_exists;
use function file_get_contents;

/**
* SARIF report format suitable for import into any SARIF compatible solution
*
* https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/sarif-v2.1.0-cs01.html
*/
class SarifReport extends Report
{
public function create(): string
{
$report = [
'version' => '2.1.0',
'runs' => [
[
'tool' => [
'driver' => [
'name' => 'Psalm',
'version' => PSALM_VERSION,
],
],
'results' => [],
],
],
];

$rules = [];

foreach ($this->issues_data as $issue_data) {
$rules[$issue_data->shortcode] = [
'id' => (string)$issue_data->shortcode,
'name' => $issue_data->type,
'shortDescription' => [
'text' => $issue_data->type,
],
'properties' => [
'tags' => [
($issue_data->shortcode == Issue\TaintedInput::SHORTCODE) ? 'security' : 'maintainability',
],
],
];

$markdown_documentation_path = __DIR__ . '/../../../docs/running_psalm/issues/' . $issue_data->type . '.md';
if (file_exists($markdown_documentation_path)) {
$markdown_documentation = file_get_contents($markdown_documentation_path);
$rules[$issue_data->shortcode]['help']['markdown'] = $markdown_documentation;
$rules[$issue_data->shortcode]['help']['text'] = $markdown_documentation;
}

$jsonEntry = [
'ruleId' => (string)$issue_data->shortcode,
'message' => [
'text' => $issue_data->message,
],
'level' => ($issue_data->severity === Config::REPORT_ERROR) ? 'error' : 'note',
'locations' => [
[
'physicalLocation' => [
'artifactLocation' => [
'uri' => $issue_data->file_name,
],
'region' => [
'startLine' => $issue_data->line_from,
'endLine' => $issue_data->line_to,
'startColumn' => $issue_data->column_from,
'endColumn' => $issue_data->column_to,
],
],
]
],
];

if ($issue_data->taint_trace != null) {
$jsonEntry['codeFlows'] = [
[
'message' => [
'text' => 'Tracing the path from user input to insecure usage',
],
'threadFlows' => [
[
'locations' => [],
],
],
]
];

/** @var \Psalm\Internal\Analyzer\DataFlowNodeData $trace */
foreach ($issue_data->taint_trace as $trace) {
if (isset($trace->line_from)) {
$jsonEntry['codeFlows'][0]['threadFlows'][0]['locations'][] = [
'location' => [
'physicalLocation' => [
'artifactLocation' => [
'uri' => $trace->file_name,
],
'region' => [
'startLine' => $trace->line_from,
'endLine' => $trace->line_to,
'startColumn' => $trace->column_from,
'endColumn' => $trace->column_to,
],
],
],
];
}
}
}

$report['runs'][0]['results'][] = $jsonEntry;
}

foreach ($rules as $rule) {
$report['runs'][0]['tool']['driver']['rules'][] = $rule;
}

$options = $this->pretty ? Json::PRETTY : Json::DEFAULT;

return Json::encode($report, $options) . "\n";
}
}
2 changes: 1 addition & 1 deletion src/command_functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ function getPsalmHelpText(): string
--report=PATH
The path where to output report file. The output format is based on the file extension.
(Currently supported formats: ".json", ".xml", ".txt", ".emacs", ".pylint", ".console",
"checkstyle.xml", "sonarqube.json", "summary.json", "junit.xml")
".sarif", "checkstyle.xml", "sonarqube.json", "summary.json", "junit.xml")
--report-show-info[=BOOLEAN]
Whether the report should include non-errors in its output (defaults to true)
Expand Down
4 changes: 4 additions & 0 deletions test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

shell_exec($_GET['foo']);
echo $_POST['far'];

0 comments on commit 43d9237

Please sign in to comment.