Class: Bundler::Audit::Database

Inherits:
Object
  • Object
show all
Defined in:
lib/bundler/audit/database.rb

Overview

Represents the directory of advisories, grouped by gem name and CVE number.

Defined Under Namespace

Classes: DownloadFailed, UpdateFailed

Constant Summary collapse

URL =

Git URL of the ruby-advisory-db.

'https://github.com/rubysec/ruby-advisory-db.git'
USER_PATH =

Path to the user's copy of the ruby-advisory-db.

File.expand_path(File.join(Gem.user_home,'.local','share','ruby-advisory-db'))
DEFAULT_PATH =

Default path to the ruby-advisory-db.

Since:

  • 0.8.0

ENV.fetch('BUNDLER_AUDIT_DB',USER_PATH)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = self.class.path) ⇒ Database

Initializes the Advisory Database.

Parameters:

  • path (String) (defaults to: self.class.path)

    The path to the advisory database.

Raises:

  • (ArgumentError)

    The path was not a directory.



62
63
64
65
66
67
68
# File 'lib/bundler/audit/database.rb', line 62

def initialize(path=self.class.path)
  unless File.directory?(path)
    raise(ArgumentError,"#{path.dump} is not a directory")
  end

  @path = path
end

Instance Attribute Details

#pathString (readonly)

The path to the advisory database.

Returns:

  • (String)


51
52
53
# File 'lib/bundler/audit/database.rb', line 51

def path
  @path
end

Class Method Details

.download(options = {}) ⇒ Dataase

Note:

Requires network access.

Downloads the ruby-advisory-db.

Parameters:

  • options (Hash) (defaults to: {})

    Additional options.

Options Hash (options):

  • :path (String) — default: DEFAULT_PATH

    The destination path for the new ruby-advisory-db.

  • :quiet (Boolean)

    Specify whether git should be --quiet.

Returns:

  • (Dataase)

    The newly downloaded database.

Raises:

Since:

  • 0.8.0



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/bundler/audit/database.rb', line 117

def self.download(options={})
  unless (options.keys - [:path, :quiet]).empty?
    raise(ArgumentError,"Invalid option(s)")
  end

  path = options.fetch(:path,DEFAULT_PATH)

  command = %w[git clone]
  command << '--quiet' if options[:quiet]
  command << URL << path

  unless system(*command)
    raise(DownloadFailed,"failed to download #{URL} to #{path.inspect}")
  end

  return new(path)
end

.exists?(path = DEFAULT_PATH) ⇒ Boolean

Tests whether the database exists.

Parameters:

  • path (String) (defaults to: DEFAULT_PATH)

    The given path of the database to check.

Returns:

  • (Boolean)

Since:

  • 0.8.0



90
91
92
# File 'lib/bundler/audit/database.rb', line 90

def self.exists?(path=DEFAULT_PATH)
  File.directory?(path) && !(Dir.entries(path) - %w[. ..]).empty?
end

.pathString

The default path for the database.

Returns:

  • (String)

    The path to the database directory.



76
77
78
# File 'lib/bundler/audit/database.rb', line 76

def self.path
  DEFAULT_PATH
end

.update!(options = {}) ⇒ Boolean

Deprecated.

Use #update! instead.

Note:

Requires network access.

Updates the ruby-advisory-db.

Parameters:

  • options (Hash) (defaults to: {})

    Additional options.

Options Hash (options):

  • :quiet (Boolean)

    Specify whether git should be --quiet.

Returns:

  • (Boolean)

    Specifies whether the update was successful.

Raises:

  • (ArgumentError)

    Invalid options were given.

Since:

  • 0.3.0



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/bundler/audit/database.rb', line 157

def self.update!(options={})
  raise "Invalid option(s)" unless (options.keys - [:quiet]).empty?

  if File.directory?(DEFAULT_PATH)
    begin
      new(DEFAULT_PATH).update!(options)
    rescue UpdateFailed then false
    end
  else
    begin
      download(options.merge(path: DEFAULT_PATH))
    rescue DownloadFailed then false
    end
  end
end

Instance Method Details

#advisories {|advisory| ... } ⇒ Enumerator

Enumerates over every advisory in the database.

Yields:

  • (advisory)

    If a block is given, it will be passed each advisory.

Yield Parameters:

  • advisory (Advisory)

    An advisory from the database.

Returns:

  • (Enumerator)

    If no block is given, an Enumerator will be returned.



265
266
267
268
269
270
271
# File 'lib/bundler/audit/database.rb', line 265

def advisories(&block)
  return enum_for(__method__) unless block_given?

  each_advisory_path do |path|
    yield Advisory.load(path)
  end
end

#advisories_for(name) {|advisory| ... } ⇒ Enumerator

Enumerates over advisories for the given gem.

Parameters:

  • name (String)

    The gem name to lookup.

