aws_security_viz 0.1.4.pre.alpha.pre.81 → 0.1.4.pre.alpha.pre.82

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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YmZlMjAxZjA3YTcwMjIzYTFiOGMzMWQ1NjExYTllMGM0ZDE3NDgzZg==
5
- data.tar.gz: !binary |-
6
- OTgwZTlmZmE4NzhkZDg5OWUwYzYzYjAwOTA3MWM5MmEzY2I2YzU3NQ==
2
+ SHA1:
3
+ metadata.gz: f1fed3837156ff2477390d1b411bbbd97a1d96fc
4
+ data.tar.gz: e737d124886db6d03301ae21d489aef70db7bec6
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- YTNiZjUzZjhkMWYzZTIyZTllMTI3Nzg0ZTViOWU0MGU5OGIxZTg1ZmEzMTFj
10
- Yzk2ZTA5ODk2NTA3ZDQ2MmE3NzBmMTgyMDdmZWFlMmIyMzEyYTEzMDdmNDIy
11
- MTMyNjdmZjU2YzVjNzJkNDYyYjUzMTY2ZWM0YzFjOTM0NmY0M2E=
12
- data.tar.gz: !binary |-
13
- N2ExYzhiOWM2ZDM0MWFiNjMyNjljOGZjYjM2OWRhNjkxMDYyZmRiN2NmMTA5
14
- ZTY5Y2JmMjZhM2YyOTI5ZGU4ZGQzZmQxNmZkZTQyNjQ0ZTNmMzcxMmJhYjlm
15
- YjUyNmQxZjUyOTA2ZGJiODljMjAzMmY4NjAxZTk2YWRiMzc1ZmM=
6
+ metadata.gz: 6fd4637e47289e1c56f93d78268b1f379113db10f61fd65a5f1ad2e9909594662fbab47d7920bce17d0902a55d9318c34f6800366c7d2fdcaf54d9eac3450162
7
+ data.tar.gz: 09898633b2c77440f2b85a64f424db98658275f4fcd23300ecce2bbd357f06eef16b8aee177641b57c6f7f7009dc54cb3c73f5d6002cdb8e1637db36cd3e1865
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
2
3
 
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = 'aws_security_viz'
7
7
  s.version = AwsSecurityViz::VERSION
8
8
  s.version = "#{s.version}-alpha-#{ENV['TRAVIS_BUILD_NUMBER']}" if ENV['TRAVIS']
9
- s.date = '2015-10-15'
9
+ s.date = Time.now.strftime('%Y-%m-%d')
10
10
  s.summary = "Visualize your aws security groups"
11
11
  s.description = "Provides a quick mechanism to visualize your EC2 security groups in multiple formats"
12
12
  s.authors = ["Anay Nayak"]
@@ -22,15 +22,16 @@ Gem::Specification.new do |s|
22
22
  s.require_paths = ["lib"]
23
23
 
24
24
  s.add_development_dependency "bundler", "~> 1.13"
25
- s.add_development_dependency "rake", "~> 11.2.2"
25
+ s.add_development_dependency "rake", "~> 12.0.0"
26
26
  s.add_development_dependency "rspec", "~> 3.5.0"
27
27
 
28
28
  s.add_runtime_dependency 'ruby-graphviz', "~> 1.2.2"
29
- s.add_runtime_dependency 'fog-aws', "~> 0.11.0"
29
+ s.add_runtime_dependency 'fog-aws', "~> 1.2.0"
30
30
  s.add_runtime_dependency 'unf', "~> 0.1.4"
31
- s.add_runtime_dependency 'json', "~> 2.0.2"
31
+ s.add_runtime_dependency 'json', "~> 2.0.3"
32
32
  s.add_runtime_dependency 'trollop', "~> 2.1.2"
33
33
  s.add_runtime_dependency 'organic_hash', "~> 1.0.2"
34
+ s.add_runtime_dependency 'rgl', "~> 0.5.2"
34
35
 
35
36
  s.required_ruby_version = '>= 2.0.0'
36
37
  end
@@ -11,6 +11,8 @@ opts = Trollop::options do
11
11
  opt :filename, 'Output file name', :type => :string, :default => 'aws-security-viz.png'
