adapter for brakeman

This commit is contained in:
Miguel Savignano 2019-11-01 18:37:30 +01:00
parent 144099eee3
commit ef286dea64
13 changed files with 327 additions and 3375 deletions

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
spec
Gemfile
Gemfile.lock
LICENSE
README.md

View File

@ -1,18 +1,15 @@
FROM ruby:2.6.5-alpine
RUN apk add --update build-base git
LABEL "com.github.actions.name"="Rubocop Linter"
LABEL "com.github.actions.description"="A GitHub Action that lints your Ruby code with Rubocop!"
LABEL "com.github.actions.name"="Brakeman linter"
LABEL "com.github.actions.description"="A GitHub Action that lints your Ruby code with Brakeman!"
LABEL "com.github.actions.icon"="code"
LABEL "com.github.actions.color"="red"
LABEL "repository"="https://github.com/andrewmcodes/rubocop-linter-action"
LABEL "maintainer"="Andrew Mason <andrewmcodes@protonmail.com>"
LABEL "repository"="https://github.com/devmasx/brakeman-linter-action"
LABEL "maintainer"="Miguel Savignano <migue.masx@gmail.com>"
LABEL "version"="1.0.0"
RUN gem install brakeman
COPY lib /action/lib
RUN gem install bundler
ENTRYPOINT ["/action/lib/entrypoint.sh"]
CMD ["ruby", "/action/lib/index.rb"]

View File

@ -1,8 +1,8 @@
{
"repository": {
"owner": {
"login": "andrewmcodes"
}
,"name": "rubocop-linter"
"login": "devmasx"
},
"name": "brakeman-linter"
}
}

View File

@ -1,7 +0,0 @@
#!/bin/sh
set -e
gem install rubocop rubocop-performance rubocop-rails rubocop-minitest rubocop-rspec
ruby /action/lib/index.rb

View File

@ -7,7 +7,7 @@ class GithubCheckRunService
@report = report
@github_data = github_data
@report_adapter = report_adapter
@client = GithubClient.new(@github_data[:token], user_agent: 'rubocop-action')
@client = GithubClient.new(@github_data[:token], user_agent: 'brakeman-action')
end
def run

View File

@ -23,7 +23,7 @@ end
if ENV['REPORT_PATH']
read_json(ENV['REPORT_PATH'])
else
Dir.chdir(ENV['GITHUB_WORKSPACE']) { JSON.parse(`rubocop -f json`) }
Dir.chdir(ENV['GITHUB_WORKSPACE']) { JSON.parse(`brakeman -f json`) }
end
GithubCheckRunService.new(@report, @github_data, ReportAdapter).run

View File

@ -1,54 +1,38 @@
# frozen_string_literal: true
# https://developer.github.com/v3/checks/runs/#output-object
class ReportAdapter
class << self
CONCLUSION_TYPES = { failure: 'failure', success: 'success' }.freeze
ANNOTATION_LEVELS = {
'refactor' => 'failure',
'convention' => 'failure',
'warning' => 'warning',
'error' => 'failure',
'fatal' => 'failure'
}.freeze
ANNOTATION_LEVEL = { notice: 'notice', warning: 'warning', failure: 'failure' }.freeze
def conslusion(report)
return CONCLUSION_TYPES[:failure] if total_offenses(report).positive?
return CONCLUSION_TYPES[:failure] if security_warnings(report).positive?
CONCLUSION_TYPES[:success]
end
def summary(report)
"#{total_offenses(report)} offense(s) found"
"**Brakeman Report**: \n - #{security_warnings(report)} security warnings"
end
def annotations(report)
annotation_list = []
count = 0
report['files'].each do |file|
file['offenses'].each do |offense|
count += 1
return annotation_list if count == 48
location = offense['location']
annotation_list.push(
'path' => file['path'],
'start_line' => location['start_line'],
'end_line' => location['last_line'],
'annotation_level' => annotation_level(offense['severity']),
'message' => offense['message']
)
end
report['warnings'].map do |error|
{
'path' => error['file'],
'start_line' => error['line'],
'end_line' => error['line'],
'annotation_level' => ANNOTATION_LEVEL[:warning],
'title' => "#{error['confidence']} - #{error['check_name']}",
'message' => error['message']
}
end
end
private
def annotation_level(severity)
ANNOTATION_LEVELS[severity]
end
def total_offenses(report)
report.dig('summary', 'offense_count')
def security_warnings(report)
report['scan_info']['security_warnings']
end
end
end

