DevOps

Level-up your Rails Security with SonarQube Generic Issue Format

Sonarqube is a popular solution for static analysis of code for quality and security issues. It supports 27 different languages, and the list keeps growing. The range of coverage is one of Sonarqube’s great strengths, but unfortunately, it puts the product in a “jack of all trades, master of none” role.

If you are developing products in Ruby on Rails, you may have used Brakeman. I’ve yet to encounter a security scanning tool that does a better job on this framework. In short, I want to use Brakeman as the security tool for my rails projects, but I want the results in Sonarqube, side by side with the other projects I have in C#, NodeJs, PHP, and Python.

Contributing to Brakeman

How do we get this? By utilizing Sonarqube’s Generic Issue Format, and Brakeman’s flexible output pattern, we can stitch this together pretty easily. In short, the generic issue format allows you to import issues from almost any linter or analyzer, even without a specific plugin. Since Sonarqube has a generic format, the code changes we need are in the Brakeman source. Full source changes can be found here.

The key is creating a brakeman “report” to convert the brakeman output into the JSON format that Sonarqube requires. Mine looks like this:

class Brakeman::Report::Sonar < Brakeman::Report::Base
  def generate_report
    report_object = {
      issues: all_warnings.map { |warning| issue_json(warning) }
    }
    return JSON.pretty_generate report_object
  end
  
  private
  
  def issue_json(warning)
    {
      engineId: "Brakeman",
      ruleId: warning.warning_code,
      type: "VULNERABILITY",
      severity: severity_level_for(warning.confidence),
      primaryLocation: {
        message: warning.message,
        filePath: warning.file.relative,
        textRange: {
          "startLine": warning.line || 1,
          "endLine": warning.line || 1,
        }
      },
      effortMinutes: (4 - warning.confidence) * 15
    }
  end

  def severity_level_for(confidence)
    if confidence == 0
      "CRITICAL"
    elsif confidence == 1
      "MAJOR"
    else
      "MINOR"
    end
  end
end

Running the Scanner on your Code

This code will be included in the 5.0 release of Brakeman. In order to add this to your project, you’ll need to add it to your Gemfile

gem 'brakeman', '~> 5.0.0.pre1'

or install the gem locally

gem install brakeman --pre

Once you have the updated version of brakeman, you’ll need to make your Sonarqube runner aware of the content. I’ve done this using the sonar.project.properties file, you can also do it via command args.

sonar.externalIssuesReportPaths=brakeman/brakeman.json

Afterwards, you’ll run brakeman then run the sonar scanner tool to complete the analysis and send the data to your sonar server.

brakeman -o brakeman/output.sonar
sonar-scanner

Once everything is wired up correctly, you’ll get those wonderful brakeman warnings in your sonar issues list.

Whats next?

This is just an example of what you can do with a bit of code and the generic issue format. You can apply this pattern to a lot of different ruby plugins. If you work in a rails-only shop, you may find that you don’t need Sonarqube, but if you, like me, work in a polyglot company, you’ll find Sonarqube to be a flexible way to pull all your code under one roof.


Leave a Reply

Your email address will not be published. Required fields are marked *