aws_security_viz 0.1.2.pre.alpha.pre.58 → 0.1.2.pre.alpha.pre.59

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NmYxNzdmYTg5OTc1ODk0N2UwNzgwOWYwZTI5ZTdjZmZiNDg0MTk0Mg==
4
+ ZTU2ODBmNTYyYTNkYTUwZWVlNGM4ODQwNWUxOGI4ZWU0ZDlhMTIwMQ==
5
5
  data.tar.gz: !binary |-
6
- NWY5NTNkOWU4NDNmNjg5OWRhMjE5YjkxNzZlMzA0OGI1NWYxZWE0NQ==
6
+ YTMzYTFhODNlZjAyMWEwMjRiNjUzN2JjZDc1M2I0ZGNhODAwMDRjMg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NDJhODY3ZDBjYzNlMjE2NGFjMGYwNjQ0YWI1OTZjMTkxNGIzYjczMjllOGY2
10
- N2EwN2IxNGE1ZDZiZDZiZTE5MGUxYjczNTZhNjU4MTBkNTk1YWM0MGU2MDJl
11
- NDNmMTE1YWE4ZDE3ZmMyYmQ3MDFlMjRmMGM0ZjMyZDkyNThkOGI=
9
+ ZDNjMTcxMGU3ZDlhYjlmYzc4ZTExZTQ0MWI5NDlkMTNjYWFjYmY0ZDZhYmM3
10
+ YTIzMzIwNzQ0N2U5NjM3Njk3YmM5OGIzMjUwZjRmZjRlM2I4OWNlNzBlOGQy
11
+ M2YwZTYxZmE4NTkwNTQ4Y2VmZDQyNjBhYWVhZjY5ZDAzNDM4YWM=
12
12
  data.tar.gz: !binary |-
13
- Y2IyZDZkZDhjMDJkMmYyMjI2YzBkYzk0NmVkZGEzMDhkMDI3NTI3Mzg5MDgy
14
- MjZmMmRhMGM2MGU4MjA1MTlkOTg2OTYyZjkzMDM3NDIyY2VjZDM0YzdmY2I2
15
- YTg2ZjBkOTIwYTM1OGMwMzIzNGIzNDk1NjQzMDU1NzdmZTMxYzE=
13
+ YzIxOGFiZmMzNDYyMTNhZGZjYmMyNzBhZmZhOTYwYzE1ZDllOTU1NDM4NzVk
14
+ NzU3Njg1Y2RiMDcxNzlkNWU1MWRiYTdhNDE0NjQxYmZjNDYzMWM1N2U4MmU4
15
+ NDUzOTM0ZGEzMzM4OWFhYTBiYjAyNGJiZDk3ZTgzZTc0YThmYzc=
@@ -1,6 +1,8 @@
1
1
  require_relative 'ec2/security_groups'
2
2
  require_relative 'provider/json'
3
3
  require_relative 'provider/ec2'
4
+ require_relative 'renderer/graphviz'
5
+ require_relative 'renderer/json'
4
6
  require_relative 'graph'
5
7
  require_relative 'exclusions'
6
8
  require_relative 'debug_graph'
@@ -17,28 +19,25 @@ class VisualizeAws
17
19
 
18
20
  def unleash(output_file)
19
21
  g = build
20
- render(g, output_file)
22
+ renderer = output_file.end_with?('json') ? Renderer::Json.new(output_file, @config) : Renderer::GraphViz.new(output_file, @config)
23
+ g.output(renderer)
21
24
  end
22
25
 
23
26
  def build
