rondabot 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +82 -0
- data/lib/module/Azure.rb +47 -0
- data/lib/module/Core.rb +102 -0
- data/lib/module/GitHub.rb +14 -0
- data/lib/module/GitLab.rb +14 -0
- data/lib/module/NpmAndYarn.rb +132 -0
- data/lib/module/Option.rb +28 -0
- data/lib/module/SourceControl.rb +66 -0
- data/lib/module/Version.rb +177 -0
- data/lib/rondabot.rb +11 -0
- data/spec/rondabot_spec.rb +5 -0
- data/spec/spec_helper.rb +14 -0
- metadata +88 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 76ef4c5c79896efc24cfe7700f8069e591bf24d4e5fe9f2b75200589f7f481f3
|
|
4
|
+
data.tar.gz: b22c709271b237e7963b3c50e19a965aab50e4d91df7924ca540b8b7f9d09813
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6db3c3fafdb96e18fd49827744d9ca9828cd0e240fa416c283b598d619f7e8e5ff85cda3718fd65f98c63078ad807e4c31e4251047185cd832ee23cfc421cc2c
|
|
7
|
+
data.tar.gz: f9c4e7efe0c460889863ec482824ed7b8da39c6f1b984709e13281be2c12bf4c3d8c70ad2c223730e3dedb9eeb96a62e1c0e2c0a94229b87a2fe01fe43359b59
|
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2020 Rondinelli Morais
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
**Rondabot** is a powerful agent that checks for vulnerabilities on the project's premises and submits pull requests with the best version.
|
|
4
|
+
|
|
5
|
+
The high-level flow looks like this:
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="resources/flow.svg" alt="Rondabot architecture">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
# Install
|
|
12
|
+
|
|
13
|
+
To get started let's create our Gemfile:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
# Gemfile
|
|
17
|
+
ruby "2.5.5"
|
|
18
|
+
source "https://rubygems.org"
|
|
19
|
+
|
|
20
|
+
gem "dependabot-omnibus", "~> 0.111.5"
|
|
21
|
+
gem "rondabot", "~> 1.0.0"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
run:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bundle install
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
After installation! To start using Rondabot all you need is a script looks like this:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
require "dependabot/omnibus"
|
|
34
|
+
require "rondabot"
|
|
35
|
+
|
|
36
|
+
core = Rondabot::Core.new(
|
|
37
|
+
# ...
|
|
38
|
+
# the parameters. See Parameters table below
|
|
39
|
+
# ...
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# start bot
|
|
43
|
+
core.start()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Parameters
|
|
47
|
+
|
|
48
|
+
| Name | Description |
|
|
49
|
+
|:------|:------|
|
|
50
|
+
| **provider** | Source control provider **azure**, **gitlab** or **github** |
|
|
51
|
+
| **organization** | Name of your organization on azure devops |
|
|
52
|
+
| **project** | Name of your project on azure devops |
|
|
53
|
+
| **repository** | Name of your project to using for clone and create pull requests |
|
|
54
|
+
| **credentials** | A user credentials (_username_ and _password_) permission to clone e create pull requests |
|
|
55
|
+
| **feed_id** | Your feed id npm/yarn on azure devops. Go to Azure Devops, your project _Artifacts_ > _Connect to feed_ > _npm_ and then you can find feed id in the url looks like `https://pkgs.dev.azure.com/your organization name/you feed id to be right here/_packaging/npm-packages/npm/registry/` |
|
|
56
|
+
| **github_public_token** | A GitHub access token with read access to public repos. Go to your GitHub account _Settings_ > _Developer settings_ > _Personal access tokens_ and then _Generate new token_ |
|
|
57
|
+
|
|
58
|
+
## Example
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
require "dependabot/omnibus"
|
|
62
|
+
require "rondabot"
|
|
63
|
+
|
|
64
|
+
core = Rondabot::Core.new(
|
|
65
|
+
provider: "azure",
|
|
66
|
+
organization: "Akatsuki",
|
|
67
|
+
project: "Digital%20Channel",
|
|
68
|
+
repository: "akatsuki-website",
|
|
69
|
+
credentials: {
|
|
70
|
+
:username => "Ronda.Bot",
|
|
71
|
+
:password => "cm9uZGluZWxsaW1vcmFpcwcm9uZGFib3Q"
|
|
72
|
+
},
|
|
73
|
+
feed_id: "11db190-e3b1872-1e6e6e-c97f2dd-49253",
|
|
74
|
+
github_public_token: "11db190e3b18721e6e6ec97f2dd49253"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
core.start()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
# License
|
|
81
|
+
|
|
82
|
+
MIT.
|
data/lib/module/Azure.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Rondabot
|
|
2
|
+
class Azure < SourceControl
|
|
3
|
+
def initialize params
|
|
4
|
+
super(params)
|
|
5
|
+
@repository = params[:repository]
|
|
6
|
+
@project = params[:project]
|
|
7
|
+
|
|
8
|
+
user_credentials = get_user_credentials(params)
|
|
9
|
+
@credentials << {
|
|
10
|
+
"type" => "git_source",
|
|
11
|
+
"host" => "dev.azure.com",
|
|
12
|
+
"username" => user_credentials[:username],
|
|
13
|
+
"password" => user_credentials[:password]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# get organization
|
|
17
|
+
@organization = params[:organization]
|
|
18
|
+
if @organization.nil?
|
|
19
|
+
raise ArgumentError.new("'organization' param is missing!")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# get npm registry feed id
|
|
23
|
+
@feed_id = params[:feed_id]
|
|
24
|
+
if @feed_id.nil?
|
|
25
|
+
raise ArgumentError.new("'feed_id' param is missing!")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@credentials << {
|
|
29
|
+
"type" => "npm_registry",
|
|
30
|
+
"registry" => "https://pkgs.dev.azure.com/#{@organization}/#{@feed_id}/_packaging/npm-packages/npm/registry/",
|
|
31
|
+
"token" => "#{@feed_id}:#{user_credentials[:password]}"
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def repository_uri
|
|
36
|
+
if @repository.nil?
|
|
37
|
+
raise ArgumentError.new("'repository' param is missing!")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if @project.nil?
|
|
41
|
+
raise ArgumentError.new("'project' param is missing!")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
return "#{@organization}/#{@project}/_git/#{@repository}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/module/Core.rb
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require "dependabot/omnibus"
|
|
2
|
+
require "json"
|
|
3
|
+
|
|
4
|
+
module Rondabot
|
|
5
|
+
class Core
|
|
6
|
+
def initialize params
|
|
7
|
+
@provider = params[:provider]
|
|
8
|
+
|
|
9
|
+
case @provider
|
|
10
|
+
when 'azure'
|
|
11
|
+
@source_control = Rondabot::Azure.new(params)
|
|
12
|
+
when 'gitlab'
|
|
13
|
+
# @source_control = Rondabot::GitLab.new(params)
|
|
14
|
+
raise ArgumentError.new("gitlab available soon :)")
|
|
15
|
+
when 'github'
|
|
16
|
+
# @source_control = Rondabot::GitHub.new(params)
|
|
17
|
+
raise ArgumentError.new("github available soon :)")
|
|
18
|
+
else
|
|
19
|
+
raise ArgumentError.new("'provider' param is missing! The available values are: azure, gitlab or github.")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def start
|
|
24
|
+
package_manager = "npm_and_yarn"
|
|
25
|
+
source = Dependabot::Source.new(
|
|
26
|
+
provider: @provider,
|
|
27
|
+
repo: @source_control.repository_uri
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
fetcher = @source_control.clone(source)
|
|
31
|
+
files = fetcher.files
|
|
32
|
+
commit = fetcher.commit
|
|
33
|
+
|
|
34
|
+
# keep only safe files
|
|
35
|
+
exclude_files = [
|
|
36
|
+
'yarn.lock',
|
|
37
|
+
'package-lock.json'
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
dependency_files = files.select do |f|
|
|
41
|
+
!exclude_files.include?(f.name)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
parser = Dependabot::FileParsers.for_package_manager(package_manager).new(
|
|
45
|
+
dependency_files: dependency_files,
|
|
46
|
+
source: source,
|
|
47
|
+
credentials: @source_control.credentials,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
dependencies = parser.parse
|
|
51
|
+
|
|
52
|
+
# Get the audit report to find out which
|
|
53
|
+
# dependencies are vulnerable
|
|
54
|
+
npm_and_yarn = Rondabot::NpmAndYarn.new(dependencies)
|
|
55
|
+
audit_obj = npm_and_yarn.audit()
|
|
56
|
+
|
|
57
|
+
#r report
|
|
58
|
+
print_audit_table(audit_obj)
|
|
59
|
+
|
|
60
|
+
# for each dependency, the best version for the
|
|
61
|
+
# upgrade must be analyzed
|
|
62
|
+
audit_obj.each do |audit|
|
|
63
|
+
best_version_to_go = Rondabot::Version.next(
|
|
64
|
+
audit[:current_version],
|
|
65
|
+
audit[:patched_versions]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
dependency = Dependabot::Dependency.new(
|
|
69
|
+
name: audit[:name],
|
|
70
|
+
version: best_version_to_go.version,
|
|
71
|
+
requirements: [{:requirement=>best_version_to_go.version, :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
72
|
+
previous_requirements: [{:requirement=>audit[:current_version].version, :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
73
|
+
package_manager: package_manager
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
updater = Dependabot::FileUpdaters.for_package_manager(package_manager).new(
|
|
77
|
+
dependencies: [dependency],
|
|
78
|
+
dependency_files: dependency_files,
|
|
79
|
+
credentials: @source_control.credentials,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@source_control.create_pull_request(
|
|
83
|
+
updater: updater,
|
|
84
|
+
base_commit: commit,
|
|
85
|
+
dependencies: [dependency],
|
|
86
|
+
source: source
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def print_audit_table audit_obj
|
|
92
|
+
if !audit_obj.empty?
|
|
93
|
+
puts "\nThe following dependencies are considered vulnerable."
|
|
94
|
+
puts "=============="
|
|
95
|
+
audit_obj.each do |audit|
|
|
96
|
+
puts "#{audit[:name]}@#{audit[:current_version].version}"
|
|
97
|
+
end
|
|
98
|
+
puts "\n"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
require "dependabot/omnibus"
|
|
2
|
+
require "uri"
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Rondabot
|
|
7
|
+
class NpmAndYarn
|
|
8
|
+
|
|
9
|
+
attr_accessor :dependencies
|
|
10
|
+
|
|
11
|
+
def initialize dependencies
|
|
12
|
+
@dependencies = dependencies
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Faz uma requisição do serviço do npm para verificar quais
|
|
17
|
+
# dependencias da lista são vulneráveis
|
|
18
|
+
#
|
|
19
|
+
# Retorna uma lista de
|
|
20
|
+
# {
|
|
21
|
+
# :name => "module name",
|
|
22
|
+
# :patched_versions => [Rondabot::Version],
|
|
23
|
+
# :current_version => Rondabot::Version
|
|
24
|
+
# }
|
|
25
|
+
def audit
|
|
26
|
+
requires = {}
|
|
27
|
+
dependencies = {}
|
|
28
|
+
self.dependencies.each do |dep|
|
|
29
|
+
# create the requires object
|
|
30
|
+
requires[:"#{dep.name}"] = dep.requirements.first[:requirement]
|
|
31
|
+
|
|
32
|
+
# create the dependencies object
|
|
33
|
+
dependencies[:"#{dep.name}"] = {
|
|
34
|
+
:version => dep.requirements.first[:requirement]
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
body = {
|
|
39
|
+
:name => "rondabot",
|
|
40
|
+
:version => "1.0.0",
|
|
41
|
+
:requires => requires,
|
|
42
|
+
:dependencies => dependencies
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
response = request(
|
|
46
|
+
url: URI("https://registry.npmjs.org/-/npm/v1/security/audits"),
|
|
47
|
+
body: body
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
audit_data = response.read_body
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Com a resposta do serviço monta um objeto contendo a versão atual
|
|
54
|
+
# e as versões com vulnerabilidades
|
|
55
|
+
#
|
|
56
|
+
vulnerable_versions = []
|
|
57
|
+
if audit_data != nil && audit_data.length > 0
|
|
58
|
+
object = JSON.parse(audit_data)
|
|
59
|
+
vulnerabilidades(object).each do |vul|
|
|
60
|
+
vulnerable_versions << vulnerable_version(object["advisories"], vul)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
return vulnerable_versions
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def request(config)
|
|
69
|
+
|
|
70
|
+
https = Net::HTTP.new(config[:url].host, config[:url].port)
|
|
71
|
+
https.use_ssl = true
|
|
72
|
+
|
|
73
|
+
request = Net::HTTP::Post.new(config[:url])
|
|
74
|
+
request["Content-Type"] = "application/json"
|
|
75
|
+
request.body = config[:body].to_json
|
|
76
|
+
|
|
77
|
+
return https.request(request)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def vulnerabilidades(obj_audit_data)
|
|
81
|
+
vulnerabs = []
|
|
82
|
+
actions = obj_audit_data["actions"]
|
|
83
|
+
if !actions.empty?
|
|
84
|
+
actions.each do |action|
|
|
85
|
+
resolves = action["resolves"]
|
|
86
|
+
if !resolves.empty?
|
|
87
|
+
resolves.each do |r|
|
|
88
|
+
vulnerabs << {:id => r["id"]}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
return vulnerabs
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def vulnerable_version(advisories, vulnerability)
|
|
97
|
+
depend = advisories["#{vulnerability[:id]}"]
|
|
98
|
+
return {
|
|
99
|
+
:name => depend["module_name"],
|
|
100
|
+
:patched_versions => Rondabot::Version.make(depend["patched_versions"]),
|
|
101
|
+
:current_version => Rondabot::Version.new(depend["findings"].first["version"])
|
|
102
|
+
}
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# dependencies = [
|
|
108
|
+
# Dependabot::Dependency.new(
|
|
109
|
+
# name: "minimist",
|
|
110
|
+
# version: "1.2.0",
|
|
111
|
+
# requirements: [{:requirement=>"1.2.0", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
112
|
+
# previous_requirements: [{:requirement=>"1.2.0", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
113
|
+
# package_manager: "npm_and_yarn"
|
|
114
|
+
# ),
|
|
115
|
+
# Dependabot::Dependency.new(
|
|
116
|
+
# name: "date-fns",
|
|
117
|
+
# version: "2.5.0",
|
|
118
|
+
# requirements: [{:requirement=>"2.5.0", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
119
|
+
# previous_requirements: [{:requirement=>"2.3.0", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
120
|
+
# package_manager: "npm_and_yarn"
|
|
121
|
+
# ),
|
|
122
|
+
# Dependabot::Dependency.new(
|
|
123
|
+
# name: "node.extend",
|
|
124
|
+
# version: "1.1.6",
|
|
125
|
+
# requirements: [{:requirement=>"1.1.6", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
126
|
+
# previous_requirements: [{:requirement=>"1.1.6", :file=>"package.json", :groups=>["dependencies"], :source=>nil}],
|
|
127
|
+
# package_manager: "npm_and_yarn"
|
|
128
|
+
# )
|
|
129
|
+
# ]
|
|
130
|
+
|
|
131
|
+
# npm_and_yarn = Rondabot::NpmAndYarn.new(dependencies)
|
|
132
|
+
# puts npm_and_yarn.audit()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
|
|
3
|
+
module Rondabot
|
|
4
|
+
class Option
|
|
5
|
+
def self.parse()
|
|
6
|
+
options = {}
|
|
7
|
+
opt_parser = OptionParser.new do |opts|
|
|
8
|
+
opts.banner = "Usage: example.rb [options]"
|
|
9
|
+
|
|
10
|
+
opts.on("-h", "--help", "Prints this help") do
|
|
11
|
+
puts opts
|
|
12
|
+
exit
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
opts.on("-ePATH", "--env=PATH", "The path to the .env file") { |v| options[:env] = v }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
begin opt_parser.parse! ARGV
|
|
19
|
+
rescue OptionParser::InvalidOption => e
|
|
20
|
+
puts e
|
|
21
|
+
puts opt_parser
|
|
22
|
+
exit 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return options
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "dependabot/omnibus"
|
|
2
|
+
|
|
3
|
+
module Rondabot
|
|
4
|
+
class SourceControl
|
|
5
|
+
attr_accessor :credentials, :provider
|
|
6
|
+
|
|
7
|
+
def initialize params
|
|
8
|
+
@credentials = []
|
|
9
|
+
@provider = params[:provider]
|
|
10
|
+
|
|
11
|
+
# A GitHub access token with read access to public repos
|
|
12
|
+
if params[:github_public_token].nil?
|
|
13
|
+
raise ArgumentError.new("'github_public_token' param is missing!")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@credentials << {
|
|
17
|
+
"type" => "git_source",
|
|
18
|
+
"host" => "github.com",
|
|
19
|
+
"username" => "x-access-token",
|
|
20
|
+
"password" => "#{params[:github_public_token]}"
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def repository_uri
|
|
25
|
+
raise "this method cannot be called directly, do override!"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def clone source
|
|
29
|
+
return Dependabot::FileFetchers.for_package_manager("npm_and_yarn").new(
|
|
30
|
+
source: source,
|
|
31
|
+
credentials: self.credentials,
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_pull_request params
|
|
36
|
+
files = params[:updater].updated_dependency_files
|
|
37
|
+
pr_creator = Dependabot::PullRequestCreator.new(
|
|
38
|
+
source: params[:source],
|
|
39
|
+
base_commit: params[:base_commit],
|
|
40
|
+
dependencies: params[:dependencies],
|
|
41
|
+
files: files,
|
|
42
|
+
credentials: self.credentials,
|
|
43
|
+
label_language: true
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
pull_request = pr_creator.create
|
|
47
|
+
|
|
48
|
+
if pull_request&.status == 201
|
|
49
|
+
content = JSON[pull_request.body]
|
|
50
|
+
puts " PR ##{content["pullRequestId"]} submitted"
|
|
51
|
+
else
|
|
52
|
+
puts " PR already exists or an error has occurred"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
def get_user_credentials(params)
|
|
58
|
+
_credentials = params[:credentials]
|
|
59
|
+
if _credentials.nil? || _credentials[:username].nil? || _credentials[:password].nil?
|
|
60
|
+
raise ArgumentError.new("'credentials' param is missing! Check your credentials parameter")
|
|
61
|
+
end
|
|
62
|
+
return _credentials
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Fontes de pesquisa
|
|
3
|
+
#
|
|
4
|
+
# https://github.com/npm/node-semver
|
|
5
|
+
# https://github.com/jlindsey/semantic
|
|
6
|
+
# https://semver.org/
|
|
7
|
+
#
|
|
8
|
+
module Rondabot
|
|
9
|
+
class Version
|
|
10
|
+
|
|
11
|
+
SemVerRegExp = /\A(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\Z/
|
|
12
|
+
|
|
13
|
+
attr_accessor :major, :minor, :patch, :pre, :version
|
|
14
|
+
|
|
15
|
+
def initialize version_str
|
|
16
|
+
v = version_str.match(SemVerRegExp)
|
|
17
|
+
|
|
18
|
+
raise ArgumentError.new("#{version_str} is not a valid SemVer Version (http://semver.org)") if v.nil?
|
|
19
|
+
@major = v[1].to_i
|
|
20
|
+
@minor = v[2].to_i
|
|
21
|
+
@patch = v[3].to_i
|
|
22
|
+
@pre = v[4]
|
|
23
|
+
@build = v[5]
|
|
24
|
+
@version = version_str
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Public Methods
|
|
28
|
+
|
|
29
|
+
def gt? other_version
|
|
30
|
+
compare(other_version) > 0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def lt? other_version
|
|
34
|
+
compare(other_version) < 0
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def eq? other_version
|
|
38
|
+
compare(other_version) == 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Static Methods
|
|
42
|
+
|
|
43
|
+
def self.max versions
|
|
44
|
+
ordered = versions.sort_by { |s| Gem::Version.new(s.version) }
|
|
45
|
+
return ordered.last
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.min versions
|
|
49
|
+
ordered = versions.sort_by { |s| Gem::Version.new(s.version) }
|
|
50
|
+
return ordered.first
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.valid str
|
|
54
|
+
return str.match(SemVerRegExp)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# Cria uma lista de Version com base na string semântica
|
|
59
|
+
# exemplo:
|
|
60
|
+
# str => ">=1.1.7 <2.0.0 || >=2.0.1"
|
|
61
|
+
# vira => [Rondabot::Version[1.1.7], Rondabot::Version[2.0.0], Rondabot::Version[2.0.1]]
|
|
62
|
+
#
|
|
63
|
+
def self.make str_versions
|
|
64
|
+
cleared_versions = str_versions.gsub(/[^a-zA-Z0-9_\.]+/, ",").split(",")
|
|
65
|
+
|
|
66
|
+
versions = []
|
|
67
|
+
cleared_versions.each do |v|
|
|
68
|
+
if valid(v)
|
|
69
|
+
versions << Version.new(v)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
return versions
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# A próxima versão é a mínima maior do que a atual
|
|
77
|
+
#
|
|
78
|
+
def self.next(current_version, patched_versions)
|
|
79
|
+
biggest_versions = []
|
|
80
|
+
ordered = patched_versions.sort_by { |s| Gem::Version.new(s.version) }
|
|
81
|
+
ordered.each do |v|
|
|
82
|
+
# Versões maiores do que a versão atual são adicionada no array
|
|
83
|
+
if v.gt?(current_version.version)
|
|
84
|
+
biggest_versions << v
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
return min(biggest_versions)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Private Methods
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def compare other_version
|
|
94
|
+
other_version = Version.new(other_version)
|
|
95
|
+
return Gem::Version.new(self.version) <=> Gem::Version.new(other_version.version)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# CRIAÇÃO DO OBJETO
|
|
103
|
+
#
|
|
104
|
+
# version = Rondabot::Version.new('1.6.5')
|
|
105
|
+
# version.major # => 1
|
|
106
|
+
# version.minor # => 6
|
|
107
|
+
# version.patch # => 5
|
|
108
|
+
# puts "Aqui está => #{version.patch}"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# TESTE DE ORDENACAO DE ARRAY
|
|
113
|
+
#
|
|
114
|
+
|
|
115
|
+
# array = [
|
|
116
|
+
# Rondabot::Version.new('1.2.3-beta'),
|
|
117
|
+
# Rondabot::Version.new('1.1.7'),
|
|
118
|
+
# Rondabot::Version.new('2.0.1'),
|
|
119
|
+
# Rondabot::Version.new('1.2.2-alpha'),
|
|
120
|
+
# Rondabot::Version.new('0.0.54'),
|
|
121
|
+
# Rondabot::Version.new('1.0.54'),
|
|
122
|
+
# Rondabot::Version.new('0.79.4'),
|
|
123
|
+
# Rondabot::Version.new('0.83.0'),
|
|
124
|
+
# Rondabot::Version.new('0.83.1'),
|
|
125
|
+
# Rondabot::Version.new('2.0.0')
|
|
126
|
+
# ]
|
|
127
|
+
|
|
128
|
+
# ordered = array.sort_by { |s| Gem::Version.new(s.version) }
|
|
129
|
+
# ordered.each do |s|
|
|
130
|
+
# puts s.version
|
|
131
|
+
# end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
# TESTE DE COMPARACAO
|
|
136
|
+
#
|
|
137
|
+
# version117 = Rondabot::Version.new('1.1.7')
|
|
138
|
+
# puts "gt? #{version117.gt?('1.1.8')}"
|
|
139
|
+
# puts "lt? #{version117.lt?('1.1.8')}"
|
|
140
|
+
# puts "eq? #{version117.eq?('1.1.8')}"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
#
|
|
144
|
+
# MAX VERSION
|
|
145
|
+
#
|
|
146
|
+
# array = [
|
|
147
|
+
# Rondabot::Version.new('1.1.7'),
|
|
148
|
+
# Rondabot::Version.new('2.0.1'),
|
|
149
|
+
# Rondabot::Version.new('2.0.0')
|
|
150
|
+
# ]
|
|
151
|
+
|
|
152
|
+
# puts Rondabot::Version::max(array).version
|
|
153
|
+
# puts Rondabot::Version::min(array).version
|
|
154
|
+
|
|
155
|
+
#
|
|
156
|
+
# CRIADOR DE VERSOES COM BASE NO PATHCED
|
|
157
|
+
#
|
|
158
|
+
# ">=1.1.7 <2.0.0 || >= 2.0.1"
|
|
159
|
+
#
|
|
160
|
+
|
|
161
|
+
# versions = Rondabot::Version.make(">=1.1.7 <2.0.0 || >= 2.0.1")
|
|
162
|
+
# puts versions
|
|
163
|
+
# exit
|
|
164
|
+
|
|
165
|
+
#
|
|
166
|
+
# METODO QUE IRÁ ACHAR A PROXIMA VERSAO COM BASE NA ATUAL
|
|
167
|
+
#
|
|
168
|
+
# versions = [
|
|
169
|
+
# Rondabot::Version.new('0.83.0'),
|
|
170
|
+
# Rondabot::Version.new('0.83.1'),
|
|
171
|
+
# Rondabot::Version.new('1.1.7'),
|
|
172
|
+
# Rondabot::Version.new('2.0.1'),
|
|
173
|
+
# Rondabot::Version.new('2.0.0')
|
|
174
|
+
# ]
|
|
175
|
+
# current_version = Rondabot::Version.new('1.0.54')
|
|
176
|
+
# best_version_to_go = Rondabot::Version.next(current_version, versions)
|
|
177
|
+
# puts best_version_to_go.version
|
data/lib/rondabot.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Rondabot
|
|
2
|
+
VERSION = '0.0.10'
|
|
3
|
+
autoload :Option, File.join(File.dirname(__FILE__), 'module/Option')
|
|
4
|
+
autoload :Core, File.join(File.dirname(__FILE__), 'module/Core')
|
|
5
|
+
autoload :Version, File.join(File.dirname(__FILE__), 'module/Version')
|
|
6
|
+
autoload :NpmAndYarn, File.join(File.dirname(__FILE__), 'module/NpmAndYarn')
|
|
7
|
+
autoload :SourceControl, File.join(File.dirname(__FILE__), 'module/SourceControl')
|
|
8
|
+
autoload :Azure, File.join(File.dirname(__FILE__), 'module/Azure')
|
|
9
|
+
autoload :GitHub, File.join(File.dirname(__FILE__), 'module/GitHub')
|
|
10
|
+
autoload :GitLab, File.join(File.dirname(__FILE__), 'module/GitLab')
|
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "bundler/setup"
|
|
2
|
+
require "rondabot"
|
|
3
|
+
|
|
4
|
+
RSpec.configure do |config|
|
|
5
|
+
# Enable flags like --only-failures and --next-failure
|
|
6
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
|
7
|
+
|
|
8
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
|
9
|
+
config.disable_monkey_patching!
|
|
10
|
+
|
|
11
|
+
config.expect_with :rspec do |c|
|
|
12
|
+
c.syntax = :expect
|
|
13
|
+
end
|
|
14
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rondabot
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.10
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rondinelli Morais
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-08-14 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '11'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '11'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3'
|
|
41
|
+
description: Rondabot Rondabot is a powerful agent that checks for vulnerabilities
|
|
42
|
+
on the project's premises and submits pull requests with the best version.
|
|
43
|
+
email:
|
|
44
|
+
- rondinellimorais@gmail.com
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- LICENSE
|
|
50
|
+
- README.md
|
|
51
|
+
- lib/module/Azure.rb
|
|
52
|
+
- lib/module/Core.rb
|
|
53
|
+
- lib/module/GitHub.rb
|
|
54
|
+
- lib/module/GitLab.rb
|
|
55
|
+
- lib/module/NpmAndYarn.rb
|
|
56
|
+
- lib/module/Option.rb
|
|
57
|
+
- lib/module/SourceControl.rb
|
|
58
|
+
- lib/module/Version.rb
|
|
59
|
+
- lib/rondabot.rb
|
|
60
|
+
- spec/rondabot_spec.rb
|
|
61
|
+
- spec/spec_helper.rb
|
|
62
|
+
homepage: https://github.com/rondinellimorais/rondabot
|
|
63
|
+
licenses:
|
|
64
|
+
- MIT
|
|
65
|
+
metadata:
|
|
66
|
+
homepage_uri: https://github.com/rondinellimorais/rondabot
|
|
67
|
+
post_install_message:
|
|
68
|
+
rdoc_options: []
|
|
69
|
+
require_paths:
|
|
70
|
+
- lib
|
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 2.3.0
|
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '0'
|
|
81
|
+
requirements: []
|
|
82
|
+
rubygems_version: 3.1.4
|
|
83
|
+
signing_key:
|
|
84
|
+
specification_version: 4
|
|
85
|
+
summary: Rondabot searches for and fixes dependencies with security vulnerabilities.
|
|
86
|
+
test_files:
|
|
87
|
+
- spec/rondabot_spec.rb
|
|
88
|
+
- spec/spec_helper.rb
|