Library to write SARIF files from Perl
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE.txt Added licenses Sep 21, 2018
README.adoc Support latest sarif version Nov 20, 2018
SarifJsonWriter.pm

README.adoc

SWAMP SARIF IO Libraries

Module Version: 0.8.3

Last updated on 11-20-2018

Sarif version currently tracking: 2.0.0-csd.2.beta.2018-10-10

Name

swamp-sarif-io - Library to write SARIF files from Perl

Description

The Software Assurance Marketplace (SWAMP) runs software assurance tools, and converts the results of each tool into a common format called SCARF (SWAMP Common Assessment Result Format). There is now a new format being developed by OASIS called SARIF. This repository contains a set of libraries that allows a program to write SARIF data from programs written in Perl.

Documentation for SCARF is available here. Documentation for SARIF is available here.

Synopsis

An example of a normal usage where the assessment ran successfully:

use SarifJsonWriter;

my $output = "/path/to/file.sarif"
my $writer = new SarifJsonWriter($output, "utf-8");

my $defaultPretty = $writer->GetPretty();
$writer->SetPretty(1);

my $defaultErrorLevel = $writer->GetErrorLevel();
$writer->SetErrorLevel(2);

my @errors = ();
push @errors, CheckStart($initialData);
push @errors, CheckStart($bugData);

$writer->AddStartTag($initialData);
$writer->AddBugInstance($bugData);
$writer->Close();

An example usage where the assessment was either unable to run or failed:

use SarifJsonWriter;

my $output = "/path/to/file.sarif"
my $writer = new SarifJsonWriter($output, "utf-8");

$writer->SetPretty(1);

$writer->AddFailure($failureData);

Output

Significant SARIF properties included in the generated SARIF files:

{
  version: "...",
  $schema: "...",
  runs: [
    {
      instanceGuid: "...",
      tool: { ... },
      invocations: [ ... ],
      conversion: { ... },
      originalUriBaseIds: { ... },
      files: [ ... ],
      logicalLocations: { ... },
      results: [
        {
          ruleId: "...",
          level: "...",
          message: "...",
          locations: [ ... ], # including line, column, snippets
          codeFlows: [ ... ],
          conversionProvenance: { ... },
          properties: { tags: [], ... },
        }, ...
      ]
    }, ...
  ]
}

Requirements

The following Perl libraries should be installed for the program to work correctly:

  • JSON::Streaming::Writer

Subroutines

new($output_file, $encoding)

This is the subroutine used to instantiate the writer. This subroutine expects two parameters, which are the output file name and the encoding. Only the "utf-8" encoding is supported right now.

SetPretty($value)

Sets whether the writer pretty prints (meaning add indentation). Writer will pretty print if $value is true, and will not pretty print if $value is false. Default value is 0 (false).

GetPretty()

Returns a boolean that shows whether the writer currently pretty prints. 0 (false) is the default.

SetErrorLevel($error_level)

Sets how program handle errors. 0 means do nothing; 1 means just print the error; 2 means print the error and die. 2 is the default value.

GetErrorLevel()

Returns the error level currently set. 2 is the default value.

CheckStart($initialData)

Checks whether the required fields in the data structure are set. Program either does nothing, just print errors or dies depending on the error level set.

CheckBug($bugData)

Checks whether the required fields in the data structure are set. Program either does nothing, just print errors or dies depending on the error level set.

AddStartTag($initialData)

This subroutine writes to the SARIF file data that applies to the whole assessment.

AddBugInstance($bugData)

Every BugInstance in a SCARF file maps to a result object in SARIF. This subroutine writes necessary data from a BugInstance to a result object, as well as storing some data that will be written by the Close() subroutine (when all BugInstances are read). This subroutine should be called after AddStartTag($initialData).

Close()

This subroutine should be called after all BugInstances are read, which is after AddBugInstance($bugData). Data saved from initialData and bugData are written out here and the SARIF file is also closed here.

AddFailure($failureData)

The only method to call after new() when there is a failure. This subroutine writes a sarif file containing only the conversion object in the run object. Inside the conversion object is the property "toolNotifications" which will contain the error message.