24
- g = ENV["OBFUSCATE"] ? DebugGraph.new : Graph.new
27
+ g = ENV["OBFUSCATE"] ? DebugGraph.new(@config) : Graph.new(@config)
25
28
  @security_groups.each_with_index { |group, index|
26
29
  picker = ColorPicker.new(@options[:color])
27
30
  g.add_node(group.name)
28
31
  group.traffic.each { |traffic|
29
- if traffic.ingress
30
- g.add_edge(traffic.from, traffic.to, :color => picker.color(index, traffic.ingress), :style => 'bold', :label => traffic.port_range)
32
+ if traffic.ingress
33
+ g.add_edge(traffic.from, traffic.to, :color => picker.color(index, traffic.ingress), :label => traffic.port_range)
31
34
  else
32
- g.add_edge(traffic.to, traffic.from, :color => picker.color(index, traffic.ingress), :style => 'bold', :label => traffic.port_range)
35
+ g.add_edge(traffic.to, traffic.from, :color => picker.color(index, traffic.ingress), :label => traffic.port_range)
33
36
  end
34
37
  }
35
38
  }
36
39
  g
37
40
  end
38
41
 
39
- def render(g, output_file)
40
- extension = File.extname(output_file)
41
- g.output(extension[1..-1].to_sym => output_file, :use => @config.format)
42
- end
43
42
  end
44
43
 
data/lib/debug_graph.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'digest'
2
+ require_relative 'graph'
2
3
 
3
4
  class DebugGraph
4
- def initialize
5
- @g = Graph.new
5
+ def initialize(config)
6
+ @g = Graph.new(config)
6
7
  end
7
8
 
8
9
  def add_node(name)
@@ -13,8 +14,8 @@ class DebugGraph
13
14
  @g.add_edge(h(from), h(to), opts.update(label: h(opts[:label])))
14
15
  end
15
16
 
16
- def output(opts)
17
- @g.output(opts)
17
+ def output(renderer)
18
+ @g.output(renderer)
18
19
  end
19
20
 
20
21
  private