12
12
  opt :config, 'Config file (opts.yml)', :type => :string, :default => 'opts.yml'
13
13
  opt :color, 'Colored node edges', :default => false
14
+ opt :source_filter, 'Source filter', :default => nil, :type => :string
15
+ opt :target_filter, 'Target filter', :default => nil, :type => :string
14
16
  end
15
17
 
16
18
  cmd = ARGV.shift
@@ -21,5 +23,10 @@ if cmd=="setup"
21
23
  end
22
24
 
23
25
  config = AwsConfig.load(opts[:config]).merge(obfuscate: ENV['OBFUSCATE'], debug: ENV['DEBUG'])
24
- VisualizeAws.new(config, opts).unleash(opts[:filename])
26
+ begin
27
+ VisualizeAws.new(config, opts).unleash(opts[:filename])
28
+ rescue Exception => e
29
+ puts "[ERROR] #{e.message}"
30
+ exit 1
31
+ end
25
32
 
@@ -4,6 +4,7 @@ require_relative 'provider/ec2'
4
4
  require_relative 'renderer/graphviz'
5
5
  require_relative 'renderer/json'
6
6
  require_relative 'graph'
7
+ require_relative 'graph_filter'
7
8
  require_relative 'exclusions'
8
9
  require_relative 'debug_graph'
9
10
  require_relative 'color_picker'
@@ -19,6 +20,7 @@ class VisualizeAws
19
20
 
20
21
  def unleash(output_file)
21
22
  g = build
23
+ g.filter(@options[:source_filter], @options[:target_filter])
22
24
  if output_file.end_with?('json')
23
25
  g.output(Renderer::Json.new(output_file, @config))
