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

Sign up to get free protection for your applications and to get access to all the features.
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