@@ -1,36 +1,132 @@
1
- <html>
2
- <head>
3
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css">
4
- <link rel="stylesheet" href="https://cdn.rawgit.com/mountainstorm/jquery.graphviz.svg/master/css/graphviz.svg.css">
5
- </head>
6
- <body>
7
- <div id="graph" style=""></div>
8
- <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
9
- <script type="text/javascript" src="https://cdn.rawgit.com/jquery/jquery-mousewheel/master/jquery.mousewheel.min.js"></script>
10
- <script type="text/javascript" src="https://cdn.rawgit.com/jquery/jquery-color/master/jquery.color.js"></script>
11
- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
12
- <script type="text/javascript" src="https://cdn.rawgit.com/mountainstorm/jquery.graphviz.svg/master/js/jquery.graphviz.svg.js"></script>
13
- <script type="text/javascript">
14
- $(document).ready(function(){
15
- $("#graph").graphviz({
16
- url: "demo.svg",
17
- ready: function() {
18
- var gv = this
19
- gv.nodes().click(function () {
20
- var $set = $()
21
- $set.push(this)
22
- $set = $set.add(gv.linkedFrom(this, true))
23
- gv.highlight($set, true)
24
- gv.bringToFront($set)
25
- })
26
- $(document).keydown(function (evt) {
27
- if (evt.keyCode == 27) {
28
- gv.highlight()
29
- }
30
- })
31
- }
32
- });
1
+ <html>
2
+ <head>
3
+ <style type="text/css">
4
+ #container {
5
+ max-width: 100%;
6
+ height: 100%;
7
+ margin: auto;
8
+ }
9
+ </style>
10
+ </head>
11
+ <body>
12
+ <div id="container"></div>
13
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/sigma.min.js"></script>
14
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/plugins/sigma.parsers.json.min.js"></script>
15
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/plugins/sigma.layouts.forceLink.min.js"></script>
16
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/plugins/sigma.plugins.design.min.js"></script>
17
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/plugins/sigma.plugins.colorbrewer.min.js"></script>
18
+ <script src="https://rawgit.com/Linkurious/linkurious.js/develop/dist/plugins/sigma.renderers.edgeLabels.min.js"></script>
19
+ <script>
20
+ sigma.classes.graph.addMethod('neighbors', function (nodeId) {
21
+ var k,
22
+ neighbors = {},
23
+ index = this.allNeighborsIndex[nodeId] || {};
24
+
25
+ for (k in index)
26
+ neighbors[k] = this.nodesIndex[k];
27
+
28
+ return neighbors;
29
+ });
30
+ sigma.classes.graph.addMethod('neighborCount', function (nodeId) {
31
+ return this.allNeighborsCount[nodeId];
32
+ });
33
+ var config = {
34
+ renderer: {
35
+ container: 'container',
36
+ type: 'canvas'
37
+ },
38
+ settings: {
39
+ animationsTime: 1000,
40
+ borderSize: 1,
41
+ outerBorderSize: 1,
42
+ defaultNodeOuterBorderColor: 'rgb(236, 81, 72)',
43
+ enableEdgeHovering: true,
44
+ edgeHoverHighlightNodes: 'circle',
45
+ sideMargin: 1,
46
+ edgeHoverColor: 'edge',
47
+ defaultEdgeHoverColor: '#000',
48
+ edgeHoverExtremities: true,
49
+ scalingMode: 'outside',
50
+ edgeLabelThreshold: 2,
51
+ edgeHoverSizeRatio: 2,
52
+ edgeLabelSize: 'proportional'
53
+ }
54
+ };
55
+ sigma.parsers.json('/aws.json', config, function (s) {
56
+ s.graph.nodes().forEach(function (n) {
57
+ n.x = Math.random();
58
+ n.y = Math.random();
59
+ n.size = 1;
60
+ n.label = n.id;
61
+ n.data = {edgeCount: s.graph.neighborCount(n.id)};
62
+ });
63
+ var myStyles = {
64
+ nodes: {
65
+ color: {
66
+ by: 'data.edgeCount',
67
+ scheme: 'colorbrewer.nodes',
68
+ bins: 3
69
+ },
70
+ size: {
71
+ by: 'data.edgeCount',
72
+ bins: 7,
73
+ min: 2,
74
+ max: 10
75
+ }
76
+ }
77
+ };
78
+ var myPalette = {
79
+ colorbrewer: {
80
+ nodes: sigma.plugins.colorbrewer.Dark2
81
+ }
82
+ };
83
+ var design = sigma.plugins.design(s, {styles: myStyles, palette: myPalette});
84
+ design.apply();
85
+
86
+ s.graph.nodes().forEach(function (n) {
87
+ n.originalColor = n.color;
88
+ });
89
+ s.graph.edges().forEach(function (e) {
90
+ e.size = 1;
91
+ e.originalColor = e.color;
92
+ e.type = "arrow";
93
+ });
94
+ var fa = sigma.layouts.startForceLink(s, {autoStop: true, adjustSizes: true, randomize: true});
95
+
96
+ s.bind('clickNode', function (e) {
97
+ var nodeId = e.data.node.id,
98
+ toKeep = s.graph.neighbors(nodeId);
99
+ toKeep[nodeId] = e.data.node;
100
+
101
+ s.graph.nodes().forEach(function (n) {
102
+ if (toKeep[n.id])
103
+ n.color = n.originalColor;
104
+ else
105
+ n.color = '#eee';
33
106
  });
34
- </script>
35
- </body>
36
- </html>
107
+
108
+ s.graph.edges().forEach(function (e) {
109
+ if (toKeep[e.source] && toKeep[e.target])
110
+ e.color = e.originalColor;
111
+ else
112
+ e.color = '#eee';
113
+ });
114
+
115
+ s.refresh();
116
+ });
117
+ s.bind('clickStage', function (e) {
118
+ s.graph.nodes().forEach(function (n) {
119
+ n.color = n.originalColor;
120
+ });
121
+
122
+ s.graph.edges().forEach(function (e) {
123
+ e.color = e.originalColor;
124
+ });
125
+
126
+ s.refresh();
127
+ });
128
+ });
129
+ </script>
130
+ </body>
131
+ </html>
132
+
data/lib/graph.rb CHANGED
@@ -1,39 +1,46 @@
1
- require 'graphviz'
2
- require 'logger'
3
-
4
1
  class Graph
5
- def initialize
6
- @g = GraphViz::new('G', :type => 'strict digraph') { |g|
7
- g[:overlap] = :false
8
- g[:splines] = :true
9
- g[:sep] = 1
10
- g[:concentrate] = :true
11
- }
2
+ attr_reader :ops
3
+
4
+ def initialize(config)
5
+ @config = config
6
+ @ops = []
7
+ @nodes = Set.new
12
8
  end
13
9
 
14
10
  def add_node(name)
15
11
  log("node: #{name}")
16
- @g.add_node(name) if name
17
- end
18
-
19
- def get_node(name, &block)
20
- @g.get_node(name, &block)
12
+ uniquely_add(@ops, :node, name) {
13
+ [:node, name]
14
+ }
21
15
  end
16
+ #TODO : Dedup edge labels ?
17
+ #TODO : Remove env dependencies
22
18
 
23
19
  def add_edge(from, to, opts)
24
20
  log("edge: #{from} -> #{to}")
25
- @g.add_edge(from, to, opts)
21
+ add_node(from)
22
+ add_node(to)
23
+ uniquely_add(@ops, :edge, from, to) {
24
+ [:edge, from, to, opts]
25
+ }
26
26
  end
27
27
 
28
- def each_edge(&block)
29
- @g.each_edge(&block)
28
+ def output(renderer)
29
+ @ops.each { |op, *args|
30
+ renderer.add_node(*args) if op==:node
31
+ renderer.add_edge(*args) if op==:edge
32
+ }
33
+ renderer.output
30
34
  end
31
35
 
32
- def output(opts)
33
- log("output: #{opts}")
34
- @g.output(opts)
36
+ def uniquely_add(target, type, *opts, &block)
37
+ return if opts.compact.empty?
38
+ return if @nodes.include?([type, opts])
39
+ @nodes.add([type, opts])
40
+ target << yield
35
41
  end
36
42
 
43
+
37
44
  def log(msg)
38
45
  puts msg if ENV["DEBUG"]
39
46
  end
@@ -0,0 +1,30 @@
1
+ require 'graphviz'
2
+
3
+ module Renderer
4
+ class GraphViz
5
+ def initialize(file_name, config)
6
+ @g = ::GraphViz::new('G', :type => 'strict digraph') { |g|
7
+ g[:overlap] = :false
8
+ g[:splines] = :true
9
+ g[:sep] = 1
10
+ g[:concentrate] = :true
11
+ }
12
+ @file_name = file_name
13
+ @config = config
14
+ end
15
+
16
+ def add_node(name)
17
+ @g.add_node(name)
18
+ end
19
+
20
+ def add_edge(from, to, opts)
21
+ @g.add_edge(from, to, ({style: 'bold'}).merge(opts))
22
+ end
23
+
24
+ def output
25
+ extension = File.extname(@file_name)
26
+ opts = {extension[1..-1].to_sym => @file_name, :use => @config.format}
27
+ @g.output(opts)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module Renderer
2
+ class Json
3
+ def initialize(file_name, config)
4
+ @nodes = []
5
+ @edges = []
6
+ @file_name = file_name
7
+ @config = config
8
+ end
9
+
10
+ def add_node(name)
11
+ @nodes << {id: name, label: name}
12
+ end
13
+
14
+ def add_edge(from, to, opts)
15
+ @edges << {id: "#{from}-#{to}", source: from, target: to, label: opts[:label]}
16
+ end
17
+
18
+ def output
19
+ IO.write(@file_name, {nodes: @nodes, edges: @edges}.to_json)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +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,17 +1,28 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe VisualizeAws do
4
- context 'json' do
5
- let(:opts) {
6
- {
4
+ let(:opts) {
5
+ {
7
6
  :source_file => source_file,
8
7
  :filename => temp_file
9
- }
10
8
  }
11
- let(:source_file) {File.join(File.dirname(__FILE__), 'dummy.json')}
12
- let(:expected_file) {File.join(File.dirname(__FILE__), 'dummy.dot')}
9
+ }
10
+ let(:source_file) { File.join(File.dirname(__FILE__), 'dummy.json') }
11
+ let(:config) { AwsConfig.new({groups: {'0.0.0.0/0' => '*'}}) }
12
+
13
+ context 'json to dot file' do
14
+ let(:expected_file) { File.join(File.dirname(__FILE__), 'dummy.dot') }
13
15
  let(:temp_file) { Tempfile.new(%w(aws .dot)) }
14
- let(:config) {AwsConfig.new({groups: {'0.0.0.0/0' => '*'}})}
16
+
17
+ it 'should parse json input', :integration => true do
18
+ VisualizeAws.new(config, opts).unleash(temp_file.path)
19
+ expect(File.read(expected_file)).to eq(temp_file.read)
20
+ end
21
+ end
22
+
23
+ context 'json to json file' do
24
+ let(:expected_file) { File.join(File.dirname(__FILE__), 'expected.json') }
25
+ let(:temp_file) { Tempfile.new(%w(aws .json)) }
15
26
 
16
27
  it 'should parse json input', :integration => true do
17
28
  VisualizeAws.new(config, opts).unleash(temp_file.path)
@@ -6,49 +6,52 @@ describe VisualizeAws do
6
6
  allow(Fog::Compute).to receive(:new).and_return(@ec2)
7
7
  end
8
8
 
9
- let(:visualize_aws) {VisualizeAws.new(AwsConfig.new)}
9
+ let(:visualize_aws) { VisualizeAws.new(AwsConfig.new) }
10
10
 
11
- it 'should add nodes for each security group' do
11
+ it 'should add nodes, edges for each security group' do
12
12
  expect(@ec2).to receive(:security_groups).and_return([group('Remote ssh', group_ingress('22', 'My machine')), group('My machine')])
13
13
  graph = visualize_aws.build
14
- node1 = graph.get_node('Remote ssh')
15
- node2 = graph.get_node('My machine')
16
14
 
17
- expect(node1).not_to be_nil
18
- expect(node2).not_to be_nil
19
- expect(graph.each_edge.size).to eq(1)
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
+ ])
20
20
  end