24
26
  FileUtils.copy(File.expand_path('../export/html/view.html', __FILE__),
@@ -14,6 +14,10 @@ class DebugGraph
14
14
  @g.add_edge(h(from), h(to), opts.update(label: h(opts[:label])))
15
15
  end
16
16
 
17
+ def filter(source, destination)
18
+ @g.filter(source, destination)
19
+ end
20
+
17
21
  def output(renderer)
18
22
  @g.output(renderer)
19
23
  end
@@ -1,45 +1,43 @@
1
+ require 'rgl/adjacency'
2
+
1
3
  class Graph
2
- attr_reader :ops
4
+ attr_reader :underlying
3
5
 
4
- def initialize(config)
6
+ def initialize(config, underlying=RGL::DirectedAdjacencyGraph.new)
5
7
  @config = config
6
- @ops = []
7
- @nodes = Set.new
8
+ @underlying = underlying
9
+ @edge_properties = {}
8
10
  end
9
11
 
10
12
  def add_node(name)
11
13
  log("node: #{name}")
12
- uniquely_add(@ops, :node, name) {
13
- [:node, name]
14
- }
14
+ @underlying.add_vertex(name)
15
15
  end
16
16
 
17
17
  def add_edge(from, to, opts)
18
18
  log("edge: #{from} -> #{to}")
19
- add_node(from)
20
- add_node(to)
21
- uniquely_add(@ops, :edge, from, to) {
22
- [:edge, from, to, opts]
23
- }
19
+ @underlying.add_edge(from, to)
20
+ @edge_properties[[from, to]] = opts
21
+ end
22
+
23
+ def filter(source, destination)
24
+ @underlying = GraphFilter.new(underlying).filter(source, destination)
24
25
  end
25
26
 
26
27
  def output(renderer)
27
- @ops.each { |op, *args|
28
- renderer.add_node(*args) if op==:node
29
- renderer.add_edge(*args) if op==:edge
28
+ @underlying.each_vertex { |v| renderer.add_node(v) }
29
+ @underlying.each_edge { |u, v|
30
+ renderer.add_edge(u, v, opts(u, v))
30
31
  }
31
32
  renderer.output
32
33
  end
33
34
 
34
- def uniquely_add(target, type, *opts, &block)
35
- return if opts.compact.empty?
36
- return if @nodes.include?([type, opts])
37
- @nodes.add([type, opts])
38
- target << yield
39
- end
40
-
41
-
42
35
  def log(msg)
43
36
  puts msg if @config.debug?
44
37
  end
38
+
39
+ private
40
+ def opts(u, v)
41
+ @edge_properties[[u, v]]
42
+ end
45
43
  end
@@ -0,0 +1,38 @@
1
+ require 'rgl/traversal'
2
+ require 'rgl/implicit'
3
+
4
+ class GraphFilter
5
+ def initialize(graph)
6
+ @graph = graph
7
+ end
8
+
9
+ def filter(source, destination)
10
+ return @graph if source.nil? && destination.nil?
11
+ if !source.nil? && destination.nil?
12
+ return reduce(@graph, source)
13
+ end
14
+ if !destination.nil? && source.nil?
15
+ return reduce(@graph.reverse, destination).reverse
16
+ end
17
+ search(@graph, source, destination)
18
+ end
19
+
20
+ private
21
+ def reduce(graph, source)
22
+ tree = graph.bfs_search_tree_from(source)
23
+ graph.vertices_filtered_by { |v| tree.has_vertex? v }
24
+ end
25
+
26
+ def search(graph, source, destination)
27
+ visitor = RGL::DFSVisitor.new(graph)
28
+ path = []
29
+ paths = []
30
+ visitor.set_examine_vertex_event_handler { |x| path << x }
31
+ visitor.set_finish_vertex_event_handler { |x| path.pop }
32
+ visitor.set_examine_edge_event_handler { |x, y| paths << path.dclone + [y] if y == destination }
33
+ graph.depth_first_visit(source, visitor) { |x|}
34
+ to_remove = graph.vertices - paths.flatten
35
+ graph.remove_vertices(*to_remove)
36
+ graph
37
+ end
38
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ describe GraphFilter do
5
+ it 'should include nodes reachable from source' do
6
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[1, 2, 2, 3, 2, 4, 4, 5])
7
+
8
+ expect(graph.filter(2, nil).to_s).to eq('(2-3)(2-4)(4-5)')
9
+ end
10
+ it 'should remove nodes not reachable from source' do
11
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[1, 2, 2, 3, 2, 4, 4, 5, 3, 5])
12
+
13
+ expect(graph.filter(3, nil).to_s).to eq('(3-5)')
14
+ end
15
+ it 'should remove nodes not reachable to destination' do
16
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
17
+ 1, 2,
18
+ 1, 3,
19
+ 1, 4,
20
+ 2, 3,
21
+ 2, 4,
22
+ 3, 4,
23
+ ])
24
+
25
+ expect(graph.filter(nil, 3).to_s).to eq('(1-2)(1-3)(2-3)')
26
+ end
27
+ it 'should remove nodes not reachable to destination from source' do
28
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
29
+ 1, 2,
30
+ 1, 3,
31
+ 1, 4,
32
+ 2, 3,
33
+ 2, 4,
34
+ ])
35
+
36
+ expect(graph.filter(2, 4).to_s).to eq('(2-4)')
37
+ end
38
+ it 'should retain edges which pass through intermediate nodes' do
39
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
40
+ 1, 2,
41
+ 1, 3,
42
+ 1, 4,
43
+ 2, 3,
44
+ 2, 4,
45
+ 3, 4,
46
+ ])
47
+ expect(graph.filter(2, 4).to_s).to eq('(2-3)(2-4)(3-4)')
48
+ end
49
+ it 'should remove nodes not reachable to destination from source #1' do
50
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
51
+ 1, 2,
52
+ 1, 3,
53
+ 1, 4,
54
+ 2, 3,
55
+ 2, 4,
56
+ 3, 5,
57
+ 5, 4
58
+ ])
59
+ expect(graph.filter(1, 5).to_s).to eq('(1-2)(1-3)(2-3)(3-5)')
60
+ end
61
+ it 'should remove nodes not reachable to destination from source #2' do
62
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
63
+ 1, 2,
64
+ 1, 3,
65
+ 1, 4,
66
+ 2, 3,
67
+ 2, 4,
68
+ 3, 5,
69
+ 5, 4
70
+ ])
71
+ expect(graph.filter(1, 4).to_s).to eq('(1-2)(1-3)(1-4)(2-3)(2-4)(3-5)(5-4)')
72
+ end
73
+ it 'should remove nodes not reachable to destination from source #3' do
74
+ graph = GraphFilter.new(RGL::DirectedAdjacencyGraph[
75
+ 1, 2,
76
+ 1, 3,
77
+ 1, 4,
78
+ 2, 3,
79
+ 2, 4,
80
+ 3, 5,
81
+ 5, 4
82
+ ])
83
+ expect(graph.filter(2, 4).to_s).to eq('(2-3)(2-4)(3-5)(5-4)')
84
+ end
85
+ end
@@ -0,0 +1 @@
1
+ {"nodes":[{"id":"asv-app","label":"asv-app"},{"id":"asv-bastion","label":"asv-bastion"},{"id":"*","label":"*"},{"id":"asv-db","label":"asv-db"},{"id":"asv-solr","label":"asv-solr"},{"id":"default","label":"default"}],"edges":[{"id":"asv-bastion-asv-app","source":"asv-bastion","target":"asv-app","label":"22/tcp"},{"id":"*-asv-app","source":"*","target":"asv-app","label":"80/tcp"},{"id":"*-asv-bastion","source":"*","target":"asv-bastion","label":"22/tcp"},{"id":"asv-app-asv-db","source":"asv-app","target":"asv-db","label":"5432/tcp"},{"id":"asv-bastion-asv-db","source":"asv-bastion","target":"asv-db","label":"22/tcp"},{"id":"asv-app-asv-solr","source":"asv-app","target":"asv-solr","label":"8983/tcp"},{"id":"asv-bastion-asv-solr","source":"asv-bastion","target":"asv-solr","label":"22/tcp"},{"id":"default-default","source":"default","target":"default","label":"*"},{"id":"*-default","source":"*","target":"default","label":"22/tcp"},{"id":"default-*","source":"default","target":"*","label":"*"}]}
@@ -1 +1 @@
1
- {"nodes":[{"id":"app","label":"app"},{"id":"8.8.8.8/32","label":"8.8.8.8/32"},{"id":"amazon-elb-sg","label":"amazon-elb-sg"},{"id":"*","label":"*"},{"id":"db","label":"db"}],"edges":[{"id":"8.8.8.8/32-app","source":"8.8.8.8/32","target":"app","label":"80/tcp"},{"id":"amazon-elb-sg-app","source":"amazon-elb-sg","target":"app","label":"80/tcp"},{"id":"*-app","source":"*","target":"app","label":"22/tcp"},{"id":"app-db","source":"app","target":"db","label":"5984/tcp"}]}
1
+ {"nodes":[{"id":"app","label":"app"},{"id":"8.8.8.8/32","label":"8.8.8.8/32"},{"id":"amazon-elb-sg","label":"amazon-elb-sg"},{"id":"*","label":"*"},{"id":"db","label":"db"}],"edges":[{"id":"app-db","source":"app","target":"db","label":"5984/tcp"},{"id":"8.8.8.8/32-app","source":"8.8.8.8/32","target":"app","label":"80/tcp"},{"id":"amazon-elb-sg-app","source":"amazon-elb-sg","target":"app","label":"80/tcp"},{"id":"*-app","source":"*","target":"app","label":"22/tcp"}]}
@@ -9,6 +9,8 @@ describe VisualizeAws do
9
9
  }