Data Structures

The following are the data structures used in the callbacks listed above:

$initialData

initialData contains information regarding the assessment.

{
  build_root_dir     => PACKAGE_DIRECTORY,                        # REQUIRED
  package_root_dir   => DIRECTORY_CONTAINING_PACKAGE,             # REQUIRED
  results_root_dir   => DIRECTORY_CONTAINING_ASSESSMENT_REPORTS,  # REQUIRED
  uuid               => UUIDVALUE,                                # REQUIRED
  tool_name          => TOOL_NAME,                                # REQUIRED
  tool_version       => TOOL_VERSION,                             # REQUIRED
  package_name       => PACKAGE_NAME,                             # REQUIRED
  package_version    => PACKAGE_VERSION                           # REQUIRED
  conversion         => (SEE BELOW),
  sha256hashes       => (SEE BELOW),
  invocations        => (SEE BELOW),
  buildDir           => BUILD_DIR_PATH
}

$conversion

This hash contains information required to write the conversion object in SARIF. All fields are required.

{
  tool_name             => TOOL_NAME,
  tool_version          => TOOL_VERSION,
  commandLine           => PROGRAM_NAME,
  workingDirectory      => WORKING_DIRECTORY,
  argv => [
    'ARG1', 'ARG2', ...  # ARGUMENTS
  ],
  env => {               # ENVIRONMENT_VARIABLES
    'key1' => 'value1',
    'key2' => 'value2',
    ...
  }
  startTime             => PROGRAM_START_TIME
}

$sha256hashes

This hash contains the sha256 hashes for all files used in the assessment.

{
  /path/to/file1 => SHA256 VALUE FOR FILE1,
  /path/to/file2 => SHA256 VALUE FOR FILE2,
  ...
}

$invocations

This hash contains the information related to the invocation(s) of the tool

{
  packageRootDir            => PACKAGE_ROOT_DIR_VALUE,
  assessments => [
    {
      commandLine           => COMMAND_LINE_VALUE,
      startTime             => INVOCATION_START_TIME,
      endTime               => INVOCATION_END_TIME,
      workingDirectory      => WORKING_DIRECTORY,
      exitCode              => EXIT_CODE_VALUE,
      args => [
        'ARG1', 'ARG2', ...  # ARGUMENTS
      ],
      env => {               # ENVIRONMENT_VARIABLES
        'key1' => 'value1',
        'key2' => 'value2',
        ...
      },
      report                => ASSESSMENT_REPORT_FILE
    },
    ...
  ]
}

$bugData

Each bugData hash contains information on one bug instance. Fields marked as required must be present. If both BugGroup and BugCode are not present, the ruleId for the corresponding result object in sarif will be set to "__UNKNOWN__".

{
  BugGroup              => GROUP_VALUE,
  BugCode               => CODE_VALUE,
  BugMessage            => BUG_MESSAGE_VALUE,           # REQUIRED
  BugLocations  => [
    {
      SourceFile        => SOURCE_FILE_NAME,            # REQUIRED
      StartLine         => START_LINE,
      EndLine           => END_LINE,
      StartColumn       => START_COLUMN,
      EndColumn         => END_COLUMN,
      primary           => PRIMARY_VALUE,
      Explanation       => EXPLANATION_VALUE
    },
    ...
  ],
  AssessmentReportFile  => ASSESSMENT_REPORT_FILE_NAME,
  ClassName             => CLASS_NAME_VALUE,
  Methods => [
    {
      name              => METHODNAMEVALUE,             # REQUIRED
    },
    ...
  ],
  BugSeverity           => SEVERITY_VALUE,
  CweIds => [
    CWEIDVALUE, CWEIDVALUE, ...
  ],
}

$failureData

This hash contains all the information needed to write to a sarif file in the case that the converter finds that the assessment failed. All fields listed below are required.

{
  conversion            => (SEE ABOVE),                 # REQUIRED
  tool => {
    tool_name           => TOOL_NAME,                   # REQUIRED
  },
  message               => ERROR_MESSAGE                # REQUIRED
}