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.