10
10
  let(:source_file) { File.join(File.dirname(__FILE__), 'dummy.json') }
11
11
  let(:config) { AwsConfig.new({groups: {'0.0.0.0/0' => '*'}}) }
12
+ let(:expected_content) { File.read(expected_file) }
13
+ let(:actual_content) { temp_file.read }
12
14
 
13
15
  context 'json to dot file' do
14
16
  let(:expected_file) { File.join(File.dirname(__FILE__), 'dummy.dot') }
@@ -16,7 +18,7 @@ describe VisualizeAws do
16
18
 
17
19
  it 'should parse json input', :integration => true do
18
20
  VisualizeAws.new(config, opts).unleash(temp_file.path)
19
- expect(File.read(expected_file)).to eq(temp_file.read)
21
+ expect(expected_content).to eq(actual_content)
20
22
  end
21
23
  end
22
24
 
@@ -27,7 +29,28 @@ describe VisualizeAws do
27
29
  it 'should parse json input', :integration => true do
28
30
  expect(FileUtils).to receive(:copy)
29
31
  VisualizeAws.new(config, opts).unleash(temp_file.path)
30
- expect(File.read(expected_file)).to eq(temp_file.read)
32
+ expect(JSON.parse(expected_content)).to eq(JSON.parse(actual_content))
33
+ end
34
+ end
35
+
36
+ if ENV['TEST_ACCESS_KEY']
37
+ context 'ec2 to json file' do
38
+ let(:expected_file) { File.join(File.dirname(__FILE__), 'aws_expected.json') }
39
+ let(:temp_file) { Tempfile.new(%w(aws .json)) }
40
+ let(:opts) {
41
+ {
42
+ :filename => temp_file,
43
+ :secret_key => ENV['TEST_SECRET_KEY'],
44
+ :access_key => ENV['TEST_ACCESS_KEY']
45
+ }
46
+ }
47
+
48
+ it 'should read from ec2 account', :integration => true do
49
+ expect(FileUtils).to receive(:copy)
50
+ VisualizeAws.new(config, opts).unleash(temp_file.path)
51
+ expect(JSON.parse(expected_content)['edges']).to match_array(JSON.parse(actual_content)['edges'])
52
+ expect(JSON.parse(expected_content)['nodes']).to match_array(JSON.parse(actual_content)['nodes'])
53
+ end
31
54
  end