21
21
 
22
22
  context 'groups' do
23
- it 'should add an edge for each security ingress' do
24
- expect(@ec2).to receive(:security_groups).and_return([group('Remote ssh', group_ingress('22', 'My machine')), group('My machine')])
25
- graph = visualize_aws.build
26
-
27
- expect(graph.each_edge.size).to eq(1)
28
- expect(graph).to have_edge "My machine" => 'Remote ssh'
29
- end
30
-
31
23
  it 'should add nodes for external security groups defined through ingress' do
32
24
  expect(@ec2).to receive(:security_groups).and_return([group('Web', group_ingress('80', 'ELB'))])
33
25
  graph = visualize_aws.build
34
26
 
35
- expect(graph.get_node('Web')).to_not be_nil
36
- expect(graph.get_node('ELB')).to_not be_nil
37
- expect(graph.each_edge.size).to eq(1)
38
- expect(graph).to have_edge("ELB" => 'Web')
27
+ expect(graph.ops).to eq([
28
+ [:node, 'Web'],
29
+ [:node, 'ELB'],
30
+ [:edge, 'ELB', 'Web', {:color => :blue, :label => '80/tcp'}],
31
+ ])
39
32
  end
40
33
 
41
34
  it 'should add an edge for each security ingress' do
42
35
  expect(@ec2).to receive(:security_groups).and_return(
43
- [
44
- group('App', group_ingress('80', 'Web'), group_ingress('8983', 'Internal')),
45
- group('Web', group_ingress('80', 'External')),
46
- group('Db', group_ingress('7474', 'App'))
47
- ])
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
+ ])
48
41
  graph = visualize_aws.build