171
spec/fixtures/event.json vendored Normal file
View File

@ -0,0 +1,171 @@
{
"after": "6668752dba6d4f1b1e72e88f7355889cc039176c",
"base_ref": null,
"before": "64bf02a0916fab1a4f5e91a7cd44068302cd31f7",
"commits": [
{
"author": {
"email": "migue.masx@gmail.com",
"name": "Miguel Savignano",
"username": "MiguelSavignano"
},
"committer": {
"email": "migue.masx@gmail.com",
"name": "Miguel Savignano",
"username": "MiguelSavignano"
},
"distinct": true,
"id": "6668752dba6d4f1b1e72e88f7355889cc039176c",
"message": ".",
"timestamp": "2019-10-24T01:13:19+02:00",
"tree_id": "b99d954a0de55070aec5999d530dd7438210f594",
"url": "https://github.com/MiguelSavignano/dockerize-rails/commit/6668752dba6d4f1b1e72e88f7355889cc039176c"
}
],
"compare": "https://github.com/MiguelSavignano/dockerize-rails/compare/64bf02a0916f...6668752dba6d",
"created": false,
"deleted": false,
"forced": false,
"head_commit": {
"author": {
"email": "migue.masx@gmail.com",
"name": "Miguel Savignano",
"username": "MiguelSavignano"
},
"committer": {
"email": "migue.masx@gmail.com",
"name": "Miguel Savignano",
"username": "MiguelSavignano"
},
"distinct": true,
"id": "6668752dba6d4f1b1e72e88f7355889cc039176c",
"message": ".",
"timestamp": "2019-10-24T01:13:19+02:00",
"tree_id": "b99d954a0de55070aec5999d530dd7438210f594",
"url": "https://github.com/MiguelSavignano/dockerize-rails/commit/6668752dba6d4f1b1e72e88f7355889cc039176c"
},
"pusher": {
"email": "migue.masx@gmail.com",
"name": "MiguelSavignano"
},
"ref": "refs/heads/test-brakeman-errros",
"repository": {
"archive_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/{archive_format}{/ref}",
"archived": false,
"assignees_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/assignees{/user}",
"blobs_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/git/blobs{/sha}",
"branches_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/branches{/branch}",
"clone_url": "https://github.com/MiguelSavignano/dockerize-rails.git",
"collaborators_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/collaborators{/collaborator}",
"comments_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/comments{/number}",
"commits_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/commits{/sha}",
"compare_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/compare/{base}...{head}",
"contents_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/contents/{+path}",
"contributors_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/contributors",
"created_at": 1546466490,
"default_branch": "master",
"deployments_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/deployments",
"description": "Example rails with docker, docker-compose and minikube. Use worker with sidekiq and nginx web server.",
"disabled": false,
"downloads_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/downloads",
"events_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/events",
"fork": false,
"forks": 1,
"forks_count": 1,
"forks_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/forks",
"full_name": "MiguelSavignano/dockerize-rails",
"git_commits_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/git/commits{/sha}",
"git_refs_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/git/refs{/sha}",
"git_tags_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/git/tags{/sha}",
"git_url": "git://github.com/MiguelSavignano/dockerize-rails.git",
"has_downloads": true,
"has_issues": true,
"has_pages": false,
"has_projects": true,
"has_wiki": true,
"homepage": null,
"hooks_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/hooks",
"html_url": "https://github.com/MiguelSavignano/dockerize-rails",
"id": 163894157,
"issue_comment_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/issues/comments{/number}",
"issue_events_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/issues/events{/number}",
"issues_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/issues{/number}",
"keys_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/keys{/key_id}",
"labels_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/labels{/name}",
"language": "Ruby",
"languages_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/languages",
"license": null,
"master_branch": "master",
"merges_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/merges",
"milestones_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/milestones{/number}",
"mirror_url": null,
"name": "dockerize-rails",
"node_id": "MDEwOlJlcG9zaXRvcnkxNjM4OTQxNTc=",
"notifications_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/notifications{?since,all,participating}",
"open_issues": 0,
"open_issues_count": 0,
"owner": {
"avatar_url": "https://avatars3.githubusercontent.com/u/6641863?v=4",
"email": "migue.masx@gmail.com",
"events_url": "https://api.github.com/users/MiguelSavignano/events{/privacy}",
"followers_url": "https://api.github.com/users/MiguelSavignano/followers",
"following_url": "https://api.github.com/users/MiguelSavignano/following{/other_user}",
"gists_url": "https://api.github.com/users/MiguelSavignano/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/MiguelSavignano",
"id": 6641863,
"login": "MiguelSavignano",
"name": "MiguelSavignano",
"node_id": "MDQ6VXNlcjY2NDE4NjM=",
"organizations_url": "https://api.github.com/users/MiguelSavignano/orgs",
"received_events_url": "https://api.github.com/users/MiguelSavignano/received_events",
"repos_url": "https://api.github.com/users/MiguelSavignano/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/MiguelSavignano/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/MiguelSavignano/subscriptions",
"type": "User",
"url": "https://api.github.com/users/MiguelSavignano"
},
"private": false,
"pulls_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/pulls{/number}",
"pushed_at": 1571872407,
"releases_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/releases{/id}",
"size": 249,
"ssh_url": "git@github.com:MiguelSavignano/dockerize-rails.git",
"stargazers": 1,
"stargazers_count": 1,
"stargazers_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/stargazers",
"statuses_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/statuses/{sha}",
"subscribers_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/subscribers",
"subscription_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/subscription",
"svn_url": "https://github.com/MiguelSavignano/dockerize-rails",
"tags_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/tags",
"teams_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/teams",
"trees_url": "https://api.github.com/repos/MiguelSavignano/dockerize-rails/git/trees{/sha}",
"updated_at": "2019-04-10T17:03:40Z",
"url": "https://github.com/MiguelSavignano/dockerize-rails",
"watchers": 1,
"watchers_count": 1
},
"sender": {
"avatar_url": "https://avatars3.githubusercontent.com/u/6641863?v=4",
"events_url": "https://api.github.com/users/MiguelSavignano/events{/privacy}",
"followers_url": "https://api.github.com/users/MiguelSavignano/followers",
"following_url": "https://api.github.com/users/MiguelSavignano/following{/other_user}",
"gists_url": "https://api.github.com/users/MiguelSavignano/gists{/gist_id}",
"gravatar_id": "",
"html_url": "https://github.com/MiguelSavignano",
"id": 6641863,
"login": "MiguelSavignano",
"node_id": "MDQ6VXNlcjY2NDE4NjM=",
"organizations_url": "https://api.github.com/users/MiguelSavignano/orgs",
"received_events_url": "https://api.github.com/users/MiguelSavignano/received_events",
"repos_url": "https://api.github.com/users/MiguelSavignano/repos",
"site_admin": false,
"starred_url": "https://api.github.com/users/MiguelSavignano/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/MiguelSavignano/subscriptions",
"type": "User",
"url": "https://api.github.com/users/MiguelSavignano"
}
}