32
55
  end
33
56
  end
@@ -1,5 +1,21 @@
1
1
  require 'spec_helper'
2
2
 
3
+ class DummyRenderer
4
+ attr_reader :output
5
+
6
+ def initialize
7
+ @output = []
8
+ end
9
+
10
+ def add_node(name)
11
+ @output << [:node, name]
12
+ end
13
+
14
+ def add_edge(from, to, opts)
15
+ @output << [:edge, from, to, opts]
16
+ end
17
+ end
18
+
3
19
  describe VisualizeAws do
4
20
  before do
5
21
  @ec2 = double(Fog::Compute)
@@ -7,16 +23,17 @@ describe VisualizeAws do
7
23
  end
8
24
 
9
25
  let(:visualize_aws) { VisualizeAws.new(AwsConfig.new) }
26
+ let(:renderer) { DummyRenderer.new }
10
27
 
11
28
  it 'should add nodes, edges for each security group' do
12
29
  expect(@ec2).to receive(:security_groups).and_return([group('Remote ssh', group_ingress('22', 'My machine')), group('My machine')])
13
30
  graph = visualize_aws.build
14
31
 
15
- expect(graph.ops).to eq([
16
- [:node, 'Remote ssh'],
17
- [:node, 'My machine'],
18
- [:edge, 'My machine', 'Remote ssh', {:color => :blue, :label => '22/tcp'}],
19
- ])
32
+ expect(graph.output(renderer)).to contain_exactly(
33
+ [:node, 'Remote ssh'],
34
+ [:node, 'My machine'],
35
+ [:edge, 'My machine', 'Remote ssh', {:color => :blue, :label => '22/tcp'}],
36
+ )
20
37
  end
21
38
 
22
39
  context 'groups' do
@@ -24,33 +41,33 @@ describe VisualizeAws do
24
41
  expect(@ec2).to receive(:security_groups).and_return([group('Web', group_ingress('80', 'ELB'))])
25
42
  graph = visualize_aws.build
26
43
 
27
- expect(graph.ops).to eq([
28
- [:node, 'Web'],
29
- [:node, 'ELB'],
30
- [:edge, 'ELB', 'Web', {:color => :blue, :label => '80/tcp'}],
31
- ])
44
+ expect(graph.output(renderer)).to contain_exactly(
45
+ [:node, 'Web'],
46
+ [:node, 'ELB'],
47
+ [:edge, 'ELB', 'Web', {:color => :blue, :label => '80/tcp'}]
48
+ )
32
49
  end
