miam 0.1.0.beta → 0.1.0

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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78a6357ad96eb46c37e14554170823849a1b7299
4
- data.tar.gz: 5e8e8b62d90cfa1d313874b5d842a505bb07bcfe
3
+ metadata.gz: 1c277e2932203a2740972ef45fb3588f25e08ced
4
+ data.tar.gz: 560435cc28118cc841397919249697a68a2e6851
5
5
  SHA512:
6
- metadata.gz: 2bbe33cd3fc4274a239bfde9bff8eee340af294178b873f9b3f1c533a5efd02f0a41a960ee8d752f54c252eadba21a3f2a1484f939a94e16c96690e173e8ee3f
7
- data.tar.gz: aa09af7d99890cd20908d5f6991846978bc40fcdf007e2cc7b152e72f81f13e49b00b9120646e34524ec95e66bc863a12b5586c49d54518146e4593fa8d01382
6
+ metadata.gz: f631ea1267d5c62723f85129e26508dc712b5189ea53e47ada4aacbcbc4b75f22bf56971364dc7490734343d2e62d885a6bbf68636d622550495a35bda2585b5
7
+ data.tar.gz: fa71e40019ca1342ec1472c07c1ae376b4233e1bda0129ed3715e9c151c751b43d1339e08f11018752ab080ed6cec1debcc79bc9a7104891f13f6eb99c4b3490
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --require rspec/instafail
2
+ --format RSpec::Instafail
3
+ --colour
4
+ --require spec_helper
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script:
5
+ - bundle install
6
+ - bundle exec rake
7
+ env:
8
+ global:
9
+ - secure: "Ec8bwSfp06anSzLJpGhkKjPz9EocMwl7H8t2LKoI3bKV/cz9JU0GhhUdUUmg3mCFH9+8/YGLzcbFKcxZIqnDK7ukdgTGsnGDevnctis0QwM7/nKHdkaK8JWhCx41TUXOqoiCKkNEnm1EbDtrILt4rJwb0BGXGnPjv6nLAyvdE2Y="
10
+ - secure: "Ky5Dpxc7SIqbQ4Y10m/jik/rVdeGMeh1439m3KB+tiV/Bz1hhWv4+If150ajLjbmWCZBPMLhxrTL0EePoyqYXpOGHvINvYM+/XCPcpP4iYkaTzr1MVIOMpa8A8aAOOgQWoGOwfyWoxfrYzv/TRvtMietnm+dZwVcbbkQ4ut7oa4="
11
+ - AWS_REGION=ap-northeast-1
data/README.md CHANGED
@@ -4,6 +4,10 @@ Miam is a tool to manage IAM.
4
4
 
5
5
  It defines the state of IAM using DSL, and updates IAM according to DSL.
6
6
 