49
42
 
50
- expect(graph.each_edge.size).to eq(4)
51
- expect(graph).to have_edge('Internal'=>'App', 'External' => 'Web', 'App'=> 'Db')
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
+ ])
54
+
52
55
  end
53
56
  end
54
57
 
@@ -56,92 +59,124 @@ describe VisualizeAws do
56
59
 
57
60
  it 'should add an edge for each cidr ingress' do
58
61
  expect(@ec2).to receive(:security_groups).and_return(
59
- [
60
- group('Web', group_ingress('80', 'External')),
61
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
62
- ])
62
+ [
63
+ group('Web', group_ingress('80', 'External')),
64
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
65
+ ])
63
66
  graph = visualize_aws.build
64
67
 
65
- expect(graph.each_edge.size).to eq(3)
66
- expect(graph).to have_edge('External' => 'Web', 'App'=> 'Db')
67
- expect(graph).to have_edge('127.0.0.1/32' => 'Db' )
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
+ ])
78
+
68
79
  end
69
80
 
70
81
  it 'should add map edges for cidr ingress' do
71
82
  expect(@ec2).to receive(:security_groups).and_return(
72
- [
73
- group('Web', group_ingress('80', 'External')),
74
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
75
- ])
83
+ [
84
+ group('Web', group_ingress('80', 'External')),
85
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
86
+ ])
76
87
  mapping = {'127.0.0.1/32' => 'Work'}
