metasploit_data_models 6.0.9 → 6.0.11
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 +4 -4
- data/.github/workflows/verify.yml +11 -68
- data/app/models/mdm/service.rb +60 -1
- data/app/models/mdm/service_link.rb +52 -0
- data/app/models/mdm/vuln.rb +6 -0
- data/db/migrate/20250716155919_add_resource_to_mdm_vuln.rb +5 -0
- data/db/migrate/20250717170556_add_resource_to_services.rb +5 -0
- data/db/migrate/20250718122714_create_service_links.rb +11 -0
- data/db/migrate/20250720082201_drop_service_uniqueness_index2.rb +5 -0
- data/db/migrate/20250721114306_remove_duplicate_services3.rb +17 -0
- data/lib/mdm.rb +1 -0
- data/lib/metasploit_data_models/version.rb +1 -1
- data/metasploit_data_models.gemspec +9 -0
- data/spec/app/models/mdm/service_link_spec.rb +112 -0
- data/spec/app/models/mdm/service_spec.rb +69 -9
- data/spec/app/models/mdm/vuln_spec.rb +1 -0
- data/spec/factories/mdm/service_links.rb +8 -0
- data/spec/factories/mdm/services.rb +5 -0
- metadata +52 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5c3b6ba17aa68aa354fd30e709e371bdc703e48bfab8bf1ab1e01d220c7a136
|
|
4
|
+
data.tar.gz: cf14f60355752907e3d87333cc6d6946295745ff69ee0ca0ebd6e24afd88a77d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c800409a016366908e074694cd8f8bf22bd0112ef77c99e738b6ed97c269f319b15afda791e82969e287dcbc03e318e374b378c92be207a5261d7564ab7ff6ca
|
|
7
|
+
data.tar.gz: 34851f917756daf8fdf85018147d7178052c15a21e3177dad4730e29b199b0d9c64ac7177118e82bdc37fbb00a8bfdbef7ffddb22dd6610caa7d7b8ff1dab7a9
|
|
@@ -25,71 +25,14 @@ on:
|
|
|
25
25
|
- '*'
|
|
26
26
|
|
|
27
27
|
jobs:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
options: >-
|
|
40
|
-
--health-cmd pg_isready
|
|
41
|
-
--health-interval 10s
|
|
42
|
-
--health-timeout 5s
|
|
43
|
-
--health-retries 5
|
|
44
|
-
|
|
45
|
-
strategy:
|
|
46
|
-
fail-fast: true
|
|
47
|
-
matrix:
|
|
48
|
-
ruby:
|
|
49
|
-
- '2.7'
|
|
50
|
-
- '3.0'
|
|
51
|
-
- '3.1'
|
|
52
|
-
- '3.2'
|
|
53
|
-
rails:
|
|
54
|
-
- '~> 7.0.0'
|
|
55
|
-
- '~> 7.1.0'
|
|
56
|
-
os:
|
|
57
|
-
- ubuntu-22.04
|
|
58
|
-
- ubuntu-latest
|
|
59
|
-
exclude:
|
|
60
|
-
- { os: ubuntu-latest, ruby: '2.7' }
|
|
61
|
-
- { os: ubuntu-latest, ruby: '3.0' }
|
|
62
|
-
|
|
63
|
-
env:
|
|
64
|
-
RAILS_ENV: test
|
|
65
|
-
|
|
66
|
-
name: ${{ matrix.os }} - Ruby ${{ matrix.ruby }} - Rails ${{ matrix.rails }}
|
|
67
|
-
steps:
|
|
68
|
-
- name: Install system dependencies
|
|
69
|
-
run: sudo apt-get install libpcap-dev graphviz
|
|
70
|
-
|
|
71
|
-
- name: Checkout code
|
|
72
|
-
uses: actions/checkout@v4
|
|
73
|
-
|
|
74
|
-
- name: Setup Ruby
|
|
75
|
-
uses: ruby/setup-ruby@v1
|
|
76
|
-
with:
|
|
77
|
-
ruby-version: ${{ matrix.ruby }}
|
|
78
|
-
bundler-cache: true
|
|
79
|
-
|
|
80
|
-
- name: Update Rails version
|
|
81
|
-
run: |
|
|
82
|
-
ruby -pi.bak -e "gsub(/gem ['\"]rails['\"],\s*['\"].+['\"]?/, \"gem 'rails', '${{ matrix.rails }}'\")" Gemfile
|
|
83
|
-
bundle update
|
|
84
|
-
bundle install
|
|
85
|
-
|
|
86
|
-
- name: Test
|
|
87
|
-
run: |
|
|
88
|
-
cp spec/dummy/config/database.yml.github_actions spec/dummy/config/database.yml
|
|
89
|
-
bundle exec rake --version
|
|
90
|
-
bundle exec rake db:create db:migrate
|
|
91
|
-
|
|
92
|
-
# Disabling this check because it is proving unreliable
|
|
93
|
-
# git diff --exit-code spec/dummy/db/structure.sql
|
|
94
|
-
bundle exec rake spec
|
|
95
|
-
bundle exec rake yard
|
|
28
|
+
build:
|
|
29
|
+
uses: rapid7/metasploit-framework/.github/workflows/shared_gem_verify_rails.yml@master
|
|
30
|
+
with:
|
|
31
|
+
dependencies: '["libpcap-dev", "graphviz"]'
|
|
32
|
+
test_commands: |
|
|
33
|
+
cp spec/dummy/config/database.yml.github_actions spec/dummy/config/database.yml
|
|
34
|
+
bundle exec rake --version
|
|
35
|
+
bundle exec rake db:create db:migrate
|
|
36
|
+
bundle exec rake spec
|
|
37
|
+
bundle exec rake spec
|
|
38
|
+
bundle exec rake yard
|
data/app/models/mdm/service.rb
CHANGED
|
@@ -96,6 +96,28 @@ class Mdm::Service < ApplicationRecord
|
|
|
96
96
|
dependent: :destroy,
|
|
97
97
|
inverse_of: :service
|
|
98
98
|
|
|
99
|
+
# @!attribute [rw] parent_links
|
|
100
|
+
# Links to parent services of this service.
|
|
101
|
+
#
|
|
102
|
+
# @return [Array<Mdm::ServiceLink>]
|
|
103
|
+
has_many :parent_links,
|
|
104
|
+
class_name: 'Mdm::ServiceLink',
|
|
105
|
+
foreign_key: 'child_id',
|
|
106
|
+
dependent: :destroy,
|
|
107
|
+
inverse_of: :child
|
|
108
|
+
|
|
109
|
+
# @!attribute [rw] parent_links
|
|
110
|
+
# Link to child services of this service.
|
|
111
|
+
#
|
|
112
|
+
# @return [Array<Mdm::ServiceLink>]
|
|
113
|
+
has_many :child_links,
|
|
114
|
+
class_name: 'Mdm::ServiceLink',
|
|
115
|
+
foreign_key: 'parent_id',
|
|
116
|
+
dependent: :destroy,
|
|
117
|
+
inverse_of: :parent
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
99
121
|
#
|
|
100
122
|
# through: :task_services
|
|
101
123
|
#
|
|
@@ -128,6 +150,27 @@ class Mdm::Service < ApplicationRecord
|
|
|
128
150
|
# @return [Array<Mdm::WebVuln>]
|
|
129
151
|
has_many :web_vulns, :through => :web_sites, :class_name => 'Mdm::WebVuln'
|
|
130
152
|
|
|
153
|
+
#
|
|
154
|
+
# through: :parent_links
|
|
155
|
+
#
|
|
156
|
+
|
|
157
|
+
# @!attribute [rw] parents
|
|
158
|
+
# Parent services of this service.
|
|
159
|
+
#
|
|
160
|
+
# @return [Array<Mdm::Service>]
|
|
161
|
+
has_many :parents, through: :parent_links, source: :parent
|
|
162
|
+
|
|
163
|
+
#
|
|
164
|
+
# through: :child_links
|
|
165
|
+
#
|
|
166
|
+
|
|
167
|
+
# @!attribute [rw] children
|
|
168
|
+
# Child services of this service.
|
|
169
|
+
#
|
|
170
|
+
# @return [Array<Mdm::Service>]
|
|
171
|
+
has_many :children, through: :child_links, source: :child
|
|
172
|
+
|
|
173
|
+
|
|
131
174
|
#
|
|
132
175
|
# Attributes
|
|
133
176
|
#
|
|
@@ -157,6 +200,11 @@ class Mdm::Service < ApplicationRecord
|
|
|
157
200
|
#
|
|
158
201
|
# @return [String] element of {STATES}.
|
|
159
202
|
|
|
203
|
+
# @!attribute [rw] resource
|
|
204
|
+
# Additional resource information about the service, such as a URL or path.
|
|
205
|
+
#
|
|
206
|
+
# @return [JSONB]
|
|
207
|
+
|
|
160
208
|
#
|
|
161
209
|
# Callbacks
|
|
162
210
|
#
|
|
@@ -227,7 +275,9 @@ class Mdm::Service < ApplicationRecord
|
|
|
227
275
|
message: 'already exists on this host and protocol',
|
|
228
276
|
scope: [
|
|
229
277
|
:host_id,
|
|
230
|
-
:proto
|
|
278
|
+
:proto,
|
|
279
|
+
:name,
|
|
280
|
+
:resource
|
|
231
281
|
]
|
|
232
282
|
}
|
|
233
283
|
validates :proto,
|
|
@@ -263,5 +313,14 @@ class Mdm::Service < ApplicationRecord
|
|
|
263
313
|
end
|
|
264
314
|
end
|
|
265
315
|
|
|
316
|
+
# Destroy this service if it does not have parents {#service_links}
|
|
317
|
+
#
|
|
318
|
+
# @return [void]
|
|
319
|
+
def destroy_if_orphaned
|
|
320
|
+
self.class.transaction do
|
|
321
|
+
destroy if parents.count == 0
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
266
325
|
Metasploit::Concern.run(self)
|
|
267
326
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Join model between {Mdm::Service} and {Mdm::Service} for many-to-many self-referencing relationship
|
|
2
|
+
class Mdm::ServiceLink < ApplicationRecord
|
|
3
|
+
self.table_name = 'service_links'
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Associations
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
# Parent service
|
|
10
|
+
belongs_to :parent,
|
|
11
|
+
class_name: 'Mdm::Service',
|
|
12
|
+
inverse_of: :child_links
|
|
13
|
+
|
|
14
|
+
# Child service
|
|
15
|
+
belongs_to :child,
|
|
16
|
+
class_name: 'Mdm::Service',
|
|
17
|
+
inverse_of: :parent_links
|
|
18
|
+
|
|
19
|
+
# Destroy orphaned child when destroying a service link
|
|
20
|
+
after_destroy :destroy_orphan_child
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Attributes
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
# @!attribute created_at
|
|
27
|
+
# When this task service was created.
|
|
28
|
+
#
|
|
29
|
+
# @return [DateTime]
|
|
30
|
+
|
|
31
|
+
# @!attribute updated_at
|
|
32
|
+
# The last time this task service was updated.
|
|
33
|
+
#
|
|
34
|
+
# @return [DateTime]
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Validations
|
|
38
|
+
#
|
|
39
|
+
|
|
40
|
+
validates :parent_id,
|
|
41
|
+
:uniqueness => {
|
|
42
|
+
:scope => :child_id
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def destroy_orphan_child
|
|
46
|
+
Mdm::Service.where(id: child.id).first&.destroy_if_orphaned
|
|
47
|
+
end
|
|
48
|
+
private :destroy_orphan_child
|
|
49
|
+
|
|
50
|
+
Metasploit::Concern.run(self)
|
|
51
|
+
end
|
|
52
|
+
|
data/app/models/mdm/vuln.rb
CHANGED
|
@@ -160,6 +160,12 @@ class Mdm::Vuln < ApplicationRecord
|
|
|
160
160
|
#
|
|
161
161
|
# @return [Integer]
|
|
162
162
|
|
|
163
|
+
# @!attribute [rw] resource
|
|
164
|
+
# The resource that this vulnerability is associated with.
|
|
165
|
+
# It is stored as a JSONB object.
|
|
166
|
+
#
|
|
167
|
+
# @return [JSONB]
|
|
168
|
+
|
|
163
169
|
#
|
|
164
170
|
# Callbacks
|
|
165
171
|
#
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class CreateServiceLinks < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :service_links do |t|
|
|
4
|
+
t.references :parent, null: false, foreign_key: { to_table: :services }
|
|
5
|
+
t.references :child, null: false, foreign_key: { to_table: :services }
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
add_index :service_links, [:parent_id, :child_id], unique: true
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class RemoveDuplicateServices3 < ActiveRecord::Migration[7.0]
|
|
2
|
+
def change
|
|
3
|
+
select_mgr = Mdm::Service.arel_table.project(
|
|
4
|
+
Mdm::Service[:host_id],
|
|
5
|
+
Mdm::Service[:proto],
|
|
6
|
+
Mdm::Service[:port].count
|
|
7
|
+
).group(
|
|
8
|
+
'host_id',
|
|
9
|
+
'port',
|
|
10
|
+
'proto'
|
|
11
|
+
).having(Mdm::Service[:port].count.gt(1))
|
|
12
|
+
|
|
13
|
+
Mdm::Service.find_by_sql(select_mgr).each(&:destroy)
|
|
14
|
+
|
|
15
|
+
add_index :services, [:host_id, :port, :proto, :name, :resource], unique: true, name: 'index_services_on_5_columns'
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/mdm.rb
CHANGED
|
@@ -46,6 +46,15 @@ Gem::Specification.new do |s|
|
|
|
46
46
|
# arel-helpers: Useful tools to help construct database queries with ActiveRecord and Arel.
|
|
47
47
|
s.add_runtime_dependency 'arel-helpers'
|
|
48
48
|
|
|
49
|
+
# Standard libraries: https://www.ruby-lang.org/en/news/2023/12/25/ruby-3-3-0-released/
|
|
50
|
+
%w[
|
|
51
|
+
bigdecimal
|
|
52
|
+
drb
|
|
53
|
+
mutex_m
|
|
54
|
+
].each do |library|
|
|
55
|
+
s.add_runtime_dependency library
|
|
56
|
+
end
|
|
57
|
+
|
|
49
58
|
if RUBY_PLATFORM =~ /java/
|
|
50
59
|
# markdown formatting for yard
|
|
51
60
|
s.add_development_dependency 'kramdown'
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
RSpec.describe Mdm::ServiceLink, type: :model do
|
|
2
|
+
it_should_behave_like 'Metasploit::Concern.run'
|
|
3
|
+
|
|
4
|
+
context 'factory' do
|
|
5
|
+
it 'should be valid' do
|
|
6
|
+
service_link = FactoryBot.build(:mdm_service_link)
|
|
7
|
+
expect(service_link).to be_valid
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context 'database' do
|
|
12
|
+
|
|
13
|
+
context 'timestamps'do
|
|
14
|
+
it { is_expected.to have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
|
|
15
|
+
it { is_expected.to have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'columns' do
|
|
19
|
+
it { is_expected.to have_db_column(:parent_id).of_type(:integer).with_options(:null => false) }
|
|
20
|
+
it { is_expected.to have_db_column(:child_id).of_type(:integer).with_options(:null => false) }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context '#destroy' do
|
|
25
|
+
it 'should successfully destroy one Mdm::ServiceLink' do
|
|
26
|
+
service_link = FactoryBot.create(:mdm_service_link)
|
|
27
|
+
expect { service_link.destroy }.to_not raise_error
|
|
28
|
+
expect { service_link.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context 'with one parent and one child' do
|
|
32
|
+
let(:parent_service1) { FactoryBot.create(:mdm_service, name: 'parent_service1') }
|
|
33
|
+
let(:child_service1) { FactoryBot.create(:mdm_service, name: 'child_service1') }
|
|
34
|
+
let!(:service_link1) { FactoryBot.create(:mdm_service_link, parent: parent_service1, child: child_service1) }
|
|
35
|
+
|
|
36
|
+
it 'should only destroy the child service' do
|
|
37
|
+
expect { service_link1.destroy }.to_not raise_error
|
|
38
|
+
expect { service_link1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
39
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
40
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'with multiple children' do
|
|
44
|
+
let(:child_service2) { FactoryBot.create(:mdm_service, name: 'child_service2') }
|
|
45
|
+
let!(:service_link2) { FactoryBot.create(:mdm_service_link, parent: parent_service1, child: child_service2) }
|
|
46
|
+
|
|
47
|
+
it 'should only destroy the child service related to this service link' do
|
|
48
|
+
expect { service_link1.destroy }.to_not raise_error
|
|
49
|
+
expect { service_link1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
50
|
+
expect { service_link2.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
51
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
52
|
+
expect { child_service2.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
53
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'with multiple nested children' do
|
|
58
|
+
let(:child_service2) { FactoryBot.create(:mdm_service, name: 'child_service2') }
|
|
59
|
+
let!(:service_link2) { FactoryBot.create(:mdm_service_link, parent: child_service1, child: child_service2) }
|
|
60
|
+
|
|
61
|
+
it 'should only destroy the nested child services and service links' do
|
|
62
|
+
expect { service_link1.destroy }.to_not raise_error
|
|
63
|
+
expect { service_link1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
64
|
+
expect { service_link2.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
65
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
66
|
+
expect { child_service2.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
67
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context 'with a child that has another parent' do
|
|
72
|
+
let(:parent_service2) { FactoryBot.create(:mdm_service, name: 'parent_service2') }
|
|
73
|
+
let!(:service_link2) { FactoryBot.create(:mdm_service_link, parent: parent_service2, child: child_service1) }
|
|
74
|
+
|
|
75
|
+
it 'should not destroy the child' do
|
|
76
|
+
expect { service_link1.destroy }.to_not raise_error
|
|
77
|
+
expect { service_link1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
78
|
+
expect { service_link2.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
79
|
+
expect { child_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
80
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
81
|
+
expect { parent_service2.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "Associations" do
|
|
88
|
+
it { is_expected.to belong_to(:parent).class_name('Mdm::Service') }
|
|
89
|
+
it { is_expected.to belong_to(:child).class_name('Mdm::Service') }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "validations" do
|
|
93
|
+
it "should not allow duplicate associations" do
|
|
94
|
+
parent_service = FactoryBot.build(:mdm_service)
|
|
95
|
+
child_service = FactoryBot.build(:mdm_service)
|
|
96
|
+
FactoryBot.create(:mdm_service_link, :parent => parent_service, :child => child_service)
|
|
97
|
+
service_link2 = FactoryBot.build(:mdm_service_link, :parent => parent_service, :child => child_service)
|
|
98
|
+
expect(service_link2).not_to be_valid
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context 'callbacks' do
|
|
103
|
+
context 'before_destroy' do
|
|
104
|
+
it 'should call #destroy_orphan_child' do
|
|
105
|
+
service_link = FactoryBot.create(:mdm_service_link)
|
|
106
|
+
expect(service_link).to receive(:destroy_orphan_child)
|
|
107
|
+
service_link.destroy
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
@@ -35,6 +35,10 @@ RSpec.describe Mdm::Service, type: :model do
|
|
|
35
35
|
it { is_expected.to have_many(:web_pages).class_name('Mdm::WebPage').through(:web_sites) }
|
|
36
36
|
it { is_expected.to have_many(:web_forms).class_name('Mdm::WebForm').through(:web_sites) }
|
|
37
37
|
it { is_expected.to have_many(:web_vulns).class_name('Mdm::WebVuln').through(:web_sites) }
|
|
38
|
+
it { is_expected.to have_many(:parent_links).class_name('Mdm::ServiceLink').dependent(:destroy) }
|
|
39
|
+
it { is_expected.to have_many(:parents).class_name('Mdm::Service').through(:parent_links) }
|
|
40
|
+
it { is_expected.to have_many(:child_links).class_name('Mdm::ServiceLink').dependent(:destroy) }
|
|
41
|
+
it { is_expected.to have_many(:children).class_name('Mdm::Service').through(:child_links) }
|
|
38
42
|
it { is_expected.to belong_to(:host).class_name('Mdm::Host') }
|
|
39
43
|
end
|
|
40
44
|
|
|
@@ -114,14 +118,70 @@ RSpec.describe Mdm::Service, type: :model do
|
|
|
114
118
|
end
|
|
115
119
|
|
|
116
120
|
context '#destroy' do
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
let(:service) { FactoryBot.create(:mdm_service) }
|
|
122
|
+
|
|
123
|
+
it 'should successfully destroy one Mdm::Service' do
|
|
124
|
+
expect { service.destroy }.to_not raise_error
|
|
125
|
+
expect { service.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context 'with one parent and one child' do
|
|
129
|
+
let(:parent_service1) { FactoryBot.create(:mdm_service, name: 'parent_service1') }
|
|
130
|
+
let(:child_service1) { FactoryBot.create(:mdm_service, name: 'child_service1') }
|
|
131
|
+
|
|
132
|
+
before :example do
|
|
133
|
+
service.parents << parent_service1
|
|
134
|
+
service.children << child_service1
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'should only destroy the child service' do
|
|
138
|
+
expect { service.destroy }.to_not raise_error
|
|
139
|
+
expect { service.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
140
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
141
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
context 'with multiple children' do
|
|
145
|
+
let(:child_service2) { FactoryBot.create(:mdm_service, name: 'child_service2') }
|
|
146
|
+
|
|
147
|
+
it 'should all the child services' do
|
|
148
|
+
service.children << child_service2
|
|
149
|
+
|
|
150
|
+
expect { service.destroy }.to_not raise_error
|
|
151
|
+
expect { service.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
152
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
153
|
+
expect { child_service2.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
154
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
context 'with multiple nested children' do
|
|
159
|
+
let(:child_service2) { FactoryBot.create(:mdm_service, name: 'child_service2') }
|
|
160
|
+
|
|
161
|
+
it 'should all the nested child services' do
|
|
162
|
+
child_service1.children << child_service2
|
|
163
|
+
|
|
164
|
+
expect { service.destroy }.to_not raise_error
|
|
165
|
+
expect { service.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
166
|
+
expect { child_service1.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
167
|
+
expect { child_service2.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
168
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
context 'with a child that has another parent' do
|
|
173
|
+
let(:parent_service2) { FactoryBot.create(:mdm_service, name: 'parent_service2') }
|
|
174
|
+
|
|
175
|
+
it 'should not destroy the child' do
|
|
176
|
+
child_service1.parents << parent_service2
|
|
177
|
+
|
|
178
|
+
expect { service.destroy }.to_not raise_error
|
|
179
|
+
expect { service.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
180
|
+
expect { child_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
181
|
+
expect { parent_service1.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
182
|
+
expect { parent_service2.reload }.to_not raise_error(ActiveRecord::RecordNotFound)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
125
185
|
end
|
|
126
186
|
end
|
|
127
187
|
|
|
@@ -222,7 +282,7 @@ RSpec.describe Mdm::Service, type: :model do
|
|
|
222
282
|
|
|
223
283
|
context 'when a duplicate service already exists' do
|
|
224
284
|
let(:service1) { FactoryBot.create(:mdm_service)}
|
|
225
|
-
let(:service2) { FactoryBot.build(:mdm_service, :host => service1.host, :port => service1.port, :proto => service1.proto )}
|
|
285
|
+
let(:service2) { FactoryBot.build(:mdm_service, :host => service1.host, :port => service1.port, :proto => service1.proto, :resource => service1.resource, :name => service1.name) }
|
|
226
286
|
it 'is not valid' do
|
|
227
287
|
expect(service2).to_not be_valid
|
|
228
288
|
end
|
|
@@ -133,6 +133,7 @@ RSpec.describe Mdm::Vuln, type: :model do
|
|
|
133
133
|
it { is_expected.to have_db_column(:origin_id).of_type(:integer) }
|
|
134
134
|
it { is_expected.to have_db_column(:origin_type).of_type(:string) }
|
|
135
135
|
it { is_expected.to have_db_column(:service_id).of_type(:integer) }
|
|
136
|
+
it { is_expected.to have_db_column(:resource).of_type(:jsonb) }
|
|
136
137
|
|
|
137
138
|
context 'counter caches' do
|
|
138
139
|
it { is_expected.to have_db_column(:vuln_attempt_count).of_type(:integer).with_options(:default => 0) }
|
|
@@ -12,6 +12,7 @@ FactoryBot.define do
|
|
|
12
12
|
port { generate :port }
|
|
13
13
|
proto { generate :mdm_service_proto }
|
|
14
14
|
state { 'open' }
|
|
15
|
+
resource { generate :mdm_service_resource }
|
|
15
16
|
|
|
16
17
|
factory :web_service do
|
|
17
18
|
proto { 'tcp' }
|
|
@@ -23,6 +24,10 @@ FactoryBot.define do
|
|
|
23
24
|
"mdm_service_name#{n}"
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
sequence(:mdm_service_resource) { |n|
|
|
28
|
+
{ "mdm_service_resource#{n}".to_sym => "mdm_service_resource_value#{n}" }
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
sequence :mdm_service_proto, Mdm::Service::PROTOS.cycle
|
|
27
32
|
|
|
28
33
|
port_bits = 16
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metasploit_data_models
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Metasploit Hackers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: metasploit-yard
|
|
@@ -206,6 +206,48 @@ dependencies:
|
|
|
206
206
|
- - ">="
|
|
207
207
|
- !ruby/object:Gem::Version
|
|
208
208
|
version: '0'
|
|
209
|
+
- !ruby/object:Gem::Dependency
|
|
210
|
+
name: bigdecimal
|
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
|
212
|
+
requirements:
|
|
213
|
+
- - ">="
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '0'
|
|
216
|
+
type: :runtime
|
|
217
|
+
prerelease: false
|
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
+
requirements:
|
|
220
|
+
- - ">="
|
|
221
|
+
- !ruby/object:Gem::Version
|
|
222
|
+
version: '0'
|
|
223
|
+
- !ruby/object:Gem::Dependency
|
|
224
|
+
name: drb
|
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
|
226
|
+
requirements:
|
|
227
|
+
- - ">="
|
|
228
|
+
- !ruby/object:Gem::Version
|
|
229
|
+
version: '0'
|
|
230
|
+
type: :runtime
|
|
231
|
+
prerelease: false
|
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
233
|
+
requirements:
|
|
234
|
+
- - ">="
|
|
235
|
+
- !ruby/object:Gem::Version
|
|
236
|
+
version: '0'
|
|
237
|
+
- !ruby/object:Gem::Dependency
|
|
238
|
+
name: mutex_m
|
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
|
240
|
+
requirements:
|
|
241
|
+
- - ">="
|
|
242
|
+
- !ruby/object:Gem::Version
|
|
243
|
+
version: '0'
|
|
244
|
+
type: :runtime
|
|
245
|
+
prerelease: false
|
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
247
|
+
requirements:
|
|
248
|
+
- - ">="
|
|
249
|
+
- !ruby/object:Gem::Version
|
|
250
|
+
version: '0'
|
|
209
251
|
- !ruby/object:Gem::Dependency
|
|
210
252
|
name: redcarpet
|
|
211
253
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -284,6 +326,7 @@ files:
|
|
|
284
326
|
- app/models/mdm/ref.rb
|
|
285
327
|
- app/models/mdm/route.rb
|
|
286
328
|
- app/models/mdm/service.rb
|
|
329
|
+
- app/models/mdm/service_link.rb
|
|
287
330
|
- app/models/mdm/session.rb
|
|
288
331
|
- app/models/mdm/session_event.rb
|
|
289
332
|
- app/models/mdm/tag.rb
|
|
@@ -466,6 +509,11 @@ files:
|
|
|
466
509
|
- db/migrate/20180904120211_create_payloads.rb
|
|
467
510
|
- db/migrate/20190308134512_create_async_callbacks.rb
|
|
468
511
|
- db/migrate/20190507120211_remove_payload_workspaces.rb
|
|
512
|
+
- db/migrate/20250716155919_add_resource_to_mdm_vuln.rb
|
|
513
|
+
- db/migrate/20250717170556_add_resource_to_services.rb
|
|
514
|
+
- db/migrate/20250718122714_create_service_links.rb
|
|
515
|
+
- db/migrate/20250720082201_drop_service_uniqueness_index2.rb
|
|
516
|
+
- db/migrate/20250721114306_remove_duplicate_services3.rb
|
|
469
517
|
- lib/mdm.rb
|
|
470
518
|
- lib/mdm/host/operating_system_normalization.rb
|
|
471
519
|
- lib/mdm/module.rb
|
|
@@ -521,6 +569,7 @@ files:
|
|
|
521
569
|
- spec/app/models/mdm/profile_spec.rb
|
|
522
570
|
- spec/app/models/mdm/ref_spec.rb
|
|
523
571
|
- spec/app/models/mdm/route_spec.rb
|
|
572
|
+
- spec/app/models/mdm/service_link_spec.rb
|
|
524
573
|
- spec/app/models/mdm/service_spec.rb
|
|
525
574
|
- spec/app/models/mdm/session_event_spec.rb
|
|
526
575
|
- spec/app/models/mdm/session_spec.rb
|
|
@@ -639,6 +688,7 @@ files:
|
|
|
639
688
|
- spec/factories/mdm/payloads.rb
|
|
640
689
|
- spec/factories/mdm/refs.rb
|
|
641
690
|
- spec/factories/mdm/routes.rb
|
|
691
|
+
- spec/factories/mdm/service_links.rb
|
|
642
692
|
- spec/factories/mdm/services.rb
|
|
643
693
|
- spec/factories/mdm/session_events.rb
|
|
644
694
|
- spec/factories/mdm/sessions.rb
|