Skip to content

Commit a6362fb

Browse files
authored
Merge pull request #2 from bugcrowd/link-methodologies-data
[BC-16717] add methodology taxonomy v0.1
2 parents c3ef17a + 7526535 commit a6362fb

File tree

17 files changed

+541
-3
lines changed

17 files changed

+541
-3
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "lib/data/0.1"]
2+
path = lib/data/0.1
3+
url = [email protected]:bugcrowd/methodology-taxonomy.git

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
55

66
## [Unreleased]
77
### Added
8+
- support for methodologies v0.1
89

910
### Changed
1011

bin/console

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/usr/bin/env ruby
22

33
require 'bundler/setup'
4-
require 'vrt'
4+
require 'bmt'
55
require 'pry'
66

7-
# An interactive console for the VRT gem
7+
# An interactive console for the BMT gem
88

99
Pry.start

bmt.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
1111
spec.email = ['[email protected]']
1212
spec.date = Date.today.to_s
1313
spec.summary = 'Ruby wrapper for Bugcrowd\'s Methodology Taxonomy'
14-
spec.homepage = 'https://github.com/bugcrowd/vrt-ruby'
14+
spec.homepage = 'https://github.com/bugcrowd/bmt-ruby'
1515
spec.license = 'MIT'
1616
spec.require_paths = ['lib']
1717
spec.required_ruby_version = '>= 2.5'

lib/bmt.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,72 @@
1+
require 'bmt/item'
2+
require 'bmt/methodology'
3+
require 'bmt/step'
4+
5+
require 'date'
6+
require 'json'
7+
require 'pathname'
8+
19
module BMT
10+
class VersionNotFoundError < StandardError; end
11+
class MethodologyNotFoundError < StandardError; end
12+
DATA_DIR = Pathname.new(__dir__).join('data')
13+
14+
# memoize loaded
15+
@methodologies = {}
16+
@methodology_keys = {}
17+
18+
module_function
19+
20+
# returns a Methodology object given a key and a version
21+
def find(key, version: current_version)
22+
raise VersionNotFoundError unless versions.include?(version)
23+
raise MethodologyNotFoundError unless methodology_keys(version: version).include?(key)
24+
25+
@methodologies[version].nil? && @methodologies[version] = {}
26+
27+
@methodologies[version][key] ||= Methodology.new(
28+
key: key,
29+
version: version,
30+
attributes: methodology_json(key, version: version)
31+
)
32+
33+
@methodologies[version][key]
34+
end
35+
36+
def current_version
37+
versions.first
38+
end
39+
40+
# returns available methodology keys for a given version
41+
def methodology_keys(version: current_version)
42+
@methodology_keys[version] ||=
43+
DATA_DIR.join(version, 'methodologies').entries
44+
.map(&:basename)
45+
.map(&:to_s)
46+
.select { |dirname| dirname =~ /json/ }
47+
.map { |filepath| File.basename(filepath, File.extname(filepath)) }
48+
end
49+
50+
# Infer the available versions of the BMT from the names of the files
51+
# in the repo.
52+
# The returned list is in order with the current version first.
53+
def versions
54+
@versions ||= json_dir_names.sort.reverse!
55+
end
56+
57+
def methodology_json(key, version: current_version)
58+
JSON.parse(methodology_pathname(key, version: version).read)
59+
end
60+
61+
def methodology_pathname(key, version: current_version)
62+
DATA_DIR.join(version, 'methodologies', "#{key}.json")
63+
end
64+
65+
# Get names of directories matching lib/data/<major>-<minor>/
66+
def json_dir_names
67+
DATA_DIR.entries
68+
.map(&:basename)
69+
.map(&:to_s)
70+
.select { |dirname| dirname =~ /^[0-9]+\.[0-9]/ }.sort
71+
end
272
end

lib/bmt/item.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module BMT
2+
class Item
3+
attr_reader :key, :title, :description, :vrt_category, :step
4+
5+
def initialize(step:, attributes:)
6+
@step = step
7+
@key = attributes['key']
8+
@title = attributes['title']
9+
@description = attributes['description']
10+
@vrt_category = attributes['vrt_category']
11+
end
12+
end
13+
end

lib/bmt/methodology.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module BMT
2+
class Methodology
3+
attr_reader :key, :version, :title, :description, :vrt_version
4+
5+
def initialize(key:, version:, attributes: {})
6+
@key = key
7+
@version = version
8+
@title = attributes.dig('metadata', 'title')
9+
@release_date = attributes.dig('metadata', 'release_date')
10+
@description = attributes.dig('metadata', 'description')
11+
@vrt_version = attributes.dig('metadata', 'vrt_version')
12+
13+
@steps_data = attributes.dig('content', 'steps')
14+
end
15+
16+
def release_date
17+
Date.parse(@release_date)
18+
end
19+
20+
def steps
21+
@steps ||= @steps_data.map do |step_data|
22+
Step.new(
23+
methodology: self,
24+
attributes: step_data
25+
)
26+
end
27+
end
28+
end
29+
end

lib/bmt/step.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module BMT
2+
class Step
3+
attr_reader :key, :title, :description, :methodology
4+
5+
def initialize(methodology:, attributes:)
6+
@methodology = methodology
7+
@key = attributes['key']
8+
@title = attributes['title']
9+
@description = attributes['description']
10+
@items_data = attributes['items']
11+
end
12+
13+
def items
14+
@items ||= @items_data.map do |item_data|
15+
Item.new(
16+
step: self,
17+
attributes: item_data
18+
)
19+
end
20+
end
21+
end
22+
end

lib/data/0.1

Submodule 0.1 added at c40c734

spec/bmt/item_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe BMT::Item do
6+
let(:step) { methodology.steps.first }
7+
let(:methodology) { BMT.find(methodology_key) }
8+
let(:methodology_json) { BMT.methodology_json(methodology_key) }
9+
let(:attributes) { methodology_json.dig('content', 'steps', 0, 'items', 0) }
10+
let(:methodology_key) { 'outback-animal-testing' }
11+
12+
describe '#new' do
13+
subject do
14+
described_class.new(
15+
step: step,
16+
attributes: attributes
17+
)
18+
end
19+
20+
it 'initialize an item' do
21+
expect(subject).to be_a(described_class)
22+
23+
expect(subject.key).to eq('marsupial')
24+
expect(subject.title).to be_a(String)
25+
expect(subject.description).to be_a(String)
26+
expect(subject.vrt_category).to be_a(String)
27+
expect(subject.step).to eq(step)
28+
end
29+
end
30+
end

0 commit comments

Comments
 (0)