Compare commits

...
This repository has been archived on 2023-10-25. You can view files and clone it, but cannot push or open issues or pull requests.

15 Commits

Author SHA1 Message Date
Miguel Savignano
ec568a8682 remove trace 2019-11-02 23:23:01 +01:00
Miguel Savignano
829bd10190 refactor read_json method 2019-11-02 23:22:50 +01:00
Miguel Savignano
21926a5e7d rubocop 2019-11-02 23:19:43 +01:00
Miguel Savignano
78e98633e0 update readme 2019-11-02 23:18:39 +01:00
Miguel Savignano
7436a56daa . 2019-11-02 22:34:12 +01:00
Miguel Savignano
96f5618266 delete footer 2019-11-02 22:33:08 +01:00
Miguel Savignano
25b58a6a5d . 2019-11-02 22:31:05 +01:00
Miguel Savignano
1c13cdc80e rename varaibles . 2019-11-02 22:25:06 +01:00
Miguel Savignano
22a9598b0f . 2019-11-02 22:20:40 +01:00
Miguel Savignano
10ef5432cc . 2019-11-02 22:13:02 +01:00
Miguel Savignano
6fe95f9b39 fix read path 2019-11-02 21:56:56 +01:00
Miguel Savignano
eb7a4513da use inputs 2019-11-02 21:50:34 +01:00
Miguel Savignano
e86bde2331 generate coverage report 2019-11-02 21:50:16 +01:00
Miguel Savignano
9247c263a3 report adapter 2019-11-02 13:41:39 +01:00
Miguel Savignano
d7c0892c88 adapter for coverage 2019-11-02 03:10:52 +01:00
15 changed files with 97 additions and 109 deletions

View File

@ -8,4 +8,4 @@ Style/Documentation:
Enabled: false
Metrics/LineLength:
Max: 120
Max: 150

View File