77
88
  mapping = CidrGroupMapping.new([], mapping)
78
89
  allow(CidrGroupMapping).to receive(:new).and_return(mapping)
79
90
 
80
91
  graph = visualize_aws.build
81
92
 
82
- expect(graph.each_edge.size).to eq(3)
83
- expect(graph).to have_edge('External' => 'Web', 'App'=> 'Db')
84
- expect(graph).to have_edge('Work' => 'Db' )
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
+ ])
103
+
85
104
  end
105
+
86
106
  it 'should group mapped duplicate edges for cidr ingress' do
87
107
  expect(@ec2).to receive(:security_groups).and_return(
88
- [
89
- group('ssh', cidr_ingress('22', '192.168.0.1/32'), cidr_ingress('22', '127.0.0.1/32'))
90
- ])
108
+ [
109
+ group('ssh', cidr_ingress('22', '192.168.0.1/32'), cidr_ingress('22', '127.0.0.1/32'))
110
+ ])
91
111
  mapping = {'127.0.0.1/32' => 'Work', '192.168.0.1/32' => 'Work'}
92
112
  mapping = CidrGroupMapping.new([], mapping)
93
113
  allow(CidrGroupMapping).to receive(:new).and_return(mapping)
94
114
 
95
115
  graph = visualize_aws.build
96
116
 
97
- expect(graph.each_edge.size).to eq(1)
98
- expect(graph).to have_edge('Work' => 'ssh' )
117
+ expect(graph.ops).to eq([
118
+ [:node, 'ssh'],
119
+ [:node, 'Work'],
120
+ [:edge, 'Work', 'ssh', {:color => :blue, :label => '22/tcp'}],
121
+ ])
99
122
  end
100
123
  end
124
+
101
125
  context "filter" do
102
126
  it 'include cidr which do not match the pattern' do
103
127
  expect(@ec2).to receive(:security_groups).and_return(
104
- [
105
- group('Web', cidr_ingress('22', '127.0.0.1/32')),
106
- group('Db', cidr_ingress('22', '192.0.1.1/32'))
107
- ])
128
+ [
129
+ group('Web', cidr_ingress('22', '127.0.0.1/32')),
130
+ group('Db', cidr_ingress('22', '192.0.1.1/32'))
131
+ ])
108
132
 