7
+ [![Gem Version](https://badge.fury.io/rb/miam.svg)](http://badge.fury.io/rb/miam)
8
+ [![Build Status](https://travis-ci.org/winebarrel/miam.svg?branch=master)](https://travis-ci.org/winebarrel/miam)
9
+ [![Coverage Status](https://coveralls.io/repos/winebarrel/miam/badge.png?branch=master)](https://coveralls.io/r/winebarrel/miam?branch=master)
10
+
7
11
  ## Installation
8
12
 
9
13
  Add this line to your application's Gemfile:
@@ -18,7 +22,7 @@ And then execute:
18
22
 
19
23
  Or install it yourself as:
20
24
 
21
- $ gem install miam --pre
25
+ $ gem install miam
22
26
 
23
27
  ## Usage
24
28
 
@@ -58,7 +62,7 @@ Usage: miam [options]
58
62
  ```ruby
59
63
  require 'other/iamfile'
60
64
 
61
- user "bob", path: "/developer/" do
65
+ user "bob", :path => "/developer/" do
62
66
  login_profile password_reset_required: true
63
67
 
64
68
  groups(
@@ -76,7 +80,7 @@ user "bob", path: "/developer/" do
76
80
  end
77
81
  end
78
82
 
79
- user "mary", path: "/staff/" do
83
+ user "mary", :path => "/staff/" do
80
84
  # login_profile password_reset_required: true
81
85
 
82
86
  groups(
@@ -104,9 +108,23 @@ user "mary", path: "/staff/" do
104
108
  end
105
109
  end
106
110
 
107
- group "Admin", path: "/admin/" do
111
+ group "Admin", :path => "/admin/" do
108
112
  policy "Admin" do
109
113
  {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
110
114
  end
111
115
  end
112
116
  ```
117
+
118
+ ## Rename
119
+
120
+ ```ruby
121
+ require 'other/iamfile'
122
+
123
+ user "bob2", :path => "/developer/", :renamed_from => "bob" do
124
+ # ...
125
+ end
126
+
127
+ group "Admin2", :path => "/admin/". :renamed_from => "Admin" do
128
+ # ...
129
+ end
130
+ ```
data/Rakefile CHANGED
@@ -1,2 +1,5 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
2
3
 
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
@@ -53,6 +53,7 @@ class Miam::Client
53
53
  actual_attrs = actual.delete(user_name)
54
54
 
55
55
  if actual_attrs
56
+ updated = walk_path(:user, user_name, expected_attrs[:path], actual_attrs[:path]) || updated
56
57
  updated = walk_user(user_name, expected_attrs, actual_attrs) || updated
57
58
  else
58
59
  actual_attrs = @driver.create_user(user_name, expected_attrs)
@@ -83,7 +84,7 @@ class Miam::Client
83
84
  def walk_user(user_name, expected_attrs, actual_attrs)
84
85
  updated = walk_login_profile(user_name, expected_attrs[:login_profile], actual_attrs[:login_profile])
85
86
  updated = walk_user_groups(user_name, expected_attrs[:groups], actual_attrs[:groups]) || updated
86
- walk_policies(:user, user_name, expected_attrs[:policies], actual_attrs[:policies])
87
+ walk_policies(:user, user_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
87
88
  end
88
89
 
89
90
  def walk_login_profile(user_name, expected_login_profile, actual_login_profile)
@@ -1,3 +1,3 @@
1
1
  module Miam
2
- VERSION = '0.1.0.beta'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -25,4 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'term-ansicolor'
26
26
  spec.add_development_dependency 'bundler', '~> 1.7'
27
27
  spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '>= 3.0.0'
29
+ spec.add_development_dependency 'rspec-instafail'
30
+ spec.add_development_dependency 'coveralls'
28
31
  end
@@ -0,0 +1,114 @@
1
+ describe 'create' do
2
+ context 'when empty' do
3
+ subject { client }
4
+
5
+ it do
6
+ updated = apply(subject) { '' }
7
+ expect(updated).to be_falsey
8
+ expect(export).to eq({:users=>{}, :groups=>{}})
9
+ end
10
+ end
11
+
12
+ context 'when create user and group' do
13
+ let(:dsl) do
14
+ <<-RUBY
15
+ user "bob", :path=>"/devloper/" do
16
+ login_profile :password_reset_required=>true
17
+
18
+ groups(
19
+ "Admin",
20
+ "SES"
21
+ )
22
+
23
+ policy "S3" do
24
+ {"Statement"=>
25
+ [{"Action"=>
26
+ ["s3:Get*",
27
+ "s3:List*"],
28
+ "Effect"=>"Allow",
29
+ "Resource"=>"*"}]}
30
+ end
31
+ end
32
+
33
+ user "mary", :path=>"/staff/" do
34
+ policy "S3" do
35
+ {"Statement"=>
36
+ [{"Action"=>
37
+ ["s3:Get*",
38
+ "s3:List*"],
39
+ "Effect"=>"Allow",
40
+ "Resource"=>"*"}]}
41
+ end
42
+ end
43
+
44
+ group "Admin", :path=>"/admin/" do
45
+ policy "Admin" do
46
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
47
+ end
48
+ end
49
+
50
+ group "SES", :path=>"/ses/" do
51
+ policy "ses-policy" do
52
+ {"Statement"=>
53
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
54
+ end
55
+ end
56
+ RUBY
57
+ end
58
+
59
+ context 'when apply' do
60
+ subject { client }
61
+
62
+ it do
63
+ updated = apply(subject) { dsl }
64
+ expect(updated).to be_truthy
65
+ expect(export).to eq(
66
+ {:users=>
67
+ {"bob"=>
68
+ {:path=>"/devloper/",
69
+ :groups=>["Admin", "SES"],
70
+ :policies=>
71
+ {"S3"=>
72
+ {"Statement"=>
73
+ [{"Action"=>["s3:Get*", "s3:List*"],
74
+ "Effect"=>"Allow",
75
+ "Resource"=>"*"}]}},
76
+ :login_profile=>{:password_reset_required=>true}},
77
+ "mary"=>
78
+ {:path=>"/staff/",
79
+ :groups=>[],
80
+ :policies=>
81
+ {"S3"=>
82
+ {"Statement"=>
83
+ [{"Action"=>["s3:Get*", "s3:List*"],
84
+ "Effect"=>"Allow",
85
+ "Resource"=>"*"}]}}}},
86
+ :groups=>
87
+ {"Admin"=>
88
+ {:path=>"/admin/",
89
+ :policies=>
90
+ {"Admin"=>
91
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
92
+ "SES"=>
93
+ {:path=>"/ses/",
94
+ :policies=>
95
+ {"ses-policy"=>
96
+ {"Statement"=>
97
+ [{"Effect"=>"Allow",
98
+ "Action"=>"ses:SendRawEmail",
99
+ "Resource"=>"*"}]}}}}}
100
+ )
101
+ end
102
+ end
103
+
104
+ context 'when dry-run' do
105
+ subject { client(dry_run: true) }
106
+
107
+ it do
108
+ updated = apply(subject) { dsl }
109
+ expect(updated).to be_falsey
110
+ expect(export).to eq({:users=>{}, :groups=>{}})
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,222 @@
1
+ describe 'delete' do
2
+ let(:dsl) do
3
+ <<-RUBY
4
+ user "bob", :path=>"/devloper/" do
5
+ login_profile :password_reset_required=>true
6
+
7
+ groups(
8
+ "Admin",
9
+ "SES"
10
+ )
11
+
12
+ policy "S3" do
13
+ {"Statement"=>
14
+ [{"Action"=>
15
+ ["s3:Get*",
16
+ "s3:List*"],
17
+ "Effect"=>"Allow",
18
+ "Resource"=>"*"}]}
19
+ end
20
+ end
21
+
22
+ user "mary", :path=>"/staff/" do
23
+ policy "S3" do
24
+ {"Statement"=>
25
+ [{"Action"=>
26
+ ["s3:Get*",
27
+ "s3:List*"],
28
+ "Effect"=>"Allow",
29
+ "Resource"=>"*"}]}
30
+ end
31
+ end
32
+
33
+ group "Admin", :path=>"/admin/" do
34
+ policy "Admin" do
35
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
36
+ end
37
+ end
38
+
39
+ group "SES", :path=>"/ses/" do
40
+ policy "ses-policy" do
41
+ {"Statement"=>
42
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
43
+ end
44
+ end
45
+ RUBY
46
+ end
47
+
48
+ let(:expected) do
49
+ {:users=>
50
+ {"bob"=>
51
+ {:path=>"/devloper/",
52
+ :groups=>["Admin", "SES"],
53
+ :policies=>
54
+ {"S3"=>
55
+ {"Statement"=>
56
+ [{"Action"=>["s3:Get*", "s3:List*"],
57
+ "Effect"=>"Allow",
58
+ "Resource"=>"*"}]}},
59
+ :login_profile=>{:password_reset_required=>true}},
60
+ "mary"=>
61
+ {:path=>"/staff/",
62
+ :groups=>[],
63
+ :policies=>
64
+ {"S3"=>
65
+ {"Statement"=>
66
+ [{"Action"=>["s3:Get*", "s3:List*"],
67
+ "Effect"=>"Allow",
68
+ "Resource"=>"*"}]}}}},
69
+ :groups=>
70
+ {"Admin"=>
71
+ {:path=>"/admin/",
72
+ :policies=>
73
+ {"Admin"=>
74
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
75
+ "SES"=>
76
+ {:path=>"/ses/",
77
+ :policies=>
78
+ {"ses-policy"=>
79
+ {"Statement"=>
80
+ [{"Effect"=>"Allow",
81
+ "Action"=>"ses:SendRawEmail",
82
+ "Resource"=>"*"}]}}}}}
83
+ end
84
+
85
+ before(:each) do
86
+ apply { dsl }
87
+ end
88
+
89
+ context 'when delete group' do
90
+ let(:delete_group_dsl) do
91
+ <<-RUBY
92
+ user "bob", :path=>"/devloper/" do
93
+ login_profile :password_reset_required=>true
94
+
95
+ groups(
96
+ "Admin"
97
+ )
98
+
99
+ policy "S3" do
100
+ {"Statement"=>
101
+ [{"Action"=>
102
+ ["s3:Get*",
103
+ "s3:List*"],
104
+ "Effect"=>"Allow",
105
+ "Resource"=>"*"}]}
106
+ end
107
+ end
108
+
109
+ user "mary", :path=>"/staff/" do
110
+ policy "S3" do
111
+ {"Statement"=>
112
+ [{"Action"=>
113
+ ["s3:Get*",
114
+ "s3:List*"],
115
+ "Effect"=>"Allow",
116
+ "Resource"=>"*"}]}
117
+ end
118
+ end
119
+
120
+ group "Admin", :path=>"/admin/" do
121
+ policy "Admin" do
122
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
123
+ end
124
+ end
125
+ RUBY
126
+ end
127
+
128
+ subject { client }
129
+
130
+ it do
131
+ updated = apply(subject) { delete_group_dsl }
132
+ expect(updated).to be_truthy
133
+ expected[:users]["bob"][:groups] = ["Admin"]
134
+ expected[:groups].delete("SES")
135
+ expect(export).to eq expected
136
+ end
137
+ end
138
+
139
+ context 'when delete user' do
140
+ let(:delete_user_dsl) do
141
+ <<-RUBY
142
+ user "mary", :path=>"/staff/" do
143
+ policy "S3" do
144
+ {"Statement"=>
145
+ [{"Action"=>
146
+ ["s3:Get*",
147
+ "s3:List*"],
148
+ "Effect"=>"Allow",
149
+ "Resource"=>"*"}]}
150
+ end
151
+ end
152
+
153
+ group "Admin", :path=>"/admin/" do
154
+ policy "Admin" do
155
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
156
+ end
157
+ end
158
+
159
+ group "SES", :path=>"/ses/" do
160
+ policy "ses-policy" do
161
+ {"Statement"=>
162
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
163
+ end
164
+ end
165
+ RUBY
166
+ end
167
+
168
+ subject { client }
169
+
170
+ it do
171
+ updated = apply(subject) { delete_user_dsl }
172
+ expect(updated).to be_truthy
173
+ expected[:users].delete("bob")
174
+ expect(export).to eq expected
175
+ end
176
+ end
177
+
178
+ context 'when delete user_and_group' do
179
+ let(:delete_user_and_group_dsl) do
180
+ <<-RUBY
181
+ user "mary", :path=>"/staff/" do
182
+ policy "S3" do
183
+ {"Statement"=>
184
+ [{"Action"=>
185
+ ["s3:Get*",
186
+ "s3:List*"],
187
+ "Effect"=>"Allow",
188
+ "Resource"=>"*"}]}
189
+ end
190
+ end
191
+
192
+ group "Admin", :path=>"/admin/" do
193
+ policy "Admin" do
194
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
195
+ end
196
+ end
197
+ RUBY
198
+ end
199
+
200
+ context 'when apply' do
201
+ subject { client }
202
+
203
+ it do
204
+ updated = apply(subject) { delete_user_and_group_dsl }
205
+ expect(updated).to be_truthy
206
+ expected[:users].delete("bob")
207
+ expected[:groups].delete("SES")
208
+ expect(export).to eq expected
209
+ end
210
+ end
211
+
212
+ context 'when dry-run' do
213
+ subject { client(dry_run: true) }
214
+
215
+ it do
216
+ updated = apply(subject) { delete_user_and_group_dsl }
217
+ expect(updated).to be_falsey
218
+ expect(export).to eq expected
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,262 @@
1
+ describe 'update' do
2
+ let(:dsl) do
3
+ <<-RUBY
4
+ user "bob", :path=>"/devloper/" do
5
+ login_profile :password_reset_required=>true
6
+
7
+ groups(
8
+ "Admin",
9
+ "SES"
10
+ )
11
+
12
+ policy "S3" do
13
+ {"Statement"=>
14
+ [{"Action"=>
15
+ ["s3:Get*",
16
+ "s3:List*"],
17
+ "Effect"=>"Allow",
18
+ "Resource"=>"*"}]}
19
+ end
20
+ end
21
+
22
+ user "mary", :path=>"/staff/" do
23
+ policy "S3" do
24
+ {"Statement"=>
25
+ [{"Action"=>
26
+ ["s3:Get*",
27
+ "s3:List*"],
28
+ "Effect"=>"Allow",
29
+ "Resource"=>"*"}]}
30
+ end
31
+ end
32
+
33
+ group "Admin", :path=>"/admin/" do
34
+ policy "Admin" do
35
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
36
+ end
37
+ end
38
+
39
+ group "SES", :path=>"/ses/" do
40
+ policy "ses-policy" do
41
+ {"Statement"=>
42
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
43
+ end
44
+ end
45
+ RUBY
46
+ end
47
+
48
+ let(:expected) do
49
+ {:users=>
50
+ {"bob"=>
51
+ {:path=>"/devloper/",
52
+ :groups=>["Admin", "SES"],
53
+ :policies=>
54
+ {"S3"=>
55
+ {"Statement"=>
56
+ [{"Action"=>["s3:Get*", "s3:List*"],
57
+ "Effect"=>"Allow",
58
+ "Resource"=>"*"}]}},
59
+ :login_profile=>{:password_reset_required=>true}},
60
+ "mary"=>
61
+ {:path=>"/staff/",
62
+ :groups=>[],
63
+ :policies=>
64
+ {"S3"=>
65
+ {"Statement"=>
66
+ [{"Action"=>["s3:Get*", "s3:List*"],
67
+ "Effect"=>"Allow",
68
+ "Resource"=>"*"}]}}}},
69
+ :groups=>
70
+ {"Admin"=>
71
+ {:path=>"/admin/",
72
+ :policies=>
73
+ {"Admin"=>
74
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
75
+ "SES"=>
76
+ {:path=>"/ses/",
77
+ :policies=>
78
+ {"ses-policy"=>
79
+ {"Statement"=>
80
+ [{"Effect"=>"Allow",
81
+ "Action"=>"ses:SendRawEmail",
82
+ "Resource"=>"*"}]}}}}}
83
+ end
84
+
85
+ before(:each) do
86
+ apply { dsl }
87
+ end
88
+
89
+ context 'when rename user' do
90
+ let(:rename_user_dsl) do
91
+ <<-RUBY
92
+ user "bob2", :path=>"/devloper/", :renamed_from=>"bob" do
93
+ login_profile :password_reset_required=>true
94
+
95
+ groups(
96
+ "Admin",
97
+ "SES"
98
+ )
99
+
100
+ policy "S3" do
101
+ {"Statement"=>
102
+ [{"Action"=>
103
+ ["s3:Get*",
104
+ "s3:List*"],
105
+ "Effect"=>"Allow",
106
+ "Resource"=>"*"}]}
107
+ end
108
+ end
109
+
110
+ user "mary", :path=>"/staff/" do
111
+ policy "S3" do
112
+ {"Statement"=>
113
+ [{"Action"=>
114
+ ["s3:Get*",
115
+ "s3:List*"],
116
+ "Effect"=>"Allow",
117
+ "Resource"=>"*"}]}
118
+ end
119
+ end
120
+
121
+ group "Admin", :path=>"/admin/" do
122
+ policy "Admin" do
123
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
124
+ end
125
+ end
126
+
127
+ group "SES", :path=>"/ses/" do
128
+ policy "ses-policy" do
129
+ {"Statement"=>
130
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
131
+ end
132
+ end
133
+ RUBY
134
+ end
135
+
136
+ subject { client }
137
+
138
+ it do
139
+ updated = apply(subject) { rename_user_dsl }
140
+ expect(updated).to be_truthy
141
+ expected[:users]["bob2"] = expected[:users].delete("bob")
142
+ expect(export).to eq expected
143
+ end
144
+ end
145
+
146
+ context 'when rename group' do
147
+ let(:rename_group_dsl) do
148
+ <<-RUBY
149
+ user "bob", :path=>"/devloper/" do
150
+ login_profile :password_reset_required=>true
151
+
152
+ groups(
153
+ "Admin",
154
+ "SES2"
155
+ )
156
+
157
+ policy "S3" do
158
+ {"Statement"=>
159
+ [{"Action"=>
160
+ ["s3:Get*",
161
+ "s3:List*"],
162
+ "Effect"=>"Allow",
163
+ "Resource"=>"*"}]}
164
+ end
165
+ end
166
+
167
+ user "mary", :path=>"/staff/" do
168
+ policy "S3" do
169
+ {"Statement"=>
170
+ [{"Action"=>
171
+ ["s3:Get*",
172
+ "s3:List*"],
173
+ "Effect"=>"Allow",
174
+ "Resource"=>"*"}]}
175
+ end
176
+ end
177
+
178
+ group "Admin", :path=>"/admin/" do
179
+ policy "Admin" do
180
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
181
+ end
182
+ end
183
+
184
+ group "SES2", :path=>"/ses/", :renamed_from=>"SES2" do
185
+ policy "ses-policy" do
186
+ {"Statement"=>
187
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
188
+ end
189
+ end
190
+ RUBY
191
+ end
192
+
193
+ subject { client }
194
+
195
+ it do
196
+ updated = apply(subject) { rename_group_dsl }
197
+ expect(updated).to be_truthy
198
+ expected[:users]["bob"][:groups] = ["Admin", "SES2"]
199
+ expected[:groups]["SES2"] = expected[:groups].delete("SES")
200
+ expect(export).to eq expected
201
+ end
202
+ end
203
+
204
+ context 'when rename without renamed_from' do
205
+ let(:rename_without_renamed_from_dsl) do
206
+ <<-RUBY
207
+ user "bob2", :path=>"/devloper/" do
208
+ login_profile :password_reset_required=>true
209
+
210
+ groups(
211
+ "Admin",
212
+ "SES2"
213
+ )
214
+
215
+ policy "S3" do
216
+ {"Statement"=>
217
+ [{"Action"=>
218
+ ["s3:Get*",
219
+ "s3:List*"],
220
+ "Effect"=>"Allow",
221
+ "Resource"=>"*"}]}
222
+ end
223
+ end
224
+
225
+ user "mary", :path=>"/staff/" do
226
+ policy "S3" do
227
+ {"Statement"=>
228
+ [{"Action"=>
229
+ ["s3:Get*",
230
+ "s3:List*"],
231
+ "Effect"=>"Allow",
232
+ "Resource"=>"*"}]}
233
+ end
234
+ end
235
+
236
+ group "Admin", :path=>"/admin/" do
237
+ policy "Admin" do
238
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
239
+ end
240
+ end
241
+
242
+ group "SES2", :path=>"/ses/" do
243
+ policy "ses-policy" do
244
+ {"Statement"=>
245
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
246
+ end
247
+ end
248
+ RUBY
249
+ end
250
+
251
+ subject { client }
252
+
253
+ it do
254
+ updated = apply(subject) { rename_without_renamed_from_dsl }
255
+ expect(updated).to be_truthy
256
+ expected[:users]["bob"][:groups] = ["Admin", "SES2"]
257
+ expected[:users]["bob2"] = expected[:users].delete("bob")
258
+ expected[:groups]["SES2"] = expected[:groups].delete("SES")
259
+ expect(export).to eq expected
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,434 @@
1
+ describe 'update' do
2
+ let(:dsl) do
3
+ <<-RUBY
4
+ user "bob", :path=>"/devloper/" do
5
+ login_profile :password_reset_required=>true
6
+
7
+ groups(
8
+ "Admin",
9
+ "SES"
10
+ )
11
+
12
+ policy "S3" do
13
+ {"Statement"=>
14
+ [{"Action"=>
15
+ ["s3:Get*",
16
+ "s3:List*"],
17
+ "Effect"=>"Allow",
18
+ "Resource"=>"*"}]}
19
+ end
20
+ end
21
+
22
+ user "mary", :path=>"/staff/" do
23
+ policy "S3" do
24
+ {"Statement"=>
25
+ [{"Action"=>
26
+ ["s3:Get*",
27
+ "s3:List*"],
28
+ "Effect"=>"Allow",
29
+ "Resource"=>"*"}]}
30
+ end
31
+ end
32
+
33
+ group "Admin", :path=>"/admin/" do
34
+ policy "Admin" do
35
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
36
+ end
37
+ end
38
+
39
+ group "SES", :path=>"/ses/" do
40
+ policy "ses-policy" do
41
+ {"Statement"=>
42
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
43
+ end
44
+ end
45
+ RUBY
46
+ end
47
+
48
+ let(:expected) do
49
+ {:users=>
50
+ {"bob"=>
51
+ {:path=>"/devloper/",
52
+ :groups=>["Admin", "SES"],
53
+ :policies=>
54
+ {"S3"=>
55
+ {"Statement"=>
56
+ [{"Action"=>["s3:Get*", "s3:List*"],
57
+ "Effect"=>"Allow",
58
+ "Resource"=>"*"}]}},
59
+ :login_profile=>{:password_reset_required=>true}},
60
+ "mary"=>
61
+ {:path=>"/staff/",
62
+ :groups=>[],
63
+ :policies=>
64
+ {"S3"=>
65
+ {"Statement"=>
66
+ [{"Action"=>["s3:Get*", "s3:List*"],
67
+ "Effect"=>"Allow",
68
+ "Resource"=>"*"}]}}}},
69
+ :groups=>
70
+ {"Admin"=>
71
+ {:path=>"/admin/",
72
+ :policies=>
73
+ {"Admin"=>
74
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}}},
75
+ "SES"=>
76
+ {:path=>"/ses/",
77
+ :policies=>
78
+ {"ses-policy"=>
79
+ {"Statement"=>
80
+ [{"Effect"=>"Allow",
81
+ "Action"=>"ses:SendRawEmail",
82
+ "Resource"=>"*"}]}}}}}
83
+ end
84
+
85
+ before(:each) do
86
+ apply { dsl }
87
+ end
88
+
89
+ context 'when no change' do
90
+ subject { client }
91
+
92
+ it do
93
+ updated = apply(subject) { dsl }
94
+ expect(updated).to be_falsey
95
+ expect(export).to eq expected
96
+ end
97
+ end
98
+
99
+ context 'when update policy' do
100
+ let(:update_policy_dsl) do
101
+ <<-RUBY
102
+ user "bob", :path=>"/devloper/" do
103
+ login_profile :password_reset_required=>true
104
+
105
+ groups(
106
+ "Admin",
107
+ "SES"
108
+ )
109
+
110
+ policy "S3" do
111
+ {"Statement"=>
112
+ [{"Action"=>
113
+ ["s3:Get*",
114
+ "s3:List*"],
115
+ "Effect"=>"Allow",
116
+ "Resource"=>"*"}]}
117
+ end
118
+ end
119
+
120
+ user "mary", :path=>"/staff/" do
121
+ policy "S3" do
122
+ {"Statement"=>
123
+ [{"Action"=>
124
+ ["s3:Get*",
125
+ "s3:Put*",
126
+ "s3:List*"],
127
+ "Effect"=>"Allow",
128
+ "Resource"=>"*"}]}
129
+ end
130
+ end
131
+
132
+ group "Admin", :path=>"/admin/" do
133
+ policy "Admin" do
134
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
135
+ end
136
+ end
137
+
138
+ group "SES", :path=>"/ses/" do
139
+ policy "ses-policy" do
140
+ {"Statement"=>
141
+ [{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
142
+ end
143
+ end
144
+ RUBY
145
+ end
146
+
147
+ subject { client }
148
+
149
+ it do
150
+ updated = apply(subject) { update_policy_dsl }
151
+ expect(updated).to be_truthy
152
+ expected[:users]["mary"][:policies]["S3"]["Statement"][0]["Action"] = ["s3:Get*", "s3:Put*", "s3:List*"]
153
+ expected[:groups]["SES"][:policies]["ses-policy"]["Statement"][0]["Action"] = "*"
154
+ expect(export).to eq expected
155
+ end
156
+ end
157
+
158
+ context 'when update path' do
159
+ let(:update_path_dsl) do
160
+ <<-RUBY
161
+ user "bob", :path=>"/devloper/" do
162
+ login_profile :password_reset_required=>true
163
+
164
+ groups(
165
+ "Admin",
166
+ "SES"
167
+ )
168
+
169
+ policy "S3" do
170
+ {"Statement"=>
171
+ [{"Action"=>
172
+ ["s3:Get*",
173
+ "s3:List*"],
174
+ "Effect"=>"Allow",
175
+ "Resource"=>"*"}]}
176
+ end
177
+ end
178
+
179
+ user "mary", :path=>"/xstaff/" do
180
+ policy "S3" do
181
+ {"Statement"=>
182
+ [{"Action"=>
183
+ ["s3:Get*",
184
+ "s3:List*"],
185
+ "Effect"=>"Allow",
186
+ "Resource"=>"*"}]}
187
+ end
188
+ end
189
+
190
+ group "Admin", :path=>"/admin/" do
191
+ policy "Admin" do
192
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
193
+ end
194
+ end
195
+
196
+ group "SES", :path=>"/ses/ses/" do
197
+ policy "ses-policy" do
198
+ {"Statement"=>
199
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
200
+ end
201
+ end
202
+ RUBY
203
+ end
204
+
205
+ subject { client }
206
+
207
+ it do
208
+ updated = apply(subject) { update_path_dsl }
209
+ expect(updated).to be_truthy
210
+ expected[:users]["mary"][:path] = "/xstaff/"
211
+ expected[:groups]["SES"][:path] = "/ses/ses/"
212
+ expect(export).to eq expected
213
+ end
214
+ end
215
+
216
+ context 'when update groups' do
217
+ let(:update_groups_dsl) do
218
+ <<-RUBY
219
+ user "bob", :path=>"/devloper/" do
220
+ login_profile :password_reset_required=>true
221
+
222
+ groups(
223
+ "Admin"
224
+ )
225
+
226
+ policy "S3" do
227
+ {"Statement"=>
228
+ [{"Action"=>
229
+ ["s3:Get*",
230
+ "s3:List*"],
231
+ "Effect"=>"Allow",
232
+ "Resource"=>"*"}]}
233
+ end
234
+ end
235
+
236
+ user "mary", :path=>"/staff/" do
237
+ groups(
238
+ "Admin",
239
+ "SES"
240
+ )
241
+
242
+ policy "S3" do
243
+ {"Statement"=>
244
+ [{"Action"=>
245
+ ["s3:Get*",
246
+ "s3:List*"],
247
+ "Effect"=>"Allow",
248
+ "Resource"=>"*"}]}
249
+ end
250
+ end
251
+
252
+ group "Admin", :path=>"/admin/" do
253
+ policy "Admin" do
254
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
255
+ end
256
+ end
257
+
258
+ group "SES", :path=>"/ses/" do
259
+ policy "ses-policy" do
260
+ {"Statement"=>
261
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
262
+ end
263
+ end
264
+ RUBY
265
+ end
266
+
267
+ subject { client }
268
+
269
+ it do
270
+ updated = apply(subject) { update_groups_dsl }
271
+ expect(updated).to be_truthy
272
+ expected[:users]["bob"][:groups] = ["Admin"]
273
+ expected[:users]["mary"][:groups] = ["Admin", "SES"]
274
+ expect(export).to eq expected
275
+ end
276
+ end
277
+
278
+ context 'when update login_profile' do
279
+ let(:update_login_profile_dsl) do
280
+ <<-RUBY
281
+ user "bob", :path=>"/devloper/" do
282
+ login_profile :password_reset_required=>false
283
+
284
+ groups(
285
+ "Admin",
286
+ "SES"
287
+ )
288
+
289
+ policy "S3" do
290
+ {"Statement"=>
291
+ [{"Action"=>
292
+ ["s3:Get*",
293
+ "s3:List*"],
294
+ "Effect"=>"Allow",
295
+ "Resource"=>"*"}]}
296
+ end
297
+ end
298
+
299
+ user "mary", :path=>"/staff/" do
300
+ policy "S3" do
301
+ {"Statement"=>
302
+ [{"Action"=>
303
+ ["s3:Get*",
304
+ "s3:List*"],
305
+ "Effect"=>"Allow",
306
+ "Resource"=>"*"}]}
307
+ end
308
+ end
309
+
310
+ group "Admin", :path=>"/admin/" do
311
+ policy "Admin" do
312
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
313
+ end
314
+ end
315
+
316
+ group "SES", :path=>"/ses/" do
317
+ policy "ses-policy" do
318
+ {"Statement"=>
319
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
320
+ end
321
+ end
322
+ RUBY
323
+ end
324
+
325
+ subject { client }
326
+
327
+ it do
328
+ updated = apply(subject) { update_login_profile_dsl }
329
+ expect(updated).to be_truthy
330
+ expected[:users]["bob"][:login_profile][:password_reset_required] = false
331
+ expect(export).to eq expected
332
+ end
333
+ end
334
+
335
+ context 'when delete login_profile' do
336
+ let(:delete_login_profile_dsl) do
337
+ <<-RUBY
338
+ user "bob", :path=>"/devloper/" do
339
+ groups(
340
+ "Admin",
341
+ "SES"
342
+ )
343
+
344
+ policy "S3" do
345
+ {"Statement"=>
346
+ [{"Action"=>
347
+ ["s3:Get*",
348
+ "s3:List*"],
349
+ "Effect"=>"Allow",
350
+ "Resource"=>"*"}]}
351
+ end
352
+ end
353
+
354
+ user "mary", :path=>"/staff/" do
355
+ policy "S3" do
356
+ {"Statement"=>
357
+ [{"Action"=>
358
+ ["s3:Get*",
359
+ "s3:List*"],
360
+ "Effect"=>"Allow",
361
+ "Resource"=>"*"}]}
362
+ end
363
+ end
364
+
365
+ group "Admin", :path=>"/admin/" do
366
+ policy "Admin" do
367
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
368
+ end
369
+ end
370
+
371
+ group "SES", :path=>"/ses/" do
372
+ policy "ses-policy" do
373
+ {"Statement"=>
374
+ [{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
375
+ end
376
+ end
377
+ RUBY
378
+ end
379
+
380
+ subject { client }
381
+
382
+ it do
383
+ updated = apply(subject) { delete_login_profile_dsl }
384
+ expect(updated).to be_truthy
385
+ expected[:users]["bob"].delete(:login_profile)
386
+ expect(export).to eq expected
387
+ end
388
+ end
389
+
390
+ context 'when delete policy' do
391
+ let(:delete_policy_dsl) do
392
+ <<-RUBY
393
+ user "bob", :path=>"/devloper/" do
394
+ login_profile :password_reset_required=>true
395
+
396
+ groups(
397
+ "Admin",
398
+ "SES"
399
+ )
400
+ end
401
+
402
+ user "mary", :path=>"/staff/" do
403
+ policy "S3" do
404
+ {"Statement"=>
405
+ [{"Action"=>
406
+ ["s3:Get*",
407
+ "s3:List*"],
408
+ "Effect"=>"Allow",
409
+ "Resource"=>"*"}]}
410
+ end
411
+ end
412
+
413
+ group "Admin", :path=>"/admin/" do
414
+ policy "Admin" do
415
+ {"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
416
+ end
417
+ end
418
+
419
+ group "SES", :path=>"/ses/" do
420
+ end
421
+ RUBY
422
+ end
423
+
424
+ subject { client }
425
+
426
+ it do
427
+ updated = apply(subject) { delete_policy_dsl }
428
+ expect(updated).to be_truthy
429
+ expected[:users]["bob"][:policies].delete("S3")
430
+ expected[:groups]["SES"][:policies].delete("ses-policy")
431
+ expect(export).to eq expected
432
+ end
433
+ end
434
+ end
@@ -0,0 +1,84 @@
1
+ if ENV['TRAVIS']
2
+ require 'simplecov'
3
+ require 'coveralls'
4
+
5
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
6
+ SimpleCov.start do
7
+ add_filter "spec/"
8
+ end
9
+ end
10
+
11
+ require 'tempfile'
12
+ require 'miam'
13
+
14
+ Aws.config.update(
15
+ access_key_id: ENV['MIAM_TEST_ACCESS_KEY_ID'],
16
+ secret_access_key: ENV['MIAM_TEST_SECRET_ACCESS_KEY']
17
+ )
18
+
19
+ RSpec.configure do |config|
20
+ config.before(:each) do
21
+ apply { '' }
22
+ end
23
+
24
+ config.after(:all) do
25
+ apply { '' }
26
+ end
27
+ end
28
+
29
+ def client(user_options = {})
30
+ options = {
31
+ password_manager: Miam::PasswordManager.new('/dev/null'),
32
+ logger: Logger.new('/dev/null'),
33
+ no_progress: true
34
+ }
35
+
36
+ if_debug do
37
+ logger = Miam::Logger.instance
38
+ logger.set_debug(true)
39
+
40
+ options.update(
41
+ debug: true,
42
+ logger: logger,
43
+ aws_config: {
44
+ http_wire_trace: true,
45
+ logger: logger
46
+ }
47
+ )
48
+ end
49
+
50
+ options = options.merge(user_options)
51
+ Miam::Client.new(options)
52
+ end
53
+
54
+ def tempfile(content, options = {})
55
+ basename = "#{File.basename __FILE__}.#{$$}"
56
+ basename = [basename, options[:ext]] if options[:ext]
57
+
58
+ Tempfile.open(basename) do |f|
59
+ f.puts(content)
60
+ f.flush
61
+ f.rewind
62
+ yield(f)
63
+ end
64
+ end
65
+
66
+ def apply(cli = client)
67
+ tempfile(yield) do |f|
68
+ begin
69
+ cli.apply(f.path)
70
+ rescue Aws::IAM::Errors::EntityTemporarilyUnmodifiable
71
+ sleep 3
72
+ retry
73
+ end
74
+ end
75
+ end
76
+
77
+ def export(options = {})
78
+ cli = options.delete(:client) || Aws::IAM::Client.new
79
+ Miam::Exporter.export(cli, options)[0]
80
+ end
81
+
82
+ def if_debug
83
+ yield if ENV['DEBUG'] == '1'
84
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miam
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
@@ -80,6 +80,48 @@ dependencies:
80
80
  - - ~>
81
81
  - !ruby/object:Gem::Version
82
82
  version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 3.0.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-instafail
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: coveralls
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
83
125
  description: Miam is a tool to manage IAM. It defines the state of IAM using DSL,
84
126
  and updates IAM according to DSL.
85
127
  email:
@@ -90,6 +132,8 @@ extensions: []
90
132
  extra_rdoc_files: []
91
133
  files:
92
134
  - .gitignore
135
+ - .rspec
136
+ - .travis.yml
93
137
  - Gemfile
94
138
  - LICENSE.txt
95
139
  - README.md
@@ -110,6 +154,11 @@ files:
110
154
  - lib/miam/utils.rb
111
155
  - lib/miam/version.rb
112
156
  - miam.gemspec
157
+ - spec/miam/create_spec.rb
158
+ - spec/miam/delete_spec.rb
159
+ - spec/miam/rename_spec.rb
160
+ - spec/miam/update_spec.rb
161
+ - spec/spec_helper.rb
113
162
  homepage: https://github.com/winebarrel/miam
114
163
  licenses:
115
164
  - MIT
@@ -125,13 +174,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
174
  version: '0'
126
175
  required_rubygems_version: !ruby/object:Gem::Requirement
127
176
  requirements:
128
- - - '>'
177
+ - - '>='
129
178
  - !ruby/object:Gem::Version
130
- version: 1.3.1
179
+ version: '0'
131
180
  requirements: []
132
181
  rubyforge_project:
133
182
  rubygems_version: 2.4.1
134
183
  signing_key:
135
184
  specification_version: 4
136
185
  summary: Miam is a tool to manage IAM.
137
- test_files: []
186
+ test_files:
187
+ - spec/miam/create_spec.rb
188
+ - spec/miam/delete_spec.rb
189
+ - spec/miam/rename_spec.rb
190
+ - spec/miam/update_spec.rb
191
+ - spec/spec_helper.rb