@ -1,34 +1,21 @@
## Brakeman github action
Brakeman is a static analysis tool which checks Ruby on Rails applications for security vulnerabilities.
[See more](https://github.com/presidentbeef/brakeman)
Check your coverage percentage.
### Usage
```yml
- name: Brakeman
uses: devmasx/brakeman-linter-action@v1.0.0
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
```
### Custom report
#### [Simplecov](https://github.com/colszowka/simplecov)
```yml
- name: Install gems
run: |
gem install brakeman -v 4.5.0
- name: brakeman report
run: |
brakeman -f json > tmp/brakeman.json || exit 0
- name: Brakeman
uses: devmasx/brakeman-linter-action@v1.0.0
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
REPORT_PATH: tmp/brakeman.json
- uses: devmasx/coverage-check-action@coverage-check
with:
result_path: coverage/.last_run.json
token: ${{secrets.GITHUB_TOKEN}}
type: simplecov
min_coverage: 90
```
## Screenshots
![example GitHub Action UI](./screenshots/action.png)
![example Pull request](./screenshots/pull_request.png)
![Success](./screenshots/success.png)
![Fail](./screenshots/fail.png)

View File

@ -1,9 +1,24 @@
name: "Brakeman linter"
description: "A GitHub Action that lints your Ruby code with Brakeman!"
author: Miguel Savignano
runs:
using: "docker"
image: "Dockerfile"
branding:
icon: "check-square"
color: "red"
inputs:
type:
description: "simplecov | jest"
required: true
default: "simplecov"
token:
description: "Github token for create checks"
required: true
default: "World"
min_coverage:
description: "Minimum coverage"
default: "80"
result_path:
description: "Json with coverage result"
required: true
runs:
using: "docker"
image: "Dockerfile"

33
lib/coverage_report.rb Normal file
View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
class CoverageReport
def self.generate(type, report_path, data)
if type == 'simplecov'
simplecov(report_path, data)
elsif type == 'jest'
jest(report_path, data)
else
raise 'InvalidCoverageReportType'
end
end
def self.simplecov(report_path, data)
report = read_json(report_path)
minumum_percent = data[:min]
covered_percent = report.dig('result', 'covered_percent')
{ 'lines' => { 'covered_percent' => covered_percent, 'minumum_percent' => minumum_percent } }
end
def self.jest(report_path, data)
report = read_json(report_path)
minumum_percent = data[:min]
covered_percent = report.dig('result', 'covered_percent')
{ 'lines' => { 'covered_percent' => covered_percent, 'minumum_percent' => minumum_percent } }
end
private
def read_json(path)
JSON.parse(File.read(path))
end
end

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true
class GithubCheckRunService
CHECK_NAME = 'Brakeman'
CHECK_NAME = 'Coverage'
def initialize(report, github_data, report_adapter)
@report = report
@github_data = github_data
@report_adapter = report_adapter
@client = GithubClient.new(@github_data[:token], user_agent: 'brakeman-action')
@client = GithubClient.new(@github_data[:token], user_agent: 'coverage-action')
end
def run

View File

@ -6,6 +6,7 @@ require 'time'
require_relative './report_adapter'
require_relative './github_check_run_service'
require_relative './github_client'
require_relative './coverage_report'
def read_json(path)
JSON.parse(File.read(path))
@ -14,16 +15,15 @@ end
@event_json = read_json(ENV['GITHUB_EVENT_PATH']) if ENV['GITHUB_EVENT_PATH']
@github_data = {
sha: ENV['GITHUB_SHA'],
token: ENV['GITHUB_TOKEN'],
token: ENV['INPUT_TOKEN'],
owner: ENV['GITHUB_REPOSITORY_OWNER'] || @event_json.dig('repository', 'owner', 'login'),
repo: ENV['GITHUB_REPOSITORY_NAME'] || @event_json.dig('repository', 'name')
}
@report =
if ENV['REPORT_PATH']
read_json(ENV['REPORT_PATH'])
else
Dir.chdir(ENV['GITHUB_WORKSPACE']) { JSON.parse(`brakeman -f json`) }
end
@coverage_type = ENV['INPUT_TYPE']
@report_path = ENV['INPUT_RESULT_PATH']
@data = { min: ENV['INPUT_MIN_COVERAGE'] }
@report = CoverageReport.generate(@coverage_type, @report_path, @data)
GithubCheckRunService.new(@report, @github_data, ReportAdapter).run

View File

@ -7,40 +7,29 @@ class ReportAdapter
ANNOTATION_LEVEL = { notice: 'notice', warning: 'warning', failure: 'failure' }.freeze
def conslusion(report)
return CONCLUSION_TYPES[:failure] if security_warnings(report).positive?
CONCLUSION_TYPES[:success]
lines_covered_percent(report) >= lines_minimum_percent(report).to_f ? CONCLUSION_TYPES[:success] : CONCLUSION_TYPES[:failure]
end
def summary(report)
"**Brakeman Report**:\n#{security_warnings(report)} security warnings\n#{check_table(report)}"
"**Coverage**:\n\n#{table_head}\n| Lines | #{lines_covered_percent(report)}% | #{lines_minimum_percent(report)}% |\n"
end
def annotations(report)
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
def annotations(_report)
[]
end
private
def check_table(report)
uniq_checks(report).reduce('') { |memo, check| memo + "- [#{check[:check_name]}](#{check[:link]})\n" }
def table_head
"| Type | covered | minimum |\n| ----- | ------- | ------- |"
end
def uniq_checks(report)
report['warnings'].map { |w| { check_name: w['check_name'], link: w['link'] } }.uniq { |w| w[:check_name] }
def lines_covered_percent(report)
@lines_covered_percent ||= report.dig('lines', 'covered_percent')
end
def security_warnings(report)
report['scan_info']['security_warnings']
def lines_minimum_percent(report)
@lines_minimum_percent ||= report.dig('lines', 'minumum_percent')
end
end
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

BIN
screenshots/fail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

BIN
screenshots/success.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1,34 +0,0 @@
[
{
"path": "app/controllers/posts_controller.rb",
"start_line": 29,
"end_line": 29,
"annotation_level": "warning",
"title": "High - Evaluation",
"message": "User input in eval"
},
{
"path": "app/controllers/posts_controller.rb",
"start_line": 18,
"end_line": 18,
"annotation_level": "warning",
"title": "High - MassAssignment",
"message": "Parameters should be whitelisted for mass assignment"
},
{
"path": "app/controllers/posts_controller.rb",
"start_line": 19,
"end_line": 19,
"annotation_level": "warning",
"title": "High - MassAssignment",
"message": "Parameters should be whitelisted for mass assignment"
},
{
"path": "app/controllers/posts_controller.rb",
"start_line": 13,
"end_line": 13,
"annotation_level": "warning",
"title": "Medium - SQL",
"message": "Possible SQL injection"
}
]

View File

@ -1,5 +1,5 @@
**Brakeman Report**:
4 security warnings
- [Evaluation](https://brakemanscanner.org/docs/warning_types/dangerous_eval/)
- [MassAssignment](https://brakemanscanner.org/docs/warning_types/mass_assignment/)
- [SQL](https://brakemanscanner.org/docs/warning_types/sql_injection/)
**Coverage**:
| Type | covered | minimum |
| ----- | ------- | ------- |
| Lines | 80% | 80% |

View File

@ -3,9 +3,11 @@
require './spec/spec_helper'
describe GithubCheckRunService do
let(:brakeman_report) { JSON(File.read('./spec/fixtures/report.json')) }
let(:report) do
{ 'lines' => { 'covered_percent' => 80, 'minumum_percent' => 80 } }
end
let(:github_data) { { sha: 'sha', token: 'token', owner: 'owner', repo: 'repository_name' } }
let(:service) { GithubCheckRunService.new(brakeman_report, github_data, ReportAdapter) }
let(:service) { GithubCheckRunService.new(report, github_data, ReportAdapter) }
it '#run' do
stub_request(:any, 'https://api.github.com/repos/owner/repository_name/check-runs/id')

View File

@ -3,12 +3,8 @@
require './spec/spec_helper'
describe ReportAdapter do
let(:brakeman_report) do
JSON(File.read('./spec/fixtures/report.json'))
end
let(:spec_annotations) do
JSON(File.read('./spec/fixtures/output/annotations.json'))
let(:report) do
{ 'lines' => { 'covered_percent' => 80, 'minumum_percent' => 80 } }
end
let(:spec_summary) do
@ -18,17 +14,17 @@ describe ReportAdapter do
let(:adapter) { ReportAdapter }
it '.conslusion' do
result = adapter.conslusion(brakeman_report)
expect(result).to eq('failure')
result = adapter.conslusion(report)
expect(result).to eq('success')
end
it '.summary' do
result = adapter.summary(brakeman_report)
result = adapter.summary(report)
expect(result).to eq(spec_summary)
end
it '.annotations' do
result = adapter.annotations(brakeman_report)
expect(result).to eq(spec_annotations)
result = adapter.annotations(report)
expect(result).to eq([])
end
end