107
spec/fixtures/input.json vendored Normal file
View File

@ -0,0 +1,107 @@
{
"scan_info": {
"app_path": "/home/miguemasx/developer/dockerize-rails",
"rails_version": "5.2.2",
"security_warnings": 1,
"start_time": "2019-10-25 11:25:31 +0200",
"end_time": "2019-10-25 11:25:31 +0200",
"duration": 0.108293375,
"checks_performed": [
"BasicAuth",
"BasicAuthTimingAttack",
"ContentTag",
"CookieSerialization",
"CreateWith",
"CrossSiteScripting",
"DefaultRoutes",
"Deserialize",
"DetailedExceptions",
"DigestDoS",
"DynamicFinders",
"EscapeFunction",
"Evaluation",
"Execute",
"FileAccess",
"FileDisclosure",
"FilterSkipping",
"ForgerySetting",
"HeaderDoS",
"I18nXSS",
"JRubyXML",
"JSONEncoding",
"JSONParsing",
"LinkTo",
"LinkToHref",
"MailTo",
"MassAssignment",
"MimeTypeDoS",
"ModelAttrAccessible",
"ModelAttributes",
"ModelSerialize",
"NestedAttributes",
"NestedAttributesBypass",
"NumberToCurrency",
"PermitAttributes",
"QuoteTableName",
"Redirect",
"RegexDoS",
"Render",
"RenderDoS",
"RenderInline",
"ResponseSplitting",
"RouteDoS",
"SQL",
"SQLCVEs",
"SSLVerify",
"SafeBufferManipulation",
"SanitizeMethods",
"SelectTag",
"SelectVulnerability",
"Send",
"SendFile",
"SessionManipulation",
"SessionSettings",
"SimpleFormat",
"SingleQuotes",
"SkipBeforeFilter",
"SprocketsPathTraversal",
"StripTags",
"SymbolDoSCVE",
"TranslateBug",
"UnsafeReflection",
"ValidationRegex",
"WithoutProtection",
"XMLDoS",
"YAMLParsing"
],
"number_of_controllers": 2,
"number_of_models": 2,
"number_of_templates": 7,
"ruby_version": "2.6.3",
"brakeman_version": "4.7.0"
},
"warnings": [
{
"warning_type": "Mass Assignment",
"warning_code": 70,
"fingerprint": "5b486a498b14e1a12361c50863e2770c966799c9d5c6b6b9ab9bd8797c28a986",
"check_name": "MassAssignment",
"message": "Parameters should be whitelisted for mass assignment",
"file": "app/controllers/posts_controller.rb",
"line": 17,
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
"code": "params.permit!",
"render_path": null,
"location": {
"type": "method",
"class": "PostsController",
"method": "new"
},
"user_input": null,
"confidence": "High"
}
],
"ignored_warnings": [],
"errors": [],
"obsolete": []
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,9 @@
# frozen_string_literal: true
require './spec/spec_helper'
describe GithubCheckRunService do
let(:rubocop_report) { JSON(File.read('./spec/fixtures/report.json')) }
let(:brakeman_report) { JSON(File.read('./spec/fixtures/input.json')) }
let(:github_data) { { sha: 'sha', token: 'token', owner: 'owner', repo: 'repository_name' } }
let(:service) { GithubCheckRunService.new(rubocop_report, github_data, ReportAdapter) }
let(:service) { GithubCheckRunService.new(brakeman_report, github_data, ReportAdapter) }
it '#run' do
stub_request(:any, 'https://api.github.com/repos/owner/repository_name/check-runs/id')
@ -17,4 +15,5 @@ describe GithubCheckRunService do
output = service.run
expect(output).to be_a(Hash)
end
end

View File

@ -1,32 +1,31 @@
# frozen_string_literal: true
require './spec/spec_helper'
describe ReportAdapter do
let(:rubocop_report) do
JSON(File.read('./spec/fixtures/report.json'))
end
let(:brakeman_report) {
JSON(File.read('./spec/fixtures/input.json'))
}
let(:adapter) { ReportAdapter }
it '.conslusion' do
result = adapter.conslusion(rubocop_report)
result = adapter.conslusion(brakeman_report)
expect(result).to eq('failure')
end
it '.summary' do
result = adapter.summary(rubocop_report)
expect(result).to eq('201 offense(s) found')
result = adapter.summary(brakeman_report)
expect(result).to be_a(String)
end
it '.annotations' do
result = adapter.annotations(rubocop_report)
expect(result.first).to eq(
'path' => 'Gemfile',
'start_line' => 1,
'end_line' => 1,
'annotation_level' => 'failure',
'message' => 'Missing magic comment `# frozen_string_literal: true`.'
)
result = adapter.annotations(brakeman_report)
expect(result).to eq([{
'path' => 'app/controllers/posts_controller.rb',
'start_line' => 17,
'annotation_level' => 'warning',
'end_line' => 17,
'title' => 'High - MassAssignment',
'message' => 'Parameters should be whitelisted for mass assignment'
}])
end
end

View File

@ -1,5 +1,3 @@
# frozen_string_literal: true
require 'webmock/rspec'
require 'json'
require 'pry'