metasploit-credential 0.14.5 → 0.14.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/metasploit/credential/exporter/core.rb +2 -2
- data/lib/metasploit/credential/exporter/pwdump.rb +2 -2
- data/lib/metasploit/credential/migrator.rb +1 -1
- data/lib/metasploit/credential/version.rb +1 -3
- data/spec/dummy/config/database.yml +13 -11
- data/spec/dummy/db/structure.sql +1 -0
- data/spec/lib/metasploit/credential/creation_spec.rb +6 -8
- data/spec/lib/metasploit/credential/exporter/core_spec.rb +100 -85
- data/spec/lib/metasploit/credential/exporter/pwdump_spec.rb +14 -16
- data/spec/lib/metasploit/credential/importer/core_spec.rb +10 -12
- data/spec/lib/metasploit/credential/importer/multi_spec.rb +4 -6
- data/spec/lib/metasploit/credential/importer/pwdump_spec.rb +11 -13
- data/spec/lib/metasploit/credential/importer/zip_spec.rb +5 -7
- data/spec/lib/metasploit/credential/migrator_spec.rb +13 -13
- data/spec/lib/metasploit/credential/version_spec.rb +3 -5
- data/spec/lib/metasploit/credential_spec.rb +1 -3
- data/spec/models/mdm/service_spec.rb +3 -5
- data/spec/models/mdm/session_spec.rb +2 -4
- data/spec/models/mdm/task_spec.rb +4 -6
- data/spec/models/mdm/user_spec.rb +2 -4
- data/spec/models/mdm/workspace_spec.rb +2 -4
- data/spec/models/metasploit/credential/blank_username_spec.rb +5 -7
- data/spec/models/metasploit/credential/core_spec.rb +43 -45
- data/spec/models/metasploit/credential/login/status_spec.rb +19 -21
- data/spec/models/metasploit/credential/login_spec.rb +36 -38
- data/spec/models/metasploit/credential/nonreplayable_hash_spec.rb +3 -5
- data/spec/models/metasploit/credential/ntlm_hash_spec.rb +13 -15
- data/spec/models/metasploit/credential/origin/cracked_password_spec.rb +5 -7
- data/spec/models/metasploit/credential/origin/import_spec.rb +8 -10
- data/spec/models/metasploit/credential/origin/manual_spec.rb +7 -9
- data/spec/models/metasploit/credential/origin/service_spec.rb +10 -12
- data/spec/models/metasploit/credential/origin/session_spec.rb +11 -13
- data/spec/models/metasploit/credential/password_hash_spec.rb +4 -6
- data/spec/models/metasploit/credential/password_spec.rb +3 -5
- data/spec/models/metasploit/credential/postgres_md5_spec.rb +4 -6
- data/spec/models/metasploit/credential/private_spec.rb +8 -10
- data/spec/models/metasploit/credential/public_spec.rb +5 -7
- data/spec/models/metasploit/credential/realm_spec.rb +14 -16
- data/spec/models/metasploit/credential/replayable_hash_spec.rb +3 -5
- data/spec/models/metasploit/credential/ssh_key_spec.rb +15 -17
- data/spec/models/metasploit/credential/username_spec.rb +6 -8
- data/spec/models/metasploit_data_models/search/visitor/relation_spec.rb +1 -3
- data/spec/spec_helper.rb +83 -18
- data/spec/support/shared/contexts/mdm/workspace.rb +1 -1
- data/spec/support/shared/examples/core_validations.rb +117 -42
- data/spec/support/shared/examples/single_table_inheritance_database_columns.rb +2 -2
- data/spec/support/shared/examples/timestamp_database_column.rb +2 -2
- metadata +9 -9
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Login do
|
1
|
+
RSpec.describe Metasploit::Credential::Login, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
9
|
-
it {
|
5
|
+
it { is_expected.to belong_to(:core).class_name('Metasploit::Credential::Core') }
|
6
|
+
it { is_expected.to have_one(:host).class_name('Mdm::Host') }
|
7
|
+
it { is_expected.to belong_to(:service).class_name('Mdm::Service')}
|
10
8
|
end
|
11
9
|
|
12
10
|
context 'callbacks' do
|
@@ -39,7 +37,7 @@ describe Metasploit::Credential::Login do
|
|
39
37
|
''
|
40
38
|
end
|
41
39
|
|
42
|
-
it {
|
40
|
+
it { is_expected.to be_nil }
|
43
41
|
end
|
44
42
|
|
45
43
|
context 'with nil' do
|
@@ -47,7 +45,7 @@ describe Metasploit::Credential::Login do
|
|
47
45
|
nil
|
48
46
|
end
|
49
47
|
|
50
|
-
it {
|
48
|
+
it { is_expected.to be_nil }
|
51
49
|
end
|
52
50
|
|
53
51
|
context 'with present' do
|
@@ -66,21 +64,21 @@ describe Metasploit::Credential::Login do
|
|
66
64
|
|
67
65
|
context 'database' do
|
68
66
|
context 'columns' do
|
69
|
-
it {
|
70
|
-
it {
|
71
|
-
it {
|
67
|
+
it { is_expected.to have_db_column(:access_level).of_type(:string).with_options(null: true) }
|
68
|
+
it { is_expected.to have_db_column(:last_attempted_at).of_type(:datetime).with_options(null: true) }
|
69
|
+
it { is_expected.to have_db_column(:status).of_type(:string).with_options(null: false) }
|
72
70
|
|
73
71
|
it_should_behave_like 'timestamp database columns'
|
74
72
|
|
75
73
|
context 'foreign keys' do
|
76
|
-
it {
|
77
|
-
it {
|
74
|
+
it { is_expected.to have_db_column(:core_id).of_type(:integer).with_options(null: false) }
|
75
|
+
it { is_expected.to have_db_column(:service_id).of_type(:integer).with_options(null: false) }
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
81
79
|
context 'indices' do
|
82
|
-
it {
|
83
|
-
it {
|
80
|
+
it { is_expected.to have_db_index([:core_id, :service_id]).unique(true) }
|
81
|
+
it { is_expected.to have_db_index([:service_id, :core_id]).unique(true) }
|
84
82
|
end
|
85
83
|
end
|
86
84
|
|
@@ -92,7 +90,7 @@ describe Metasploit::Credential::Login do
|
|
92
90
|
FactoryGirl.build(:metasploit_credential_login)
|
93
91
|
end
|
94
92
|
|
95
|
-
it {
|
93
|
+
it { is_expected.to be_valid }
|
96
94
|
|
97
95
|
context '#status' do
|
98
96
|
subject(:metasploit_credential_login) do
|
@@ -107,7 +105,7 @@ describe Metasploit::Credential::Login do
|
|
107
105
|
Metasploit::Model::Login::Status::DENIED_ACCESS
|
108
106
|
end
|
109
107
|
|
110
|
-
it {
|
108
|
+
it { is_expected.to be_valid }
|
111
109
|
end
|
112
110
|
|
113
111
|
context 'with Metasploit::Model::Login::Status::DISABLED' do
|
@@ -115,7 +113,7 @@ describe Metasploit::Credential::Login do
|
|
115
113
|
Metasploit::Model::Login::Status::DISABLED
|
116
114
|
end
|
117
115
|
|
118
|
-
it {
|
116
|
+
it { is_expected.to be_valid }
|
119
117
|
end
|
120
118
|
|
121
119
|
context 'with Metasploit::Model::Login::Status::LOCKED_OUT' do
|
@@ -123,7 +121,7 @@ describe Metasploit::Credential::Login do
|
|
123
121
|
Metasploit::Model::Login::Status::LOCKED_OUT
|
124
122
|
end
|
125
123
|
|
126
|
-
it {
|
124
|
+
it { is_expected.to be_valid }
|
127
125
|
end
|
128
126
|
|
129
127
|
context 'with Metasploit::Model::Login::Status::SUCCESSFUL' do
|
@@ -131,7 +129,7 @@ describe Metasploit::Credential::Login do
|
|
131
129
|
Metasploit::Model::Login::Status::SUCCESSFUL
|
132
130
|
end
|
133
131
|
|
134
|
-
it {
|
132
|
+
it { is_expected.to be_valid }
|
135
133
|
end
|
136
134
|
|
137
135
|
context 'with Metasploit::Model::Login::Status::UNABLE_TO_CONNECT' do
|
@@ -139,7 +137,7 @@ describe Metasploit::Credential::Login do
|
|
139
137
|
Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
140
138
|
end
|
141
139
|
|
142
|
-
it {
|
140
|
+
it { is_expected.to be_valid }
|
143
141
|
end
|
144
142
|
|
145
143
|
context 'with Metasploit::Model::Login::Status::UNTRIED' do
|
@@ -147,21 +145,21 @@ describe Metasploit::Credential::Login do
|
|
147
145
|
Metasploit::Model::Login::Status::UNTRIED
|
148
146
|
end
|
149
147
|
|
150
|
-
it {
|
148
|
+
it { is_expected.to be_valid }
|
151
149
|
end
|
152
150
|
end
|
153
151
|
end
|
154
152
|
end
|
155
153
|
|
156
154
|
context 'mass assignment security' do
|
157
|
-
it {
|
155
|
+
it { is_expected.to allow_mass_assignment_of(:access_level) }
|
158
156
|
it { should_not allow_mass_assignment_of(:core) }
|
159
157
|
it { should_not allow_mass_assignment_of(:core_id) }
|
160
158
|
it { should_not allow_mass_assignment_of(:created_at) }
|
161
|
-
it {
|
159
|
+
it { is_expected.to allow_mass_assignment_of(:last_attempted_at) }
|
162
160
|
it { should_not allow_mass_assignment_of(:service) }
|
163
161
|
it { should_not allow_mass_assignment_of(:service_id) }
|
164
|
-
it {
|
162
|
+
it { is_expected.to allow_mass_assignment_of(:status) }
|
165
163
|
it { should_not allow_mass_assignment_of(:updated_at) }
|
166
164
|
end
|
167
165
|
|
@@ -191,7 +189,7 @@ describe Metasploit::Credential::Login do
|
|
191
189
|
end
|
192
190
|
|
193
191
|
context 'validations' do
|
194
|
-
it {
|
192
|
+
it { is_expected.to validate_presence_of :core }
|
195
193
|
|
196
194
|
context 'with existent Metasploit::Credential::Login' do
|
197
195
|
include_context 'Mdm::Workspace'
|
@@ -204,11 +202,11 @@ describe Metasploit::Credential::Login do
|
|
204
202
|
)
|
205
203
|
end
|
206
204
|
|
207
|
-
it {
|
205
|
+
it { is_expected.to validate_uniqueness_of(:core_id).scoped_to(:service_id) }
|
208
206
|
end
|
209
207
|
|
210
|
-
it {
|
211
|
-
it {
|
208
|
+
it { is_expected.to validate_presence_of :service }
|
209
|
+
it { is_expected.to ensure_inclusion_of(:status).in_array(Metasploit::Model::Login::Status::ALL) }
|
212
210
|
|
213
211
|
context '#consistent_last_attempted_at' do
|
214
212
|
include_context 'Mdm::Workspace'
|
@@ -252,7 +250,7 @@ describe Metasploit::Credential::Login do
|
|
252
250
|
DateTime.now.utc
|
253
251
|
end
|
254
252
|
|
255
|
-
it {
|
253
|
+
it { is_expected.to include(error) }
|
256
254
|
end
|
257
255
|
|
258
256
|
context 'without #last_attempted' do
|
@@ -290,7 +288,7 @@ describe Metasploit::Credential::Login do
|
|
290
288
|
nil
|
291
289
|
end
|
292
290
|
|
293
|
-
it {
|
291
|
+
it { is_expected.to include(error) }
|
294
292
|
end
|
295
293
|
end
|
296
294
|
end
|
@@ -363,7 +361,7 @@ describe Metasploit::Credential::Login do
|
|
363
361
|
FactoryGirl.build(:mdm_workspace)
|
364
362
|
end
|
365
363
|
|
366
|
-
it {
|
364
|
+
it { is_expected.to include(error) }
|
367
365
|
end
|
368
366
|
end
|
369
367
|
|
@@ -372,7 +370,7 @@ describe Metasploit::Credential::Login do
|
|
372
370
|
nil
|
373
371
|
end
|
374
372
|
|
375
|
-
it {
|
373
|
+
it { is_expected.to include(error) }
|
376
374
|
end
|
377
375
|
end
|
378
376
|
|
@@ -381,7 +379,7 @@ describe Metasploit::Credential::Login do
|
|
381
379
|
nil
|
382
380
|
end
|
383
381
|
|
384
|
-
it {
|
382
|
+
it { is_expected.to include(error) }
|
385
383
|
end
|
386
384
|
end
|
387
385
|
|
@@ -390,7 +388,7 @@ describe Metasploit::Credential::Login do
|
|
390
388
|
nil
|
391
389
|
end
|
392
390
|
|
393
|
-
it {
|
391
|
+
it { is_expected.to include(error) }
|
394
392
|
end
|
395
393
|
end
|
396
394
|
|
@@ -422,7 +420,7 @@ describe Metasploit::Credential::Login do
|
|
422
420
|
FactoryGirl.build(:mdm_workspace)
|
423
421
|
end
|
424
422
|
|
425
|
-
it {
|
423
|
+
it { is_expected.to include(error) }
|
426
424
|
end
|
427
425
|
|
428
426
|
context 'without Mdm::Host#workspace' do
|
@@ -479,7 +477,7 @@ describe Metasploit::Credential::Login do
|
|
479
477
|
FactoryGirl.build(:mdm_workspace)
|
480
478
|
end
|
481
479
|
|
482
|
-
it {
|
480
|
+
it { is_expected.to include(error) }
|
483
481
|
end
|
484
482
|
|
485
483
|
context 'without Mdm::Host#workspace' do
|
@@ -522,7 +520,7 @@ describe Metasploit::Credential::Login do
|
|
522
520
|
subject(:login){ FactoryGirl.create :metasploit_credential_login, core: core}
|
523
521
|
|
524
522
|
it 'should find the right objects' do
|
525
|
-
Metasploit::Credential::Login.in_workspace_including_hosts_and_services(service.host.workspace).
|
523
|
+
expect(Metasploit::Credential::Login.in_workspace_including_hosts_and_services(service.host.workspace)).to include(login)
|
526
524
|
end
|
527
525
|
end
|
528
526
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::NonreplayableHash do
|
1
|
+
RSpec.describe Metasploit::Credential::NonreplayableHash, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
|
-
it {
|
4
|
+
it { is_expected.to be_a Metasploit::Credential::PasswordHash }
|
7
5
|
|
8
6
|
context 'factories' do
|
9
7
|
context 'metasploit_credential_nonreplayable_hash' do
|
@@ -11,7 +9,7 @@ describe Metasploit::Credential::NonreplayableHash do
|
|
11
9
|
FactoryGirl.build(:metasploit_credential_nonreplayable_hash)
|
12
10
|
end
|
13
11
|
|
14
|
-
it {
|
12
|
+
it { is_expected.to be_valid }
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::NTLMHash do
|
1
|
+
RSpec.describe Metasploit::Credential::NTLMHash, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
|
-
it {
|
4
|
+
it { is_expected.to be_a Metasploit::Credential::ReplayableHash }
|
7
5
|
|
8
6
|
context 'CONSTANTS' do
|
9
7
|
context 'DATA_REGEXP' do
|
@@ -38,7 +36,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
38
36
|
described_class::LAN_MANAGER_MAX_CHARACTERS
|
39
37
|
end
|
40
38
|
|
41
|
-
it {
|
39
|
+
it { is_expected.to eq 14 }
|
42
40
|
end
|
43
41
|
|
44
42
|
context 'LAN_MANAGER_HEX_DIGEST_REGEXP' do
|
@@ -101,7 +99,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
101
99
|
nil
|
102
100
|
end
|
103
101
|
|
104
|
-
it {
|
102
|
+
it { is_expected.to be_nil }
|
105
103
|
end
|
106
104
|
|
107
105
|
context 'with upper case characters' do
|
@@ -133,7 +131,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
133
131
|
FactoryGirl.build(:metasploit_credential_ntlm_hash)
|
134
132
|
end
|
135
133
|
|
136
|
-
it {
|
134
|
+
it { is_expected.to be_valid }
|
137
135
|
end
|
138
136
|
end
|
139
137
|
|
@@ -191,7 +189,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
191
189
|
super().gsub(':', '')
|
192
190
|
end
|
193
191
|
|
194
|
-
it {
|
192
|
+
it { is_expected.to include(error) }
|
195
193
|
end
|
196
194
|
|
197
195
|
context 'without LAN Manager hex_digest' do
|
@@ -199,7 +197,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
199
197
|
":#{nt_lan_manager_hex_digest}"
|
200
198
|
end
|
201
199
|
|
202
|
-
it {
|
200
|
+
it { is_expected.to include(error) }
|
203
201
|
end
|
204
202
|
|
205
203
|
context 'with incorrect hash length(s)' do
|
@@ -207,7 +205,7 @@ describe Metasploit::Credential::NTLMHash do
|
|
207
205
|
"123456:abcdef"
|
208
206
|
end
|
209
207
|
|
210
|
-
it {
|
208
|
+
it { is_expected.to include(error) }
|
211
209
|
end
|
212
210
|
end
|
213
211
|
end
|
@@ -375,26 +373,26 @@ describe Metasploit::Credential::NTLMHash do
|
|
375
373
|
context 'blank_password?' do
|
376
374
|
|
377
375
|
it 'returns true if the hash is for a blank password' do
|
378
|
-
expect(blank_password_hash.blank_password?).to
|
376
|
+
expect(blank_password_hash.blank_password?).to eq(true)
|
379
377
|
end
|
380
378
|
|
381
379
|
it 'returns false if the hash is not for a blank password' do
|
382
|
-
expect(non_blank_password.blank_password?).to
|
380
|
+
expect(non_blank_password.blank_password?).to eq(false)
|
383
381
|
end
|
384
382
|
|
385
383
|
it 'returns false if the nt hash is not blank but the lm hash is' do
|
386
|
-
expect(no_lm_hash.blank_password?).to
|
384
|
+
expect(no_lm_hash.blank_password?).to eq(false)
|
387
385
|
end
|
388
386
|
end
|
389
387
|
|
390
388
|
context 'lm_hash_present?' do
|
391
389
|
|
392
390
|
it 'returns false if the lm_hash is blank' do
|
393
|
-
expect(no_lm_hash.lm_hash_present?).to
|
391
|
+
expect(no_lm_hash.lm_hash_present?).to eq(false)
|
394
392
|
end
|
395
393
|
|
396
394
|
it 'returns true if the lm_hash is not blank' do
|
397
|
-
expect(non_blank_password.lm_hash_present?).to
|
395
|
+
expect(non_blank_password.lm_hash_present?).to eq(true)
|
398
396
|
end
|
399
397
|
end
|
400
398
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::CrackedPassword do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::CrackedPassword, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:originating_core).class_name('Metasploit::Credential::Core') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
@@ -13,13 +11,13 @@ describe Metasploit::Credential::Origin::CrackedPassword do
|
|
13
11
|
it_should_behave_like 'timestamp database columns'
|
14
12
|
|
15
13
|
context 'foreign keys' do
|
16
|
-
it {
|
14
|
+
it { is_expected.to have_db_column(:metasploit_credential_core_id).of_type(:integer).with_options(null: false) }
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
18
|
context 'indices' do
|
21
19
|
context 'foreign keys' do
|
22
|
-
it {
|
20
|
+
it { is_expected.to have_db_index(:metasploit_credential_core_id) }
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -1,27 +1,25 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::Import do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::Import, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:task).class_name('Mdm::Task') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
12
10
|
context 'columns' do
|
13
|
-
it {
|
11
|
+
it { is_expected.to have_db_column(:filename).of_type(:text).with_options(null: false) }
|
14
12
|
|
15
13
|
it_should_behave_like 'timestamp database columns'
|
16
14
|
|
17
15
|
context 'foreign keys' do
|
18
|
-
it {
|
16
|
+
it { is_expected.to have_db_column(:task_id).of_type(:integer) }
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
20
|
context 'indices' do
|
23
21
|
context 'foreign keys' do
|
24
|
-
it {
|
22
|
+
it { is_expected.to have_db_index(:task_id) }
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -33,12 +31,12 @@ describe Metasploit::Credential::Origin::Import do
|
|
33
31
|
FactoryGirl.build(:metasploit_credential_origin_import)
|
34
32
|
end
|
35
33
|
|
36
|
-
it {
|
34
|
+
it { is_expected.to be_valid }
|
37
35
|
end
|
38
36
|
|
39
37
|
context 'mass assignment security' do
|
40
38
|
it { should_not allow_mass_assignment_of :created_at }
|
41
|
-
it {
|
39
|
+
it { is_expected.to allow_mass_assignment_of :filename }
|
42
40
|
it { should_not allow_mass_assignment_of :task }
|
43
41
|
it { should_not allow_mass_assignment_of :task_id }
|
44
42
|
it { should_not allow_mass_assignment_of :updated_at }
|
@@ -1,17 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe Metasploit::Credential::Origin::Manual do
|
1
|
+
RSpec.describe Metasploit::Credential::Origin::Manual, type: :model do
|
4
2
|
it_should_behave_like 'Metasploit::Concern.run'
|
5
3
|
|
6
4
|
context 'associations' do
|
7
|
-
it {
|
8
|
-
it {
|
5
|
+
it { is_expected.to have_many(:cores).class_name('Metasploit::Credential::Core').dependent(:destroy) }
|
6
|
+
it { is_expected.to belong_to(:user).class_name('Mdm::User') }
|
9
7
|
end
|
10
8
|
|
11
9
|
context 'database' do
|
12
10
|
context 'columns' do
|
13
11
|
context 'foreign keys' do
|
14
|
-
it {
|
12
|
+
it { is_expected.to have_db_column(:user_id).of_type(:integer).with_options(null: false) }
|
15
13
|
end
|
16
14
|
|
17
15
|
it_should_behave_like 'timestamp database columns'
|
@@ -19,7 +17,7 @@ describe Metasploit::Credential::Origin::Manual do
|
|
19
17
|
|
20
18
|
context 'indices' do
|
21
19
|
context 'foreign keys' do
|
22
|
-
it {
|
20
|
+
it { is_expected.to have_db_index(:user_id) }
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -30,11 +28,11 @@ describe Metasploit::Credential::Origin::Manual do
|
|
30
28
|
FactoryGirl.build(:metasploit_credential_origin_manual)
|
31
29
|
end
|
32
30
|
|
33
|
-
it {
|
31
|
+
it { is_expected.to be_valid }
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
context 'validations' do
|
38
|
-
it {
|
36
|
+
it { is_expected.to validate_presence_of :user }
|
39
37
|
end
|
40
38
|
end
|