109
133
  opts = {:exclude => ['127.*']}
110
134
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
111
135
 
112
- expect(graph.each_edge.size).to eq(1)
113
- expect(graph).to have_edge('192.0.1.1/32' => 'Db')
114
- expect(graph).to_not have_edge('127.0.0.1/32' => 'Web')
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
+ ])
115
142
  end
116
143
 
117
144
  it 'include groups which do not match the pattern' do
118
145
  expect(@ec2).to receive(:security_groups).and_return(
119
- [
120
- group('Web', group_ingress('80', 'External')),
121
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
122
- ])
146
+ [
147
+ group('Web', group_ingress('80', 'External')),
148
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
149
+ ])
123
150
 
124
151
  opts = {:exclude => ['D.*b', 'App']}
125
152
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
126
153
 
127
- expect(graph.each_edge.size).to eq(1)
128
- expect(graph).to have_edge('External' => 'Web')
154
+ expect(graph.ops).to eq([
155
+ [:node, 'Web'],
156
+ [:node, 'External'],
157
+ [:edge, 'External', 'Web', {:color => :blue, :label => '80/tcp'}],
158
+ ])
129
159
  end
130
160
 
131
161
  it 'include derived groups which do not match the pattern' do
132
162
  expect(@ec2).to receive(:security_groups).and_return(
133
- [
134
- group('Web', group_ingress('80', 'External')),
135
- group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
136
- ])
163
+ [
164
+ group('Web', group_ingress('80', 'External')),
165
+ group('Db', group_ingress('7474', 'App'), cidr_ingress('22', '127.0.0.1/32'))
166
+ ])
137
167
 
138
168
  opts = {:exclude => ['App']}
139
169
  graph = VisualizeAws.new(AwsConfig.new(opts)).build
140
170
 
141
- expect(graph.each_edge.size).to eq(2)
142
- expect(graph).to have_edge('External' => 'Web')
143
- expect(graph).to have_edge('127.0.0.1/32' => 'Db' )
144
- end
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
+ ])
145
179
 
180
+ end
146
181
  end
147
182
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_security_viz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2.pre.alpha.pre.58
4
+ version: 0.1.2.pre.alpha.pre.59
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anay Nayak
@@ -169,12 +169,14 @@ files:
169
169
  - lib/opts.yml.sample
170
170
  - lib/provider/ec2.rb
171
171
  - lib/provider/json.rb
172
+ - lib/renderer/graphviz.rb
173
+ - lib/renderer/json.rb
172
174
  - lib/version.rb
173
175
  - spec/integration/dummy.dot
174
176
  - spec/integration/dummy.json
177
+ - spec/integration/expected.json
175
178
  - spec/integration/visualize_aws_spec.rb
176
179
  - spec/spec_helper.rb
177
- - spec/support/matchers/graph.rb
178
180
  - spec/visualize_aws_spec.rb
179
181
  homepage: https://github.com/anaynayak/aws-security-viz
180
182
  licenses:
@@ -203,7 +205,7 @@ summary: Visualize your aws security groups
203
205
  test_files:
204
206
  - spec/integration/dummy.dot
205
207
  - spec/integration/dummy.json
208
+ - spec/integration/expected.json
206
209
  - spec/integration/visualize_aws_spec.rb
207
210
  - spec/spec_helper.rb
208
- - spec/support/matchers/graph.rb
209
211
  - spec/visualize_aws_spec.rb
@@ -1,8 +0,0 @@
1
- RSpec::Matchers.define :have_edge do |edge|
2
- match do |actual|
3
- edges = actual.each_edge
4
- edge.each do |k,v|
5
- expect(edges.any? {|e| e.node_one == GraphViz.escape(k) && e.node_two == GraphViz.escape(v)}).to eq(true)
6
- end
7
- end
8
- end