33
50
 
34
51
  it 'should add an edge for each security ingress' do
35
52
  expect(@ec2).to receive(:security_groups).and_return(
36
- [
37
- group('App', group_ingress('80', 'Web'), group_ingress('8983', 'Internal')),
38
- group('Web', group_ingress('80', 'External')),
39
- group('Db', group_ingress('7474', 'App'))
40
- ])
53
+ [
54
+ group('App', group_ingress('80', 'Web'), group_ingress('8983', 'Internal')),
55
+ group('Web', group_ingress('80', 'External')),
56
+ group('Db', group_ingress('7474', 'App'))
57
+ ])
41
58
  graph = visualize_aws.build
42
59
 
43
- expect(graph.ops).to eq([
44
- [:node, 'App'],
45
- [:node, 'Web'],
46
- [:edge, 'Web', 'App', {:color => :blue, :label => '80/tcp'}],
47
- [:node, 'Internal'],
48
- [:edge, 'Internal', 'App', {:color => :blue, :label => '8983/tcp'}],
49
- [:node, 'External'],
50
- [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
51
- [:node, 'Db'],
52
- [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}],
53
- ])
60
+ expect(graph.output(renderer)).to contain_exactly(
61
+ [:node, 'App'],
62
+ [:node, 'Web'],
63
+ [:edge, 'Web', 'App', {:color => :blue, :label => '80/tcp'}],
64
+ [:node, 'Internal'],
65
+ [:edge, 'Internal', 'App', {:color => :blue, :label => '8983/tcp'}],
66
+ [:node, 'External'],
67
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
68
+ [:node, 'Db'],
69
+ [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}]
70
+ )
54
71
 
55
72
  end
56
73
  end
@@ -59,123 +76,123 @@ describe VisualizeAws do
59
76
 
60
77
  it 'should add an edge for each cidr ingress' do
61
78
  expect(@ec2).to receive(:security_groups).and_return(
62
- [
63
- group('Web', group_ingress('80', 'External')),
64
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
65
- ])
79
+ [
80
+ group('Web', group_ingress('80', 'External')),
81
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
82
+ ])
66
83
  graph = visualize_aws.build
67
84
 
68
- expect(graph.ops).to eq([
69
- [:node, 'Web'],
70
- [:node, 'External'],
71
- [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
72
- [:node, 'Db'],
73
- [:node, 'App'],
74
- [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}],
75
- [:node, '127.0.0.1/32'],
76
- [:edge, '127.0.0.1/32', 'Db', {:color => :blue, :label => '22/tcp'}],
77
- ])
85
+ expect(graph.output(renderer)).to contain_exactly(
86
+ [:node, 'Web'],
87
+ [:node, 'External'],
88
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
89
+ [:node, 'Db'],
90
+ [:node, 'App'],
91
+ [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}],
92
+ [:node, '127.0.0.1/32'],
93
+ [:edge, '127.0.0.1/32', 'Db', {:color => :blue, :label => '22/tcp'}]
94
+ )
78
95
 
79
96
  end
80
97
 
81
98
  it 'should add map edges for cidr ingress' do
82
99
  expect(@ec2).to receive(:security_groups).and_return(
83
- [
84
- group('Web', group_ingress('80', 'External')),
85
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
86
- ])
100
+ [
101
+ group('Web', group_ingress('80', 'External')),
102
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
103
+ ])
87
104
  mapping = {'127.0.0.1/32' => 'Work'}
88
105
  mapping = CidrGroupMapping.new([], mapping)
89
106
  allow(CidrGroupMapping).to receive(:new).and_return(mapping)
90
107
 
91
108
  graph = visualize_aws.build
92
109
 
93
- expect(graph.ops).to eq([
94
- [:node, 'Web'],
95
- [:node, 'External'],
96
- [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
97
- [:node, 'Db'],
98
- [:node, 'App'],
99
- [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}],
100
- [:node, 'Work'],
101
- [:edge, 'Work', 'Db', {:color => :blue, :label => '22/tcp'}],
102
- ])
110
+ expect(graph.output(renderer)).to contain_exactly(
111
+ [:node, 'Web'],
112
+ [:node, 'External'],
113
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
114
+ [:node, 'Db'],
115
+ [:node, 'App'],
116
+ [:edge, 'App', 'Db', {:color => :blue, :label => '7474/tcp'}],
117
+ [:node, 'Work'],
118
+ [:edge, 'Work', 'Db', {:color => :blue, :label => '22/tcp'}]
119
+ )
103
120
 
