moose-inventory 1.0.8 → 2.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.
Files changed (104) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +49 -0
  3. data/.github/workflows/release.yml +58 -0
  4. data/.gitignore +1 -1
  5. data/.gitleaks.toml +9 -0
  6. data/.rubocop.yml +19 -784
  7. data/BACKLOG.md +290 -0
  8. data/Gemfile.lock +95 -0
  9. data/README.md +38 -9
  10. data/Rakefile +1 -1
  11. data/bin/moose-inventory +1 -1
  12. data/docs/release/publishing.md +109 -0
  13. data/docs/release/release-readiness.md +55 -0
  14. data/docs/security-audit-2026-05-21.md +71 -0
  15. data/docs/security-audit-2026-05-26-rerun.md +75 -0
  16. data/docs/security-audit-2026-05-26.md +63 -0
  17. data/lib/moose_inventory/cli/formatter.rb +16 -17
  18. data/lib/moose_inventory/cli/group.rb +4 -1
  19. data/lib/moose_inventory/cli/group_add.rb +89 -75
  20. data/lib/moose_inventory/cli/group_addchild.rb +84 -71
  21. data/lib/moose_inventory/cli/group_addhost.rb +78 -69
  22. data/lib/moose_inventory/cli/group_addvar.rb +37 -37
  23. data/lib/moose_inventory/cli/group_get.rb +23 -26
  24. data/lib/moose_inventory/cli/group_list.rb +12 -15
  25. data/lib/moose_inventory/cli/group_listvars.rb +12 -14
  26. data/lib/moose_inventory/cli/group_rm.rb +104 -76
  27. data/lib/moose_inventory/cli/group_rmchild.rb +99 -54
  28. data/lib/moose_inventory/cli/group_rmhost.rb +64 -60
  29. data/lib/moose_inventory/cli/group_rmvar.rb +5 -5
  30. data/lib/moose_inventory/cli/helpers.rb +76 -0
  31. data/lib/moose_inventory/cli/host.rb +4 -1
  32. data/lib/moose_inventory/cli/host_add.rb +51 -66
  33. data/lib/moose_inventory/cli/host_addgroup.rb +77 -68
  34. data/lib/moose_inventory/cli/host_addvar.rb +6 -6
  35. data/lib/moose_inventory/cli/host_get.rb +15 -18
  36. data/lib/moose_inventory/cli/host_list.rb +3 -3
  37. data/lib/moose_inventory/cli/host_listvars.rb +21 -23
  38. data/lib/moose_inventory/cli/host_rm.rb +9 -9
  39. data/lib/moose_inventory/cli/host_rmgroup.rb +63 -60
  40. data/lib/moose_inventory/cli/host_rmvar.rb +3 -3
  41. data/lib/moose_inventory/config/config.rb +43 -40
  42. data/lib/moose_inventory/db/db.rb +92 -52
  43. data/lib/moose_inventory/db/models.rb +11 -12
  44. data/lib/moose_inventory/inventory_context.rb +50 -0
  45. data/lib/moose_inventory/operations/add_associations.rb +127 -0
  46. data/lib/moose_inventory/operations/add_groups.rb +115 -0
  47. data/lib/moose_inventory/operations/add_hosts.rb +110 -0
  48. data/lib/moose_inventory/operations/group_child_relations.rb +118 -0
  49. data/lib/moose_inventory/operations/group_cleanup.rb +55 -0
  50. data/lib/moose_inventory/operations/remove_associations.rb +101 -0
  51. data/lib/moose_inventory/operations/remove_groups.rb +79 -0
  52. data/lib/moose_inventory/version.rb +1 -1
  53. data/moose-inventory.gemspec +38 -20
  54. data/scripts/check.sh +10 -0
  55. data/scripts/ci/check_permissions.sh +35 -0
  56. data/scripts/ci/check_rubocop.sh +28 -0
  57. data/scripts/ci/check_secrets.sh +26 -0
  58. data/scripts/ci/check_security.sh +68 -0
  59. data/scripts/ci/install_security_tools.sh +47 -0
  60. data/scripts/ci/package_sanity.sh +46 -0
  61. data/scripts/files.rb +1 -4
  62. data/scripts/install_dependencies.sh +19 -0
  63. data/scripts/reports.sh +2 -2
  64. data/spec/lib/moose_inventory/cli/cli_spec.rb +13 -14
  65. data/spec/lib/moose_inventory/cli/group_add_spec.rb +118 -119
  66. data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +49 -51
  67. data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +80 -83
  68. data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +91 -91
  69. data/spec/lib/moose_inventory/cli/group_get_spec.rb +22 -23
  70. data/spec/lib/moose_inventory/cli/group_list_spec.rb +19 -20
  71. data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +35 -36
  72. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +115 -78
  73. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +86 -45
  74. data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +43 -46
  75. data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +131 -131
  76. data/spec/lib/moose_inventory/cli/group_spec.rb +9 -9
  77. data/spec/lib/moose_inventory/cli/host_add_spec.rb +103 -43
  78. data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +78 -80
  79. data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +122 -122
  80. data/spec/lib/moose_inventory/cli/host_get_spec.rb +16 -16
  81. data/spec/lib/moose_inventory/cli/host_list_spec.rb +8 -8
  82. data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +50 -52
  83. data/spec/lib/moose_inventory/cli/host_rm_spec.rb +12 -12
  84. data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +48 -51
  85. data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +136 -136
  86. data/spec/lib/moose_inventory/config/config_spec.rb +16 -3
  87. data/spec/lib/moose_inventory/db/db_spec.rb +386 -2
  88. data/spec/lib/moose_inventory/db/models_spec.rb +10 -11
  89. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +77 -0
  90. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +65 -0
  91. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +69 -0
  92. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +76 -0
  93. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +78 -0
  94. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +57 -0
  95. data/spec/shared/shared_config_setup.rb +2 -2
  96. data/spec/spec_helper.rb +7 -8
  97. metadata +157 -105
  98. data/.coveralls.yml +0 -0
  99. data/Guardfile +0 -38
  100. data/config/dotfiles/coveralls.yml +0 -0
  101. data/config/dotfiles/gitignore +0 -20
  102. data/config/dotfiles/rubocop.yml +0 -793
  103. data/scripts/guard_quality.sh +0 -3
  104. data/scripts/guard_test.sh +0 -2