Yields:

  • (advisory)

    If a block is given, each advisory for the given gem will be yielded.

Yield Parameters:

  • advisory (Advisory)

    An advisory for the given gem.

Returns:

  • (Enumerator)

    If no block is given, an Enumerator will be returned.



288
289
290
291
292
293
294
# File 'lib/bundler/audit/database.rb', line 288

def advisories_for(name)
  return enum_for(__method__,name) unless block_given?

  each_advisory_path_for(name) do |path|
    yield Advisory.load(path)
  end
end

#check_gem(gem) {|advisory| ... } ⇒ Enumerator

Verifies whether the gem is effected by any advisories.

Parameters:

  • gem (Gem::Specification)

    The gem to verify.

Yields:

  • (advisory)

    If a block is given, it will be passed advisories that effect the gem.

Yield Parameters:

  • advisory (Advisory)

    An advisory that effects the specific version of the gem.

Returns:

  • (Enumerator)

    If no block is given, an Enumerator will be returned.



312
313
314
315
316
317
318
319
320
# File 'lib/bundler/audit/database.rb', line 312

def check_gem(gem)
  return enum_for(__method__,gem) unless block_given?

  advisories_for(gem.name) do |advisory|
    if advisory.vulnerable?(gem.version)
      yield advisory
    end
  end
end

#commit_idString?

The last commit ID of the repository.

Returns:

  • (String, nil)

    The commit hash or nil if the database is not a git repository.

Since:

  • 0.9.0



228
229
230
231
232
233
234
# File 'lib/bundler/audit/database.rb', line 228

def commit_id
  if git?
    Dir.chdir(@path) do
      `git rev-parse HEAD`.chomp
    end
  end
end

#each_advisory_path {|path| ... } ⇒ Object (protected)

Enumerates over every advisory path in the database.

Yields:

  • (path)

    The given block will be passed each advisory path.

Yield Parameters:

  • path (String)

    A path to an advisory .yml file.



363
364
365
# File 'lib/bundler/audit/database.rb', line 363

def each_advisory_path(&block)
  Dir.glob(File.join(@path,'gems','*','*.yml'),&block)
end

#each_advisory_path_for(name) {|path| ... } ⇒ Object (protected)

Enumerates over the advisories for the given gem.

Parameters:

  • name (String)

    The gem of the gem.

Yields:

  • (path)

    The given block will be passed each advisory path.

Yield Parameters:

  • path (String)

    A path to an advisory .yml file.



379
380
381
# File 'lib/bundler/audit/database.rb', line 379

def each_advisory_path_for(name,&block)
  Dir.glob(File.join(@path,'gems',name,'*.yml'),&block)
end

#git?Boolean

Determines if the database is a git repository.

Returns:

  • (Boolean)

Since:

  • 0.8.0



180
181
182
# File 'lib/bundler/audit/database.rb', line 180

def git?
  File.directory?(File.join(@path,'.git'))
end

#inspectString

Inspects the database.

Returns:

  • (String)

    The inspected database.



348
349
350
# File 'lib/bundler/audit/database.rb', line 348

def inspect
  "#<#{self.class}:#{self}>"
end

#last_updated_atTime

Determines the time when the database was last updated.

Returns:

  • (Time)

Since:

  • 0.8.0



243
244
245
246
247
248
249
250
251
# File 'lib/bundler/audit/database.rb', line 243

def last_updated_at
  if git?
    Dir.chdir(@path) do
      Time.parse(`git log --date=iso8601 --pretty="%cd" -1`)
    end
  else
    File.mtime(@path)
  end
end

#sizeInteger

The number of advisories within the database.

Returns:

  • (Integer)

    The number of advisories.



328
329
330
# File 'lib/bundler/audit/database.rb', line 328

def size
  each_advisory_path.count
end

#to_sString

Converts the database to a String.

Returns:

  • (String)

    The path to the database.



338
339
340
# File 'lib/bundler/audit/database.rb', line 338

def to_s
  @path
end

#update!(options = {}) ⇒ true?

Updates the ruby-advisory-db.

Parameters:

  • options (Hash) (defaults to: {})

    Additional options.

Options Hash (options):

  • :quiet (Boolean)

    Specify whether git should be --quiet.

Returns:

  • (true, nil)
    • true - the ruby-advisory-db git repository was successfully updated.
    • nil - the ruby-advisory-db is not a git repository or the git command is not installed.

Raises:

  • (UpdateFailed)

    Could not update the ruby-advisory-db git repository.

Since:

  • 0.8.0



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/bundler/audit/database.rb', line 204

def update!(options={})
  if git?
    Dir.chdir(@path) do
      command = %w[git pull]
      command << '--quiet' if options[:quiet]
      command << 'origin' << 'master'

      unless system(*command)
        raise(UpdateFailed,"failed to update #{@path.inspect}")
      end

      return true
    end
  end
end