oss_audit 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d8c4b09cddf3f5d00344f375d67dbd749ed3f01ed8b741ae6eb40c1d5c020713
4
+ data.tar.gz: 37ecb417d5a2d5622a3968eb6a1926cf4924163a3c6a236d8e251216e86059fa
5
+ SHA512:
6
+ metadata.gz: 3a94792667ae9baf23e5c725c74003183ad23b02261a8bbe2ea2d82a138f666999f99848ebc96fb2d9eb6f78d1630c55c09555a2ccd0c471bc251a8690f2a5c6
7
+ data.tar.gz: dbdb75ae55ee96790a89b90390d7ff7e0f821eeede177efb12e1552f1ef7bfc777fa0bb6e165b6e7fd5261f5b1cfdeb3bc98e5a94829f19e7bd3a14f7c00abc5
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.1
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in oss_audit.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "minitest", "~> 5.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ oss_audit (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.14.4)
10
+ rake (12.3.3)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ minitest (~> 5.0)
17
+ oss_audit!
18
+ rake (~> 12.0)
19
+
20
+ BUNDLED WITH
21
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Alessio Signorini
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Open Source Software Auditor
2
+ Simple, opinionated tool to compile a list of the open source software in use
3
+ in a project. Each library is listed together with its licenses and links,
4
+ ready to be audited.
5
+
6
+ **Useful features:**
7
+ * No dependencies, can be ran anywhere
8
+ * Does not require any package manager nor for the code to work or be installed
9
+ * Output can be in JSON or CSV format
10
+ * Scans for nested packages
11
+ * Accepts an override file to programmatically amend results
12
+
13
+ ## Installation
14
+
15
+ Can be installed with
16
+
17
+ $ gem install oss_audit
18
+
19
+ ## Usage
20
+
21
+ A useful help screen will be displayed if launched with no arguments.
22
+
23
+ Run as
24
+
25
+ $ oss_audit [options] <dir1> ... <dirN>
26
+
27
+ Output is printed on STDOUT and can be easily redirected using `>`. Informative
28
+ logging is sent to STDERR.
29
+
30
+ A more complete example is
31
+
32
+ $ oss_audit -f csv -o overrides.json pj/serviceA pj/serviceB > libs.csv
33
+
34
+ ## Overrides
35
+
36
+ Not all libraries specify the license or useful links in their configuration
37
+ files. Instead of manually fixing that after the fact, create an override file
38
+ in JSON and pass it as argument to the tool, e.g.,
39
+ ```json
40
+ [
41
+ { "manager":"Bundler", "name":"barnes", "licenses":["MIT"] },
42
+ { "manager":"Yarn", "name":"sinon", "homepage":"https://sinonjs.org/" }
43
+ ]
44
+ ```
45
+
46
+ ## Limitations
47
+
48
+ Package Managers currently supported:
49
+ * Bundler
50
+ * Yarn / NPM (anything with `package.json`)
51
+
52
+ Adding others is trivial, look in `lib/oss_audit/managers` for examples.
53
+
54
+ Currently ignores version numbers but that too can be easily added.
55
+
56
+ ## Contributing
57
+
58
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alessio-signorini/oss_audit.
59
+
60
+ ## License
61
+
62
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "oss_audit"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/oss_audit ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require "oss_audit"
5
+
6
+ banner = "#{OssAudit::NAME} v#{OssAudit::VERSION} - alessio@signorini.us
7
+ Usage: #{File.basename($0)} [options] <dir1> ... <dirN>
8
+ "
9
+
10
+ @options = {}
11
+ opts = OptionParser.new do |opts|
12
+ opts.banner = banner
13
+
14
+ @options[:format] = :json
15
+ opts.on("-f", "--format FORMAT", [:csv, :json], "Output format (csv,json)") do |v|
16
+ @options[:format] = v
17
+ end
18
+
19
+ @options[:simple] = true
20
+ opts.on("-x", "--extended", "Add extra details (e.g., dependencies)") do |v|
21
+ @options[:simple] = false
22
+ end
23
+
24
+ opts.on("-o", "--overrides FILE.json", "Override data if in file") do |v|
25
+ @options[:overrides] = v
26
+ end
27
+ end
28
+
29
+ opts.parse!
30
+
31
+ unless ARGV.count > 0
32
+ puts opts.help()
33
+ exit 1
34
+ end
35
+
36
+ dependencies = []
37
+ ARGV.each do |path|
38
+ abort("ERROR: '#{path}' does not exists") unless Dir.exists?(path)
39
+ dependencies += OssAudit.scan(path)
40
+ end
41
+
42
+ if @options[:overrides]
43
+ OssAudit::Overrides.patch!(dependencies, @options[:overrides])
44
+ end
45
+
46
+ puts OssAudit::Output.format(dependencies, @options[:format], @options[:simple])
data/lib/oss_audit.rb ADDED
@@ -0,0 +1,43 @@
1
+ require "oss_audit/version"
2
+ require "oss_audit/managers"
3
+ require "oss_audit/output"
4
+ require 'oss_audit/overrides'
5
+
6
+ require 'logger'
7
+
8
+ module OssAudit
9
+ class Error < StandardError; end
10
+
11
+ def self.logger
12
+ @@logger ||= Logger.new(STDERR)
13
+ end
14
+
15
+ def self.scan(path)
16
+ libraries = []
17
+ Managers.list.each do |manager|
18
+ next unless manager.used_in?(path)
19
+
20
+ logger.info{"#{manager} (#{path})"}
21
+
22
+ dependencies = manager.list_dependencies(path)
23
+
24
+ logger.debug{"* Found #{dependencies.count} dependencies"}
25
+
26
+ dependencies.each do |dependency|
27
+ name, version = Array(dependency)
28
+
29
+ info = manager.get_info(name, version) or next
30
+ defaults = {
31
+ 'name' => name,
32
+ 'version' => version,
33
+ 'manager' => manager.name.split('::').last,
34
+ 'dependencies' => []
35
+ }
36
+
37
+ libraries << defaults.merge(info)
38
+ end
39
+ end
40
+
41
+ return libraries
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'utils'
2
+ require_relative 'managers/bundler'
3
+ require_relative 'managers/yarn'
4
+
5
+ module OssAudit
6
+ module Managers
7
+
8
+ def self.list
9
+ constants(false).map{|x| const_get(x)}
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ module OssAudit
2
+ module Managers
3
+ module Bundler
4
+ extend OssAudit::Utils
5
+
6
+ def self.used_in?(directory)
7
+ File.exists?(File.join(directory, 'Gemfile.lock')) || File.exists?(File.join(directory, 'Gemfile'))
8
+ end
9
+
10
+ def self.list_dependencies(directory)
11
+ file = File.read(File.join(directory, 'Gemfile'))
12
+
13
+ file.gsub!(/\#.*/,'')
14
+
15
+ return file.scan(/gem\s["'](\w+)["']/).flatten.uniq
16
+ end
17
+
18
+ def self.get_info(package, version=nil)
19
+ data = get_uri("https://rubygems.org/api/v1/gems/#{package}.json")
20
+
21
+ if data.is_a?(Exception)
22
+ OssAudit.logger.error{"#{package} | #{data}"}
23
+ return
24
+ end
25
+
26
+ name = data['name']
27
+ licenses = Array(data['license'] || data['licenses'])
28
+ homepage = data['homepage_uri'] || data.dig('metadata','homepage_uri') || data['project_uri']
29
+ source = data['source_code_uri'] || data.dig('metadata','source_code_uri')
30
+
31
+ dependencies = data['dependencies']['runtime'].map{|k| k['name']}
32
+
33
+ return {
34
+ "name" => name,
35
+ "licenses" => licenses,
36
+ "homepage" => homepage,
37
+ "source" => source,
38
+ "dependencies" => dependencies
39
+ }
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ module OssAudit
2
+ module Managers
3
+ module Yarn
4
+ extend OssAudit::Utils
5
+
6
+ def self.packages_files(directory)
7
+ Dir.glob(File.join(directory, '**/package.json')).reject{|x| x.include?('node_modules')}
8
+ end
9
+
10
+ def self.used_in?(directory)
11
+ packages_files(directory).any?
12
+ end
13
+
14
+ def self.list_dependencies(directory)
15
+ packages_files(directory).map do |file|
16
+ data = JSON.parse(File.read(file))
17
+ ((data['dependencies']||{}).keys | (data['devDependencies']||{}).keys)
18
+ end.flatten
19
+ end
20
+
21
+ def self.get_info(package, version=nil)
22
+ data = get_uri("https://registry.yarnpkg.com/#{package}/#{version||'latest'}")
23
+
24
+ unless data.is_a?(Hash)
25
+ OssAudit.logger.error{"#{package} | #{data}"}
26
+ return
27
+ end
28
+
29
+ name = data['name']
30
+ licenses = Array(data['license'])
31
+ homepage = data['homepage']
32
+ source = data.dig('repository','url')
33
+
34
+ dependencies = (data['dependencies']||{}).keys
35
+
36
+
37
+ return {
38
+ "name" => name,
39
+ "licenses" => licenses,
40
+ "homepage" => homepage,
41
+ "source" => source,
42
+ "dependencies" => dependencies
43
+ }
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ require 'json'
2
+ require 'csv'
3
+
4
+ module OssAudit
5
+ module Output
6
+
7
+ def self.format(dependencies, type='json', simple=true)
8
+ send("as_#{type}", uniq(dependencies), simple)
9
+ end
10
+
11
+ def self.as_csv(dependencies, simple=true)
12
+ headers = dependencies.map{|x| x.keys}.flatten.uniq
13
+
14
+ if simple
15
+ headers = %w(manager name version licenses homepage source)
16
+ dependencies = simplify(dependencies)
17
+ end
18
+
19
+ return CSV.generate('', :headers => headers, :col_sep => "\t", :write_headers => true) do |csv|
20
+ dependencies.each do |dependency|
21
+ csv << headers.map{|x| dependency[x]}.map{|x| to_s(x)}
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.as_json(dependencies, simple=true)
27
+ dependencies = simplify(dependencies) if simple
28
+ return JSON.pretty_generate(dependencies)
29
+ end
30
+
31
+ def self.simplify(dependencies)
32
+ keys = %w(manager name version licenses homepage source)
33
+ return dependencies.map{|x| x.slice(*keys)}
34
+ end
35
+
36
+ def self.to_s(object)
37
+ object.is_a?(Array) ? (object.empty? ? nil : object.join(',')) : object
38
+ end
39
+
40
+ def self.uniq(dependencies)
41
+ dependencies
42
+ .uniq{|x| x['name']}
43
+ .sort{|a,b| a['name'] <=> b['name']}
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+
3
+ module OssAudit
4
+ module Overrides
5
+
6
+ def self.patch!(dependencies, overrides_file)
7
+ overrides = index(overrides_file)
8
+
9
+ dependencies.each do |dep|
10
+ id = key(dep)
11
+ if overrides.include?(id)
12
+ OssAudit.logger.debug(" - Overriding #{dep['name']}")
13
+ dep.merge!(overrides[id])
14
+ end
15
+ end
16
+ end
17
+
18
+ def self.index(overrides_file)
19
+ data = JSON.parse(File.read(overrides_file)) rescue nil
20
+ abort("ERROR: Cannot read/parse JSON from #{overrides_file}") unless data
21
+
22
+ return Array(data).map{|x| [key(x), x]}.to_h
23
+ end
24
+
25
+ def self.key(dependency)
26
+ ['manager', 'name'].map{|x| dependency[x]}.join('#')
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module OssAudit
5
+ module Utils
6
+
7
+ def get_uri(url)
8
+ uri = URI.parse(url)
9
+ response = Net::HTTP.get_response(uri)
10
+ return JSON.parse(response.body)
11
+ rescue => e
12
+ return e
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ module OssAudit
2
+ NAME = "Open Source Software Auditor"
3
+ VERSION = "1.0.1"
4
+ end
data/oss_audit.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ require_relative 'lib/oss_audit/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "oss_audit"
5
+ spec.version = OssAudit::VERSION
6
+ spec.authors = ["Alessio Signorini"]
7
+ spec.email = ["alessio@signorini.us"]
8
+
9
+ spec.summary = OssAudit::NAME
10
+ spec.description = "Generate list of libraries used with licenses and links"
11
+ spec.homepage = "https://github.com/alessio-signorini/oss_audit"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ #spec.metadata["allowed_push_host"] = 'http://mygemserver.com'
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oss_audit
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alessio Signorini
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Generate list of libraries used with licenses and links
14
+ email:
15
+ - alessio@signorini.us
16
+ executables:
17
+ - oss_audit
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - ".travis.yml"
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - LICENSE.txt
26
+ - README.md
27
+ - Rakefile
28
+ - bin/console
29
+ - bin/setup
30
+ - exe/oss_audit
31
+ - lib/oss_audit.rb
32
+ - lib/oss_audit/managers.rb
33
+ - lib/oss_audit/managers/bundler.rb
34
+ - lib/oss_audit/managers/yarn.rb
35
+ - lib/oss_audit/output.rb
36
+ - lib/oss_audit/overrides.rb
37
+ - lib/oss_audit/utils.rb
38
+ - lib/oss_audit/version.rb
39
+ - oss_audit.gemspec
40
+ homepage: https://github.com/alessio-signorini/oss_audit
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/alessio-signorini/oss_audit
45
+ source_code_uri: https://github.com/alessio-signorini/oss_audit
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.3.0
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubygems_version: 3.1.2
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Open Source Software Auditor
65
+ test_files: []