@@ -9,7 +9,7 @@ RSpec.describe Moose::Inventory::Cli::Host do
9
9
  @mockarg_parts = {
10
10
  config: File.join(spec_root, 'config/config.yml'),
11
11
  format: 'yaml',
12
- env: 'test'
12
+ env: 'test',
13
13
  }
14
14
 
15
15
  @mockargs = []
@@ -38,169 +38,169 @@ RSpec.describe Moose::Inventory::Cli::Host do
38
38
  result = @host.instance_methods(false).include?(:rmvar)
39
39
  expect(result).to eq(true)
40
40
  end
41
-
41
+
42
42
  #-----------------
43
- it '<missing args> ... should abort with an error' do
44
- actual = runner do
45
- @app.start(%w(host rmvar)) # <- no group given
46
- end
47
-
48
- # Check output
49
- desired = { aborted: true}
50
- desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 2 or more.\n"
51
- expected(actual, desired)
52
- end
53
-
54
- #------------------------
55
- it 'HOST key=value ... should abort if the host does not exist' do
56
- host_name = "not-a-host"
57
- var_name = "foo=bar"
58
- actual = runner do
59
- @app.start(%W(host rmvar #{host_name} #{var_name}))
60
- end
61
-
62
- # Check output
63
- desired = { aborted: true}
64
- desired[:STDOUT] =
65
- "Remove variable(s) '#{var_name}' from host '#{host_name}':\n"\
66
- " - retrieve host '#{host_name}'...\n"
67
- desired[:STDERR] =
68
- "An error occurred during a transaction, any changes have been rolled back.\n"\
69
- "ERROR: The host '#{host_name}' does not exist.\n"
70
- expected(actual, desired)
71
- end
72
-
73
- #------------------------
74
- it 'HOST <malformed> ... should abort with an error' do
75
- # 1. Should add the var to the db
76
- # 2. Should associate the host with the var
77
-
78
- host_name = 'test1'
79
- @db.models[:host].create(name: host_name)
80
-
81
- var = {name: 'foo', value: "bar"}
82
- cases = %W(
83
- =bar
84
- foo=bar=
85
- =foo=bar
86
- foo=bar=extra
87
- )
88
-
89
- cases.each do |args|
90
- actual = runner do
91
- @app.start(%W(host rmvar #{host_name} #{args} ))
92
- end
93
- #@console.out(actual,'p')
94
-
95
- desired = { aborted: true}
96
- desired[:STDOUT] =
97
- "Remove variable(s) '#{args}' from host '#{host_name}':\n"\
98
- " - retrieve host '#{host_name}'...\n"\
99
- " - OK\n"\
100
- " - remove variable '#{args}'...\n"
101
- desired[:STDERR] =
102
- "An error occurred during a transaction, any changes have been rolled back.\n"\
103
- "ERROR: Incorrect format in {#{args}}. Expected 'key' or 'key=value'.\n"
104
-
105
- expected(actual, desired)
43
+ it '<missing args> ... should abort with an error' do
44
+ actual = runner do
45
+ @app.start(%w(host rmvar)) # <- no group given
46
+ end
47
+
48
+ # Check output
49
+ desired = { aborted: true }
50
+ desired[:STDERR] = "ERROR: Wrong number of arguments, 0 for 2 or more.\n"
51
+ expected(actual, desired)
52
+ end
53
+
54
+ #------------------------
55
+ it 'HOST key=value ... should abort if the host does not exist' do
56
+ host_name = 'not-a-host'
57
+ var_name = 'foo=bar'
58
+ actual = runner do
59
+ @app.start(%W(host rmvar #{host_name} #{var_name}))
60
+ end
61
+
62
+ # Check output
63
+ desired = { aborted: true }
64
+ desired[:STDOUT] =
65
+ "Remove variable(s) '#{var_name}' from host '#{host_name}':\n"\
66
+ " - retrieve host '#{host_name}'...\n"
67
+ desired[:STDERR] =
68
+ "An error occurred during a transaction, any changes have been rolled back.\n"\
69
+ "ERROR: The host '#{host_name}' does not exist.\n"
70
+ expected(actual, desired)
71
+ end
72
+
73
+ #------------------------
74
+ it 'HOST <malformed> ... should abort with an error' do
75
+ # 1. Should add the var to the db
76
+ # 2. Should associate the host with the var
77
+
78
+ host_name = 'test1'
79
+ @db.models[:host].create(name: host_name)
80
+
81
+ var = { name: 'foo', value: 'bar' }
82
+ cases = %w(
83
+ =bar
84
+ foo=bar=
85
+ =foo=bar
86
+ foo=bar=extra
87
+ )
88
+
89
+ cases.each do |args|
90
+ actual = runner do
91
+ @app.start(%W(host rmvar #{host_name} #{args}))
106
92
  end
93
+ # @console.out(actual,'p')
94
+
95
+ desired = { aborted: true }
96
+ desired[:STDOUT] =
97
+ "Remove variable(s) '#{args}' from host '#{host_name}':\n"\
98
+ " - retrieve host '#{host_name}'...\n"\
99
+ " - OK\n"\
100
+ " - remove variable '#{args}'...\n"
101
+ desired[:STDERR] =
102
+ "An error occurred during a transaction, any changes have been rolled back.\n"\
103
+ "ERROR: Incorrect format in {#{args}}. Expected 'key' or 'key=value'.\n"
104
+
105
+ expected(actual, desired)
107
106
  end
108
-
107
+ end
108
+
109
109
  #------------------------
110
110
  it 'host rmvar HOST <valid args> ... should remove the host variable' do
111
- # 1. Should add the var to the db
112
- # 2. Should associate the host with the var
113
-
114
- host_name = 'test1'
115
-
116
- var = {name: 'foo', value: "bar"}
117
- cases = %W(
118
- #{var[:name]}
119
- #{var[:name]}=
120
- #{var[:name]}=#{var[:value]}
121
- )
122
- cases.each do |example|
123
- # reset the db
124
- @db.reset
125
-
126
- # Add an initial host and hostvar
127
- @db.models[:host].create(name: host_name)
128
- runner do
129
- @app.start(%W(host addvar #{host_name} #{var[:name]}=#{var[:value]} ))
130
- end
131
-
132
- # Try to remove the hostvar using the case example valid args
133
- actual = runner do
134
- @app.start(%W(host rmvar #{host_name} #{example}))
135
- end
136
- #@console.out(actual,'p')
137
-
138
- # Check the output
139
- desired = { aborted: false}
140
- desired[:STDOUT] =
141
- "Remove variable(s) '#{example}' from host '#{host_name}':\n"\
142
- " - retrieve host '#{host_name}'...\n"\
143
- " - OK\n"\
144
- " - remove variable '#{example}'...\n"\
145
- " - OK\n"\
146
- " - all OK\n"\
147
- "Succeeded.\n"
148
-
149
- #@console.out(desired,'p')
150
- expected(actual, desired)
151
-
152
- # Check the db
153
- host = @db.models[:host].find(name: host_name)
154
- hostvars = host.hostvars_dataset
155
- expect(hostvars.count).to eq(0)
156
-
157
- hostvars = @db.models[:hostvar].all
158
- expect(hostvars.count).to eq(0)
159
- end
111
+ # 1. Should add the var to the db
112
+ # 2. Should associate the host with the var
113
+
114
+ host_name = 'test1'
115
+
116
+ var = { name: 'foo', value: 'bar' }
117
+ cases = %W(
118
+ #{var[:name]}
119
+ #{var[:name]}=
120
+ #{var[:name]}=#{var[:value]}
121
+ )
122
+ cases.each do |example|
123
+ # reset the db
124
+ @db.reset
125
+
126
+ # Add an initial host and hostvar
127
+ @db.models[:host].create(name: host_name)
128
+ runner do
129
+ @app.start(%W(host addvar #{host_name} #{var[:name]}=#{var[:value]}))
130
+ end
131
+
132
+ # Try to remove the hostvar using the case example valid args
133
+ actual = runner do
134
+ @app.start(%W(host rmvar #{host_name} #{example}))
135
+ end
136
+ # @console.out(actual,'p')
137
+
138
+ # Check the output
139
+ desired = { aborted: false }
140
+ desired[:STDOUT] =
141
+ "Remove variable(s) '#{example}' from host '#{host_name}':\n"\
142
+ " - retrieve host '#{host_name}'...\n"\
143
+ " - OK\n"\
144
+ " - remove variable '#{example}'...\n"\
145
+ " - OK\n"\
146
+ " - all OK\n"\
147
+ "Succeeded.\n"
148
+
149
+ # @console.out(desired,'p')
150
+ expected(actual, desired)
151
+
152
+ # Check the db
153
+ host = @db.models[:host].find(name: host_name)
154
+ hostvars = host.hostvars_dataset
155
+ expect(hostvars.count).to eq(0)
156
+
157
+ hostvars = @db.models[:hostvar].all
158
+ expect(hostvars.count).to eq(0)
159
+ end
160
160
  end
161
-
161
+
162
162
  #------------------------
163
163
  it 'HOST key1=value1 key2=value2 ... should remove multiple key/value pairs' do
164
164
  host_name = 'test1'
165
- varsarray = [
166
- {name: 'var1', value: "val1"},
167
- {name: 'var2', value: "val2"}
165
+ varsarray = [
166
+ { name: 'var1', value: 'val1' },
167
+ { name: 'var2', value: 'val2' },
168
168
  ]
169
-
169
+
170
170
  vars = []
171
171
  varsarray.each do |var|
172
172
  vars << "#{var[:name]}=#{var[:value]}"
173
173
  end
174
-
174
+
175
175
  @db.models[:host].create(name: host_name)
176
176
  actual = runner do
177
- @app.start(%W(host addvar #{host_name}) + vars )
177
+ @app.start(%W(host addvar #{host_name}) + vars)
178
178
  end
179
-
179
+
180
180
  actual = runner do
181
- @app.start(%W(host rmvar #{host_name}) + vars )
181
+ @app.start(%W(host rmvar #{host_name}) + vars)
182
182
  end
183
- #@console.out(actual,'p')
184
-
185
- desired = { aborted: false}
186
- desired[:STDOUT] =
183
+ # @console.out(actual,'p')
184
+
185
+ desired = { aborted: false }
186
+ desired[:STDOUT] =
187
187
  "Remove variable(s) '#{vars.join(',')}' from host '#{host_name}':\n"\
188
188
  " - retrieve host '#{host_name}'...\n"\
189
189
  " - OK\n"
190
190
  vars.each do |var|
191
- desired[:STDOUT] = desired[:STDOUT] +
192
- " - remove variable '#{var}'...\n"\
193
- " - OK\n"
191
+ desired[:STDOUT] = desired[:STDOUT] +
192
+ " - remove variable '#{var}'...\n"\
193
+ " - OK\n"
194
194
  end
195
- desired[:STDOUT] = desired[:STDOUT] +
196
- " - all OK\n"\
197
- "Succeeded.\n"
195
+ desired[:STDOUT] = desired[:STDOUT] +
196
+ " - all OK\n"\
197
+ "Succeeded.\n"
198
198
  expected(actual, desired)
199
-
199
+
200
200
  # We should have the correct hostvar associations
201
201
  host = @db.models[:host].find(name: host_name)
202
202
  hostvars = host.hostvars_dataset
203
203
  expect(hostvars.count).to eq(0)
204
- end
204
+ end
205
205
  end
206
206
  end
@@ -6,7 +6,7 @@ RSpec.describe 'Moose::Inventory::Config' do
6
6
  @mockarg_parts = {
7
7
  config: File.join(spec_root, 'config/config.yml'),
8
8
  format: 'yaml',
9
- env: 'test'
9
+ env: 'test',
10
10
  }
11
11
 
12
12
  @mockargs = []
@@ -39,7 +39,7 @@ RSpec.describe 'Moose::Inventory::Config' do
39
39
  end
40
40
 
41
41
  it 'should default "--format" to json' do
42
- @config.init([])
42
+ @config.init(['--config', @mockarg_parts[:config]])
43
43
  expect(@config._confopts[:format]).to eq('json')
44
44
  end
45
45
 
@@ -49,7 +49,7 @@ RSpec.describe 'Moose::Inventory::Config' do
49
49
  end
50
50
 
51
51
  it 'should default "--env" to ""' do
52
- @config.init([])
52
+ @config.init(['--config', @mockarg_parts[:config]])
53
53
  expect(@config._confopts[:env]).to eq('')
54
54
  end
55
55
 
@@ -76,5 +76,18 @@ RSpec.describe 'Moose::Inventory::Config' do
76
76
  @config.init(@mockargs)
77
77
  expect(@config._settings[:config][:db]).not_to be_nil
78
78
  end
79
+
80
+ it 'uses safe YAML loading for configuration files' do
81
+ expect(YAML).not_to receive(:load_file)
82
+ expect(YAML).to receive(:safe_load_file).with(
83
+ @mockarg_parts[:config],
84
+ aliases: false,
85
+ permitted_classes: [],
86
+ permitted_symbols: []
87
+ ).and_call_original
88
+
89
+ @config.init(@mockargs)
90
+ expect(@config._settings[:config][:db]).not_to be_nil
91
+ end
79
92
  end
80
93
  end