104
121
  end
105
122
 
106
123
  it 'should group mapped duplicate edges for cidr ingress' do
107
124
  expect(@ec2).to receive(:security_groups).and_return(
108
- [
109
- group('ssh', cidr_ingress('22', '192.168.0.1/32'), cidr_ingress('22', '127.0.0.1/32'))
110
- ])
125
+ [
126
+ group('ssh', cidr_ingress('22', '192.168.0.1/32'), cidr_ingress('22', '127.0.0.1/32'))
127
+ ])
111
128
  mapping = {'127.0.0.1/32' => 'Work', '192.168.0.1/32' => 'Work'}
112
129
  mapping = CidrGroupMapping.new([], mapping)
113
130
  allow(CidrGroupMapping).to receive(:new).and_return(mapping)
114
131
 
115
132
  graph = visualize_aws.build
116
133
 
117
- expect(graph.ops).to eq([
118
- [:node, 'ssh'],
119
- [:node, 'Work'],
120
- [:edge, 'Work', 'ssh', {:color => :blue, :label => '22/tcp'}],
121
- ])
134
+ expect(graph.output(renderer)).to contain_exactly(
135
+ [:node, 'ssh'],
136
+ [:node, 'Work'],
137
+ [:edge, 'Work', 'ssh', {:color => :blue, :label => '22/tcp'}]
138
+ )
122
139
  end
123
140
  end
124
141
 
125
142
  context "filter" do
126
143
  it 'include cidr which do not match the pattern' do
127
144
  expect(@ec2).to receive(:security_groups).and_return(
128
- [
129
- group('Web', cidr_ingress('22', '127.0.0.1/32')),
130
- group('Db', cidr_ingress('22', '192.0.1.1/32'))
131
- ])
145
+ [
146
+ group('Web', cidr_ingress('22', '127.0.0.1/32')),
147
+ group('Db', cidr_ingress('22', '192.0.1.1/32'))
148
+ ])
132
149
 
133
150
  opts = {:exclude => ['127.*']}
134
151
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
135
152
 
136
- expect(graph.ops).to eq([
137
- [:node, 'Web'],
138
- [:node, 'Db'],
139
- [:node, '192.0.1.1/32'],
140
- [:edge, '192.0.1.1/32', 'Db', {:color => :blue, :label => '22/tcp'}],
141
- ])
153
+ expect(graph.output(renderer)).to contain_exactly(
154
+ [:node, 'Web'],
155
+ [:node, 'Db'],
156
+ [:node, '192.0.1.1/32'],
157
+ [:edge, '192.0.1.1/32', 'Db', {:color => :blue, :label => '22/tcp'}]
158
+ )
142
159
  end
143
160
 
144
161
  it 'include groups which do not match the pattern' do
145
162
  expect(@ec2).to receive(:security_groups).and_return(
146
- [
147
- group('Web', group_ingress('80', 'External')),
148
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
149
- ])
163
+ [
164
+ group('Web', group_ingress('80', 'External')),
165
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
166
+ ])
150
167
 
151
168
  opts = {:exclude => ['D.*b', 'App']}
152
169
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
153
170
 
154
- expect(graph.ops).to eq([
155
- [:node, 'Web'],
156
- [:node, 'External'],
157
- [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
158
- ])
171
+ expect(graph.output(renderer)).to contain_exactly(
172
+ [:node, 'Web'],
173
+ [:node, 'External'],
174
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}]
175
+ )
159
176
  end
160
177
 
161
178
  it 'include derived groups which do not match the pattern' do
162
179
  expect(@ec2).to receive(:security_groups).and_return(
163
- [
164
- group('Web', group_ingress('80', 'External')),
165
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
166
- ])
180
+ [
181
+ group('Web', group_ingress('80', 'External')),
182
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
183
+ ])
167
184
 
168
185
  opts = {:exclude => ['App']}
169
186
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
170
187
 
171
- expect(graph.ops).to eq([
172
- [:node, 'Web'],
173
- [:node, 'External'],
174
- [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
175
- [:node, 'Db'],
176
- [:node, '127.0.0.1/32'],
177
- [:edge, '127.0.0.1/32', 'Db', {:color => :blue, :label => '22/tcp'}],
178
- ])
188
+ expect(graph.output(renderer)).to contain_exactly(
189
+ [:node, 'Web'],
190
+ [:node, 'External'],
191
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
192
+ [:node, 'Db'],
193
+ [:node, '127.0.0.1/32'],
194
+ [:edge, '127.0.0.1/32', 'Db', {:color => :blue, :label => '22/tcp'}]
195
+ )
179
196
 
180
197
  end
181
198
  end
metadata CHANGED
@@ -1,141 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_security_viz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4.pre.alpha.pre.81
4
+ version: 0.1.4.pre.alpha.pre.82
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anay Nayak
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-15 00:00:00.000000000 Z
11
+ date: 2017-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.13'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.13'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 11.2.2
33
+ version: 12.0.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 11.2.2
40
+ version: 12.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: 3.5.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 3.5.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: ruby-graphviz
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 1.2.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 1.2.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: fog-aws
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.11.0
75
+ version: 1.2.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.11.0
82
+ version: 1.2.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: unf
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: 0.1.4
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.1.4
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: json
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 2.0.2
103
+ version: 2.0.3
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 2.0.2
110
+ version: 2.0.3
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: trollop
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ~>
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
117
  version: 2.1.2
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ~>
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.1.2
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: organic_hash
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ~>
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
131
  version: 1.0.2
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ~>
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.0.2
139
+ - !ruby/object:Gem::Dependency
140
+ name: rgl
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.5.2
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.5.2
139
153
  description: Provides a quick mechanism to visualize your EC2 security groups in multiple
140
154
  formats
141
155
  email: anayak007+rubygems@gmail.com
@@ -144,8 +158,8 @@ executables:
144
158
  extensions: []
145
159
  extra_rdoc_files: []
146
160
  files:
147
- - .gitignore
148
- - .travis.yml
161
+ - ".gitignore"
162
+ - ".travis.yml"
149
163
  - CHANGELOG.md
150
164
  - Gemfile
151
165
  - LICENSE.md
@@ -167,12 +181,15 @@ files:
167
181
  - lib/exclusions.rb
168
182
  - lib/export/html/view.html
169
183
  - lib/graph.rb
184
+ - lib/graph_filter.rb
170
185
  - lib/opts.yml.sample
171
186
  - lib/provider/ec2.rb
172
187
  - lib/provider/json.rb
173
188
  - lib/renderer/graphviz.rb
174
189
  - lib/renderer/json.rb
175
190
  - lib/version.rb
191
+ - spec/graph_filter_spec.rb
192
+ - spec/integration/aws_expected.json
176
193
  - spec/integration/dummy.dot
177
194
  - spec/integration/dummy.json
178
195
  - spec/integration/expected.json
@@ -189,12 +206,12 @@ require_paths:
189
206
  - lib
190
207
  required_ruby_version: !ruby/object:Gem::Requirement
191
208
  requirements:
192
- - - ! '>='
209
+ - - ">="
193
210
  - !ruby/object:Gem::Version
194
211
  version: 2.0.0
195
212
  required_rubygems_version: !ruby/object:Gem::Requirement
196
213
  requirements:
197
- - - ! '>'
214
+ - - ">"
198
215
  - !ruby/object:Gem::Version
199
216
  version: 1.3.1
200
217
  requirements: []
@@ -204,6 +221,8 @@ signing_key:
204
221
  specification_version: 4
205
222
  summary: Visualize your aws security groups
206
223
  test_files:
224
+ - spec/graph_filter_spec.rb
225
+ - spec/integration/aws_expected.json
207
226
  - spec/integration/dummy.dot
208
227
  - spec/integration/dummy.json
209
228
  - spec/integration/expected.json