moose-inventory 1.0.9 → 2.1

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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +15 -1
  3. data/.github/workflows/release.yml +60 -0
  4. data/.gitignore +2 -1
  5. data/.gitleaks.toml +9 -0
  6. data/.rubocop.yml +49 -0
  7. data/BACKLOG.md +752 -24
  8. data/Gemfile +2 -0
  9. data/Gemfile.lock +36 -1
  10. data/README.md +340 -44
  11. data/Rakefile +2 -0
  12. data/bin/moose-inventory +2 -1
  13. data/docs/architecture/architecture-and-trust-boundaries.md +444 -0
  14. data/docs/compatibility/cli-output-compatibility.md +76 -0
  15. data/docs/governance/approval-register.md +37 -0
  16. data/docs/maintenance/database-backup-restore-guidance.md +162 -0
  17. data/docs/maintenance/package-maintenance-and-agent-boundaries.md +260 -0
  18. data/docs/process/conformance-gap-analysis-2026-05-28.md +192 -0
  19. data/docs/product/product-brief.md +161 -0
  20. data/docs/product/requirements-baseline.md +477 -0
  21. data/docs/qa/qa-documentation-and-release-gates.md +283 -0
  22. data/docs/release/package-provenance-hardening.md +126 -0
  23. data/docs/release/publishing.md +54 -50
  24. data/docs/release/release-environment-protection.md +70 -0
  25. data/docs/release/release-readiness.md +37 -4
  26. data/docs/security/accepted-risk-register.md +84 -0
  27. data/docs/security/security-privacy-process.md +287 -0
  28. data/docs/security-audit-2026-05-26-rerun.md +75 -0
  29. data/docs/security-audit-2026-05-26.md +63 -0
  30. data/docs/ux/cli-workflow-notes.md +287 -0
  31. data/examples/ansible/ansible.cfg +3 -0
  32. data/examples/ansible/inventory/moose_inventory.yml +5 -0
  33. data/examples/ansible/inventory_plugins/moose_inventory.py +100 -0
  34. data/examples/ci/README.md +16 -0
  35. data/examples/ci/github-actions/inventory-review.yml +38 -0
  36. data/examples/ci/inventory/example-snapshot.yml +19 -0
  37. data/examples/ci/scripts/validate-inventory-snapshot.sh +30 -0
  38. data/lib/moose_inventory/cli/application.rb +133 -5
  39. data/lib/moose_inventory/cli/association_rendering.rb +74 -0
  40. data/lib/moose_inventory/cli/association_rendering_support.rb +89 -0
  41. data/lib/moose_inventory/cli/audit.rb +62 -0
  42. data/lib/moose_inventory/cli/audit_recording.rb +40 -0
  43. data/lib/moose_inventory/cli/child_relation_rendering.rb +110 -0
  44. data/lib/moose_inventory/cli/console.rb +135 -0
  45. data/lib/moose_inventory/cli/db.rb +64 -0
  46. data/lib/moose_inventory/cli/factory.rb +28 -0
  47. data/lib/moose_inventory/cli/formatter.rb +8 -12
  48. data/lib/moose_inventory/cli/group.rb +7 -1
  49. data/lib/moose_inventory/cli/group_add.rb +91 -73
  50. data/lib/moose_inventory/cli/group_addchild.rb +41 -66
  51. data/lib/moose_inventory/cli/group_addhost.rb +33 -71
  52. data/lib/moose_inventory/cli/group_addvar.rb +27 -47
  53. data/lib/moose_inventory/cli/group_get.rb +8 -42
  54. data/lib/moose_inventory/cli/group_list.rb +7 -40
  55. data/lib/moose_inventory/cli/group_listvars.rb +9 -55
  56. data/lib/moose_inventory/cli/group_rm.rb +105 -73
  57. data/lib/moose_inventory/cli/group_rmchild.rb +47 -57
  58. data/lib/moose_inventory/cli/group_rmhost.rb +34 -61
  59. data/lib/moose_inventory/cli/group_rmvar.rb +30 -41
  60. data/lib/moose_inventory/cli/group_tags.rb +33 -0
  61. data/lib/moose_inventory/cli/helpers.rb +143 -0
  62. data/lib/moose_inventory/cli/host.rb +8 -2
  63. data/lib/moose_inventory/cli/host_add.rb +91 -66
  64. data/lib/moose_inventory/cli/host_addgroup.rb +39 -66
  65. data/lib/moose_inventory/cli/host_addvar.rb +28 -52
  66. data/lib/moose_inventory/cli/host_get.rb +9 -37
  67. data/lib/moose_inventory/cli/host_list.rb +24 -21
  68. data/lib/moose_inventory/cli/host_listvars.rb +9 -62
  69. data/lib/moose_inventory/cli/host_rm.rb +60 -42
  70. data/lib/moose_inventory/cli/host_rmgroup.rb +39 -55
  71. data/lib/moose_inventory/cli/host_rmvar.rb +31 -45
  72. data/lib/moose_inventory/cli/host_tags.rb +33 -0
  73. data/lib/moose_inventory/cli/listvars_support.rb +55 -0
  74. data/lib/moose_inventory/cli/plan_rendering.rb +50 -0
  75. data/lib/moose_inventory/cli/relation_transaction_support.rb +51 -0
  76. data/lib/moose_inventory/cli/tag_support.rb +97 -0
  77. data/lib/moose_inventory/cli/variable_rendering.rb +67 -0
  78. data/lib/moose_inventory/config/config.rb +185 -108
  79. data/lib/moose_inventory/db/db.rb +188 -193
  80. data/lib/moose_inventory/db/exceptions.rb +6 -3
  81. data/lib/moose_inventory/db/models.rb +16 -0
  82. data/lib/moose_inventory/db/schema_migrations.rb +248 -0
  83. data/lib/moose_inventory/inventory_context.rb +116 -0
  84. data/lib/moose_inventory/operations/add_associations.rb +131 -0
  85. data/lib/moose_inventory/operations/add_groups.rb +123 -0
  86. data/lib/moose_inventory/operations/add_hosts.rb +123 -0
  87. data/lib/moose_inventory/operations/add_variables.rb +77 -0
  88. data/lib/moose_inventory/operations/entity_variable_operation_support.rb +46 -0
  89. data/lib/moose_inventory/operations/group_child_relations.rb +125 -0
  90. data/lib/moose_inventory/operations/group_cleanup.rb +70 -0
  91. data/lib/moose_inventory/operations/import_inventory_snapshot.rb +41 -0
  92. data/lib/moose_inventory/operations/inventory_doctor.rb +172 -0
  93. data/lib/moose_inventory/operations/inventory_snapshot.rb +60 -0
  94. data/lib/moose_inventory/operations/inventory_snapshot_applier.rb +112 -0
  95. data/lib/moose_inventory/operations/inventory_snapshot_preview.rb +174 -0
  96. data/lib/moose_inventory/operations/inventory_snapshot_validator.rb +134 -0
  97. data/lib/moose_inventory/operations/operation_event_support.rb +27 -0
  98. data/lib/moose_inventory/operations/query_inventory/base_query.rb +24 -0
  99. data/lib/moose_inventory/operations/query_inventory/group_queries.rb +86 -0
  100. data/lib/moose_inventory/operations/query_inventory/host_queries.rb +106 -0
  101. data/lib/moose_inventory/operations/query_inventory.rb +47 -0
  102. data/lib/moose_inventory/operations/remove_associations.rb +113 -0
  103. data/lib/moose_inventory/operations/remove_groups.rb +79 -0
  104. data/lib/moose_inventory/operations/remove_hosts.rb +68 -0
  105. data/lib/moose_inventory/operations/remove_variables.rb +67 -0
  106. data/lib/moose_inventory/runtime_options.rb +31 -0
  107. data/lib/moose_inventory/version.rb +3 -1
  108. data/lib/moose_inventory.rb +10 -7
  109. data/moose-inventory.gemspec +22 -35
  110. data/scripts/check.sh +3 -0
  111. data/scripts/ci/check_generated_artifacts.sh +41 -0
  112. data/scripts/ci/check_permissions.sh +5 -0
  113. data/scripts/ci/check_rubocop.sh +33 -0
  114. data/scripts/ci/check_secrets.sh +26 -0
  115. data/scripts/ci/check_security.sh +18 -0
  116. data/scripts/ci/install_security_tools.sh +47 -0
  117. data/scripts/files.rb +5 -4
  118. data/scripts/install_dependencies.sh +2 -0
  119. data/spec/examples/ci_examples_spec.rb +37 -0
  120. data/spec/lib/moose_inventory/ansible_plugin_examples_spec.rb +29 -0
  121. data/spec/lib/moose_inventory/cli/application_doctor_spec.rb +50 -0
  122. data/spec/lib/moose_inventory/cli/application_import_export_spec.rb +100 -0
  123. data/spec/lib/moose_inventory/cli/application_spec.rb +25 -15
  124. data/spec/lib/moose_inventory/cli/audit_spec.rb +56 -0
  125. data/spec/lib/moose_inventory/cli/cli_spec.rb +15 -19
  126. data/spec/lib/moose_inventory/cli/console_spec.rb +98 -0
  127. data/spec/lib/moose_inventory/cli/factory_spec.rb +27 -0
  128. data/spec/lib/moose_inventory/cli/formatter_spec.rb +95 -3
  129. data/spec/lib/moose_inventory/cli/group_add_spec.rb +140 -116
  130. data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +89 -35
  131. data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +81 -84
  132. data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +65 -68
  133. data/spec/lib/moose_inventory/cli/group_get_spec.rb +17 -33
  134. data/spec/lib/moose_inventory/cli/group_list_spec.rb +16 -38
  135. data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +33 -40
  136. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +165 -85
  137. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +100 -30
  138. data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +76 -78
  139. data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +57 -63
  140. data/spec/lib/moose_inventory/cli/group_spec.rb +2 -0
  141. data/spec/lib/moose_inventory/cli/helpers_spec.rb +146 -0
  142. data/spec/lib/moose_inventory/cli/host_add_spec.rb +170 -116
  143. data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +100 -83
  144. data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +92 -74
  145. data/spec/lib/moose_inventory/cli/host_get_spec.rb +14 -33
  146. data/spec/lib/moose_inventory/cli/host_list_spec.rb +41 -33
  147. data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +45 -53
  148. data/spec/lib/moose_inventory/cli/host_rm_spec.rb +66 -48
  149. data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +73 -83
  150. data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +56 -63
  151. data/spec/lib/moose_inventory/cli/host_spec.rb +2 -0
  152. data/spec/lib/moose_inventory/cli/tags_spec.rb +81 -0
  153. data/spec/lib/moose_inventory/config/config_spec.rb +41 -3
  154. data/spec/lib/moose_inventory/db/db_spec.rb +551 -29
  155. data/spec/lib/moose_inventory/db/exceptions_spec.rb +18 -0
  156. data/spec/lib/moose_inventory/db/models_spec.rb +7 -3
  157. data/spec/lib/moose_inventory/db_lifecycle_spec.rb +73 -0
  158. data/spec/lib/moose_inventory/inventory_context_spec.rb +10 -0
  159. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +111 -0
  160. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +80 -0
  161. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +82 -0
  162. data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
  163. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +122 -0
  164. data/spec/lib/moose_inventory/operations/import_inventory_snapshot_spec.rb +226 -0
  165. data/spec/lib/moose_inventory/operations/inventory_doctor_spec.rb +77 -0
  166. data/spec/lib/moose_inventory/operations/inventory_snapshot_spec.rb +50 -0
  167. data/spec/lib/moose_inventory/operations/operation_event_support_spec.rb +78 -0
  168. data/spec/lib/moose_inventory/operations/query_inventory_spec.rb +146 -0
  169. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +113 -0
  170. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +78 -0
  171. data/spec/lib/moose_inventory/operations/remove_hosts_spec.rb +55 -0
  172. data/spec/lib/moose_inventory/operations/remove_variables_spec.rb +83 -0
  173. data/spec/shared/shared_config_setup.rb +4 -3
  174. data/spec/spec_helper.rb +50 -40
  175. data/spec/support/cli_harness.rb +33 -0
  176. metadata +163 -35
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'inventory_context'
5
+ require 'operations/remove_groups'
6
+
7
+ RSpec.describe Moose::Inventory::Operations::RemoveGroups do
8
+ before(:all) do
9
+ @mockargs = [
10
+ '--config', File.join(spec_root, 'config/config.yml'),
11
+ '--format', 'yaml',
12
+ '--env', 'test'
13
+ ]
14
+
15
+ Moose::Inventory::Config.init(@mockargs)
16
+ @db = Moose::Inventory::DB
17
+ @db.init if @db.db.nil?
18
+ end
19
+
20
+ before(:each) do
21
+ @db.reset
22
+ end
23
+
24
+ def operation
25
+ described_class.new(
26
+ context: Moose::Inventory::InventoryContext.new(db: @db)
27
+ )
28
+ end
29
+
30
+ it 'reports missing groups as warnings' do
31
+ result = operation.call(names: ['missing'], recursive: false)
32
+
33
+ expect(result.warning_count).to eq(1)
34
+ expect(result.events.map(&:type)).to include(:group_missing)
35
+ end
36
+
37
+ it 'returns dry-run events without removing groups or recursive children' do
38
+ parent = @db.models[:group].create(name: 'parent')
39
+ child = @db.models[:group].create(name: 'child')
40
+ host = @db.models[:host].create(name: 'child-host')
41
+ child.add_host(host)
42
+ parent.add_child(child)
43
+
44
+ result = operation.call(names: ['parent'], recursive: true, dry_run: true)
45
+
46
+ expect(result.warning_count).to eq(0)
47
+ expect(result.events.map(&:type)).to include(
48
+ :removing_child_association,
49
+ :recursively_delete_orphaned_group,
50
+ :adding_automatic_group_to_host,
51
+ :destroying_group,
52
+ :dry_run_summary
53
+ )
54
+ expect(@db.models[:group].find(name: 'parent')).not_to be_nil
55
+ expect(@db.models[:group].find(name: 'child')).not_to be_nil
56
+ expect(host.groups_dataset[name: 'ungrouped']).to be_nil
57
+ end
58
+ it 'removes groups and recursively cleans orphaned children when requested' do
59
+ parent = @db.models[:group].create(name: 'parent')
60
+ child = @db.models[:group].create(name: 'child')
61
+ host = @db.models[:host].create(name: 'child-host')
62
+ child.add_host(host)
63
+ parent.add_child(child)
64
+
65
+ result = operation.call(names: ['parent'], recursive: true)
66
+
67
+ expect(result.warning_count).to eq(0)
68
+ expect(result.events.map(&:type)).to include(
69
+ :removing_child_association,
70
+ :recursively_delete_orphaned_group,
71
+ :adding_automatic_group_to_host,
72
+ :destroying_group
73
+ )
74
+ expect(@db.models[:group].find(name: 'parent')).to be_nil
75
+ expect(@db.models[:group].find(name: 'child')).to be_nil
76
+ expect(host.groups_dataset[name: 'ungrouped']).not_to be_nil
77
+ end
78
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Moose::Inventory::Operations::RemoveHosts do
6
+ before(:all) do
7
+ mockargs = [
8
+ '--config', File.join(spec_root, 'config/config.yml'),
9
+ '--format', 'yaml',
10
+ '--env', 'test'
11
+ ]
12
+
13
+ @config = Moose::Inventory::Config
14
+ @config.init(mockargs)
15
+
16
+ @db = Moose::Inventory::DB
17
+ @db.init if @db.db.nil?
18
+ end
19
+
20
+ before(:each) do
21
+ @db.reset
22
+ @context = Moose::Inventory::InventoryContext.new(db: @db)
23
+ @operation = described_class.new(context: @context)
24
+ end
25
+
26
+ it 'removes an existing host' do
27
+ host = @db.models[:host].create(name: 'test1')
28
+ host.add_group(@db.models[:group].find_or_create(name: 'ungrouped'))
29
+
30
+ result = @operation.call(names: ['test1'])
31
+
32
+ expect(result.warning_count).to eq(0)
33
+ expect(@db.models[:host].find(name: 'test1')).to be_nil
34
+ expect(result.events.map(&:type)).to eq(%i[host_started retrieving_host ok destroying_host ok host_complete])
35
+ end
36
+
37
+ it 'returns dry-run events without deleting an existing host' do
38
+ host = @db.models[:host].create(name: 'test1')
39
+ host.add_group(@db.models[:group].find_or_create(name: 'ungrouped'))
40
+
41
+ result = @operation.call(names: ['test1'], dry_run: true)
42
+
43
+ expect(result.warning_count).to eq(0)
44
+ expect(@db.models[:host].find(name: 'test1')).not_to be_nil
45
+ expect(result.events.map(&:type)).to eq(%i[host_started retrieving_host ok destroying_host ok host_complete
46
+ dry_run_summary])
47
+ end
48
+ it 'returns a warning event when the host does not exist' do
49
+ result = @operation.call(names: ['fake'])
50
+
51
+ expect(result.warning_count).to eq(1)
52
+ expect(result.events.map(&:type)).to eq(%i[host_started retrieving_host host_missing missing_skipping ok
53
+ host_complete])
54
+ end
55
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'inventory_context'
5
+ require 'operations/remove_variables'
6
+
7
+ RSpec.describe Moose::Inventory::Operations::RemoveVariables do
8
+ before(:all) do
9
+ @mockargs = [
10
+ '--config', File.join(spec_root, 'config/config.yml'),
11
+ '--format', 'yaml',
12
+ '--env', 'test'
13
+ ]
14
+
15
+ Moose::Inventory::Config.init(@mockargs)
16
+ @db = Moose::Inventory::DB
17
+ @db.init if @db.db.nil?
18
+ end
19
+
20
+ before(:each) do
21
+ @db.reset
22
+ end
23
+
24
+ def build_operation(entity_type, emitter: nil)
25
+ described_class.new(
26
+ context: Moose::Inventory::InventoryContext.new(db: @db),
27
+ entity_type: entity_type,
28
+ emitter: emitter
29
+ )
30
+ end
31
+
32
+ it 'removes host variables and returns structured events without rendering output' do
33
+ host = @db.models[:host].create(name: 'test1')
34
+ var = @db.models[:hostvar].create(name: 'var1', value: 'val1')
35
+ host.add_hostvar(var)
36
+
37
+ actual = runner do
38
+ @result = build_operation(:host).call(name: 'test1', vars: ['var1'])
39
+ end
40
+
41
+ expected(actual, STDOUT: '', STDERR: '')
42
+ expect(@result.events.map(&:type)).to eq(
43
+ %i[entity_started retrieving_entity ok removing_variable ok entity_complete]
44
+ )
45
+ expect(host.hostvars_dataset.count).to eq(0)
46
+ expect(@db.models[:hostvar].count).to eq(0)
47
+ end
48
+
49
+ it 'accepts group variable removal by key=value syntax and removes the record' do
50
+ group = @db.models[:group].create(name: 'testgroup')
51
+ var = @db.models[:groupvar].create(name: 'var1', value: 'val1')
52
+ group.add_groupvar(var)
53
+
54
+ build_operation(:group).call(name: 'testgroup', vars: ['var1=val1'])
55
+
56
+ expect(group.groupvars_dataset.count).to eq(0)
57
+ expect(@db.models[:groupvar].count).to eq(0)
58
+ end
59
+
60
+ it 'dry-runs removing variables without deleting records' do
61
+ host = @db.models[:host].create(name: 'test1')
62
+ var = @db.models[:hostvar].create(name: 'var1', value: 'val1')
63
+ host.add_hostvar(var)
64
+
65
+ result = build_operation(:host).call(name: 'test1', vars: ['var1'], dry_run: true)
66
+
67
+ expect(result.events.map(&:type)).to include(:removing_variable, :dry_run_summary)
68
+ expect(host.hostvars_dataset[name: 'var1']).not_to be_nil
69
+ expect(@db.models[:hostvar].count).to eq(1)
70
+ end
71
+
72
+ it 'emits partial progress before raising on malformed group variable removal input' do
73
+ @db.models[:group].create(name: 'testgroup')
74
+ emitted = []
75
+ operation = build_operation(:group, emitter: emitted.method(:<<))
76
+
77
+ expect do
78
+ operation.call(name: 'testgroup', vars: ['=broken'])
79
+ end.to raise_error(Moose::Inventory::DB.exceptions[:moose], /Expected 'key' or 'key=value'/)
80
+
81
+ expect(emitted.map(&:type)).to eq(%i[entity_started retrieving_entity ok removing_variable])
82
+ end
83
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  RSpec.shared_context 'shared config init', a: :b do
3
4
  before(:all) do
4
5
  @mockarg_parts = {
5
- config: File.join(spec_dir, 'config/config.yml'),
6
- format: 'yaml',
7
- env: 'test',
6
+ config: File.join(spec_dir, 'config/config.yml'),
7
+ format: 'yaml',
8
+ env: 'test'
8
9
  }
9
10
 
10
11
  @mockargs = []
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if RUBY_VERSION >= '1.9'
2
4
  require 'simplecov'
3
5
  SimpleCov.formatters = [
@@ -31,34 +33,34 @@ require 'yaml'
31
33
  require 'fileutils'
32
34
  require 'find'
33
35
  require 'moose_inventory'
36
+ require_relative 'support/cli_harness'
34
37
 
35
- RSpec.configure do |config|
36
- # config.filter_run focus: true # <- enable to allow test focus
37
- config.color = true
38
- config.tty = true
39
- config.formatter = :progress #:documentation # :progress, :html, :textmate
40
- def capture(stream)
38
+ module SpecOutputHelpers
39
+ def capture(stream, &)
41
40
  case stream
42
41
  when :STDOUT
43
- begin
44
- orig = $stdout
45
- $stdout = StringIO.new
46
- yield
47
- result = $stdout.string
48
- ensure
49
- $stdout = orig
50
- end
42
+ capture_stdout(&)
51
43
  when :STDERR
52
- begin
53
- orig = $stderr
54
- $stderr = StringIO.new
55
- yield
56
- result = $stderr.string
57
- ensure
58
- $stderr = orig
59
- end
44
+ capture_stderr(&)
60
45
  end
61
- result
46
+ end
47
+
48
+ def capture_stdout
49
+ orig = $stdout
50
+ $stdout = StringIO.new
51
+ yield
52
+ $stdout.string
53
+ ensure
54
+ $stdout = orig
55
+ end
56
+
57
+ def capture_stderr
58
+ orig = $stderr
59
+ $stderr = StringIO.new
60
+ yield
61
+ $stderr.string
62
+ ensure
63
+ $stderr = orig
62
64
  end
63
65
 
64
66
  def runner
@@ -66,17 +68,13 @@ RSpec.configure do |config|
66
68
 
67
69
  out[:STDERR] = capture(:STDERR) do
68
70
  out[:STDOUT] = capture(:STDOUT) do
69
- begin
70
- yield
71
-
72
- rescue SystemExit
73
- out[:aborted] = true
74
-
75
- # rubocop:disable Lint/RescueException
76
- rescue Exception => e
77
- # rubocop:enable Lint/RescueException
78
- out[:unexpected] = e
79
- end
71
+ yield
72
+ rescue SystemExit
73
+ out[:aborted] = true
74
+ # rubocop:disable Lint/RescueException
75
+ rescue Exception => e
76
+ # rubocop:enable Lint/RescueException
77
+ out[:unexpected] = e
80
78
  end
81
79
  end
82
80
  out # return the output
@@ -93,17 +91,29 @@ RSpec.configure do |config|
93
91
  expect(actual[:STDERR]).to eq(desired[:STDERR])
94
92
  end
95
93
 
96
- def clobber_db_files
94
+ def spec_root
95
+ File.dirname(__FILE__)
96
+ end
97
+ end
98
+
99
+ module SpecDatabaseHelpers
100
+ def self.clobber_db_files
97
101
  FileUtils.mkdir_p('tmp')
98
102
  paths = []
99
103
  Find.find('tmp') { |path| paths << path if path =~ /.*\.db$/ }
100
104
  paths.each { |file| File.delete(file) }
101
105
  end
106
+ end
102
107
 
103
- def spec_root
104
- File.dirname(__FILE__)
105
- end
108
+ RSpec.configure do |config|
109
+ config.include CliHarness
110
+ config.include SpecOutputHelpers
111
+ # config.filter_run focus: true # <- enable to allow test focus
112
+ config.color = true
113
+ config.tty = true
114
+ config.formatter = :progress # :documentation # :progress, :html, :textmate
106
115
 
107
- # Always start with a fresh db file.
108
- clobber_db_files
116
+ config.before(:suite) do
117
+ SpecDatabaseHelpers.clobber_db_files
118
+ end
109
119
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CliHarness
4
+ def setup_cli_harness(command_class:, command_ivar: nil, include_cli: false, extra_commands: {}, extra_args: [])
5
+ @mockarg_parts = {
6
+ config: File.join(spec_root, 'config/config.yml'),
7
+ format: 'yaml',
8
+ env: 'test'
9
+ }
10
+ @mockargs = build_cli_args(@mockarg_parts) + extra_args
11
+
12
+ @config = Moose::Inventory::Config
13
+ @config.init(@mockargs)
14
+
15
+ @console = Moose::Inventory::Cli::Formatter
16
+ @db = Moose::Inventory::DB
17
+ @db.init if @db.db.nil?
18
+
19
+ @app = Moose::Inventory::Cli::Application
20
+ @cli = Moose::Inventory::Cli if include_cli
21
+ instance_variable_set(command_ivar, command_class) unless command_ivar.nil?
22
+ extra_commands.each { |ivar, klass| instance_variable_set(ivar, klass) }
23
+ end
24
+
25
+ def reset_cli_harness(reset_config: false)
26
+ @config.init(@mockargs) if reset_config
27
+ @db.reset
28
+ end
29
+
30
+ def build_cli_args(parts)
31
+ parts.flat_map { |key, value| ["--#{key}", value] }
32
+ end
33
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moose-inventory
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Russell Davies
@@ -163,6 +163,46 @@ dependencies:
163
163
  - - "<"
164
164
  - !ruby/object:Gem::Version
165
165
  version: '3'
166
+ - !ruby/object:Gem::Dependency
167
+ name: bundler-audit
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0.9'
173
+ - - "<"
174
+ - !ruby/object:Gem::Version
175
+ version: '1'
176
+ type: :development
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0.9'
183
+ - - "<"
184
+ - !ruby/object:Gem::Version
185
+ version: '1'
186
+ - !ruby/object:Gem::Dependency
187
+ name: parallel
188
+ requirement: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '1.10'
193
+ - - "<"
194
+ - !ruby/object:Gem::Version
195
+ version: '2.0'
196
+ type: :development
197
+ prerelease: false
198
+ version_requirements: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: '1.10'
203
+ - - "<"
204
+ - !ruby/object:Gem::Version
205
+ version: '2.0'
166
206
  - !ruby/object:Gem::Dependency
167
207
  name: rake
168
208
  requirement: !ruby/object:Gem::Requirement
@@ -197,6 +237,26 @@ dependencies:
197
237
  - - "~>"
198
238
  - !ruby/object:Gem::Version
199
239
  version: '3'
240
+ - !ruby/object:Gem::Dependency
241
+ name: rubocop
242
+ requirement: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '1.72'
247
+ - - "<"
248
+ - !ruby/object:Gem::Version
249
+ version: '2'
250
+ type: :development
251
+ prerelease: false
252
+ version_requirements: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '1.72'
257
+ - - "<"
258
+ - !ruby/object:Gem::Version
259
+ version: '2'
200
260
  - !ruby/object:Gem::Dependency
201
261
  name: simplecov
202
262
  requirement: !ruby/object:Gem::Requirement
@@ -211,7 +271,7 @@ dependencies:
211
271
  - - "~>"
212
272
  - !ruby/object:Gem::Version
213
273
  version: '0'
214
- description: The Moosecastle CLI tool for Ansible-compatable dynamic inventory management.
274
+ description: The Moosecastle CLI tool for Ansible-compatible dynamic inventory management.
215
275
  email:
216
276
  - russell@blakemere.ca
217
277
  executables:
@@ -220,7 +280,10 @@ extensions: []
220
280
  extra_rdoc_files: []
221
281
  files:
222
282
  - ".github/workflows/ci.yml"
283
+ - ".github/workflows/release.yml"
223
284
  - ".gitignore"
285
+ - ".gitleaks.toml"
286
+ - ".rubocop.yml"
224
287
  - BACKLOG.md
225
288
  - Gemfile
226
289
  - Gemfile.lock
@@ -228,11 +291,42 @@ files:
228
291
  - README.md
229
292
  - Rakefile
230
293
  - bin/moose-inventory
294
+ - docs/architecture/architecture-and-trust-boundaries.md
295
+ - docs/compatibility/cli-output-compatibility.md
296
+ - docs/governance/approval-register.md
297
+ - docs/maintenance/database-backup-restore-guidance.md
298
+ - docs/maintenance/package-maintenance-and-agent-boundaries.md
299
+ - docs/process/conformance-gap-analysis-2026-05-28.md
300
+ - docs/product/product-brief.md
301
+ - docs/product/requirements-baseline.md
302
+ - docs/qa/qa-documentation-and-release-gates.md
303
+ - docs/release/package-provenance-hardening.md
231
304
  - docs/release/publishing.md
305
+ - docs/release/release-environment-protection.md
232
306
  - docs/release/release-readiness.md
233
307
  - docs/security-audit-2026-05-21.md
308
+ - docs/security-audit-2026-05-26-rerun.md
309
+ - docs/security-audit-2026-05-26.md
310
+ - docs/security/accepted-risk-register.md
311
+ - docs/security/security-privacy-process.md
312
+ - docs/ux/cli-workflow-notes.md
313
+ - examples/ansible/ansible.cfg
314
+ - examples/ansible/inventory/moose_inventory.yml
315
+ - examples/ansible/inventory_plugins/moose_inventory.py
316
+ - examples/ci/README.md
317
+ - examples/ci/github-actions/inventory-review.yml
318
+ - examples/ci/inventory/example-snapshot.yml
319
+ - examples/ci/scripts/validate-inventory-snapshot.sh
234
320
  - lib/moose_inventory.rb
235
321
  - lib/moose_inventory/cli/application.rb
322
+ - lib/moose_inventory/cli/association_rendering.rb
323
+ - lib/moose_inventory/cli/association_rendering_support.rb
324
+ - lib/moose_inventory/cli/audit.rb
325
+ - lib/moose_inventory/cli/audit_recording.rb
326
+ - lib/moose_inventory/cli/child_relation_rendering.rb
327
+ - lib/moose_inventory/cli/console.rb
328
+ - lib/moose_inventory/cli/db.rb
329
+ - lib/moose_inventory/cli/factory.rb
236
330
  - lib/moose_inventory/cli/formatter.rb
237
331
  - lib/moose_inventory/cli/group.rb
238
332
  - lib/moose_inventory/cli/group_add.rb
@@ -246,6 +340,8 @@ files:
246
340
  - lib/moose_inventory/cli/group_rmchild.rb
247
341
  - lib/moose_inventory/cli/group_rmhost.rb
248
342
  - lib/moose_inventory/cli/group_rmvar.rb
343
+ - lib/moose_inventory/cli/group_tags.rb
344
+ - lib/moose_inventory/cli/helpers.rb
249
345
  - lib/moose_inventory/cli/host.rb
250
346
  - lib/moose_inventory/cli/host_add.rb
251
347
  - lib/moose_inventory/cli/host_addgroup.rb
@@ -256,23 +352,65 @@ files:
256
352
  - lib/moose_inventory/cli/host_rm.rb
257
353
  - lib/moose_inventory/cli/host_rmgroup.rb
258
354
  - lib/moose_inventory/cli/host_rmvar.rb
355
+ - lib/moose_inventory/cli/host_tags.rb
356
+ - lib/moose_inventory/cli/listvars_support.rb
357
+ - lib/moose_inventory/cli/plan_rendering.rb
358
+ - lib/moose_inventory/cli/relation_transaction_support.rb
359
+ - lib/moose_inventory/cli/tag_support.rb
360
+ - lib/moose_inventory/cli/variable_rendering.rb
259
361
  - lib/moose_inventory/config/config.rb
260
362
  - lib/moose_inventory/db/db.rb
261
363
  - lib/moose_inventory/db/exceptions.rb
262
364
  - lib/moose_inventory/db/models.rb
365
+ - lib/moose_inventory/db/schema_migrations.rb
366
+ - lib/moose_inventory/inventory_context.rb
367
+ - lib/moose_inventory/operations/add_associations.rb
368
+ - lib/moose_inventory/operations/add_groups.rb
369
+ - lib/moose_inventory/operations/add_hosts.rb
370
+ - lib/moose_inventory/operations/add_variables.rb
371
+ - lib/moose_inventory/operations/entity_variable_operation_support.rb
372
+ - lib/moose_inventory/operations/group_child_relations.rb
373
+ - lib/moose_inventory/operations/group_cleanup.rb
374
+ - lib/moose_inventory/operations/import_inventory_snapshot.rb
375
+ - lib/moose_inventory/operations/inventory_doctor.rb
376
+ - lib/moose_inventory/operations/inventory_snapshot.rb
377
+ - lib/moose_inventory/operations/inventory_snapshot_applier.rb
378
+ - lib/moose_inventory/operations/inventory_snapshot_preview.rb
379
+ - lib/moose_inventory/operations/inventory_snapshot_validator.rb
380
+ - lib/moose_inventory/operations/operation_event_support.rb
381
+ - lib/moose_inventory/operations/query_inventory.rb
382
+ - lib/moose_inventory/operations/query_inventory/base_query.rb
383
+ - lib/moose_inventory/operations/query_inventory/group_queries.rb
384
+ - lib/moose_inventory/operations/query_inventory/host_queries.rb
385
+ - lib/moose_inventory/operations/remove_associations.rb
386
+ - lib/moose_inventory/operations/remove_groups.rb
387
+ - lib/moose_inventory/operations/remove_hosts.rb
388
+ - lib/moose_inventory/operations/remove_variables.rb
389
+ - lib/moose_inventory/runtime_options.rb
263
390
  - lib/moose_inventory/version.rb
264
391
  - moose-inventory.gemspec
265
392
  - scripts/check.sh
393
+ - scripts/ci/check_generated_artifacts.sh
266
394
  - scripts/ci/check_permissions.sh
395
+ - scripts/ci/check_rubocop.sh
396
+ - scripts/ci/check_secrets.sh
267
397
  - scripts/ci/check_security.sh
398
+ - scripts/ci/install_security_tools.sh
268
399
  - scripts/ci/package_sanity.sh
269
400
  - scripts/files.rb
270
401
  - scripts/install_dependencies.sh
271
402
  - scripts/reports.sh
272
403
  - scripts/work-through.sh
273
404
  - spec/config/config.yml
405
+ - spec/examples/ci_examples_spec.rb
406
+ - spec/lib/moose_inventory/ansible_plugin_examples_spec.rb
407
+ - spec/lib/moose_inventory/cli/application_doctor_spec.rb
408
+ - spec/lib/moose_inventory/cli/application_import_export_spec.rb
274
409
  - spec/lib/moose_inventory/cli/application_spec.rb
410
+ - spec/lib/moose_inventory/cli/audit_spec.rb
275
411
  - spec/lib/moose_inventory/cli/cli_spec.rb
412
+ - spec/lib/moose_inventory/cli/console_spec.rb
413
+ - spec/lib/moose_inventory/cli/factory_spec.rb
276
414
  - spec/lib/moose_inventory/cli/formatter_spec.rb
277
415
  - spec/lib/moose_inventory/cli/group_add_spec.rb
278
416
  - spec/lib/moose_inventory/cli/group_addchild_spec.rb
@@ -286,6 +424,7 @@ files:
286
424
  - spec/lib/moose_inventory/cli/group_rmhost_spec.rb
287
425
  - spec/lib/moose_inventory/cli/group_rmvar_spec.rb
288
426
  - spec/lib/moose_inventory/cli/group_spec.rb
427
+ - spec/lib/moose_inventory/cli/helpers_spec.rb
289
428
  - spec/lib/moose_inventory/cli/host_add_spec.rb
290
429
  - spec/lib/moose_inventory/cli/host_addgroup_spec.rb
291
430
  - spec/lib/moose_inventory/cli/host_addvar_spec.rb
@@ -296,15 +435,35 @@ files:
296
435
  - spec/lib/moose_inventory/cli/host_rmgroup_spec.rb
297
436
  - spec/lib/moose_inventory/cli/host_rmvar_spec.rb
298
437
  - spec/lib/moose_inventory/cli/host_spec.rb
438
+ - spec/lib/moose_inventory/cli/tags_spec.rb
299
439
  - spec/lib/moose_inventory/config/config_spec.rb
300
440
  - spec/lib/moose_inventory/db/db_spec.rb
441
+ - spec/lib/moose_inventory/db/exceptions_spec.rb
301
442
  - spec/lib/moose_inventory/db/models_spec.rb
443
+ - spec/lib/moose_inventory/db_lifecycle_spec.rb
444
+ - spec/lib/moose_inventory/inventory_context_spec.rb
445
+ - spec/lib/moose_inventory/operations/add_associations_spec.rb
446
+ - spec/lib/moose_inventory/operations/add_groups_spec.rb
447
+ - spec/lib/moose_inventory/operations/add_hosts_spec.rb
448
+ - spec/lib/moose_inventory/operations/add_variables_spec.rb
449
+ - spec/lib/moose_inventory/operations/group_child_relations_spec.rb
450
+ - spec/lib/moose_inventory/operations/import_inventory_snapshot_spec.rb
451
+ - spec/lib/moose_inventory/operations/inventory_doctor_spec.rb
452
+ - spec/lib/moose_inventory/operations/inventory_snapshot_spec.rb
453
+ - spec/lib/moose_inventory/operations/operation_event_support_spec.rb
454
+ - spec/lib/moose_inventory/operations/query_inventory_spec.rb
455
+ - spec/lib/moose_inventory/operations/remove_associations_spec.rb
456
+ - spec/lib/moose_inventory/operations/remove_groups_spec.rb
457
+ - spec/lib/moose_inventory/operations/remove_hosts_spec.rb
458
+ - spec/lib/moose_inventory/operations/remove_variables_spec.rb
302
459
  - spec/shared/shared_config_setup.rb
303
460
  - spec/spec_helper.rb
461
+ - spec/support/cli_harness.rb
304
462
  homepage: https://github.com/RusDavies/moose-inventory
305
463
  licenses:
306
464
  - MIT
307
- metadata: {}
465
+ metadata:
466
+ rubygems_mfa_required: 'true'
308
467
  rdoc_options: []
309
468
  require_paths:
310
469
  - lib
@@ -322,35 +481,4 @@ requirements: []
322
481
  rubygems_version: 3.6.9
323
482
  specification_version: 4
324
483
  summary: Moose-tools inventory manager
325
- test_files:
326
- - spec/config/config.yml
327
- - spec/lib/moose_inventory/cli/application_spec.rb
328
- - spec/lib/moose_inventory/cli/cli_spec.rb
329
- - spec/lib/moose_inventory/cli/formatter_spec.rb
330
- - spec/lib/moose_inventory/cli/group_add_spec.rb
331
- - spec/lib/moose_inventory/cli/group_addchild_spec.rb
332
- - spec/lib/moose_inventory/cli/group_addhost_spec.rb
333
- - spec/lib/moose_inventory/cli/group_addvar_spec.rb
334
- - spec/lib/moose_inventory/cli/group_get_spec.rb
335
- - spec/lib/moose_inventory/cli/group_list_spec.rb
336
- - spec/lib/moose_inventory/cli/group_listvar_spec.rb
337
- - spec/lib/moose_inventory/cli/group_rm_spec.rb
338
- - spec/lib/moose_inventory/cli/group_rmchild_spec.rb
339
- - spec/lib/moose_inventory/cli/group_rmhost_spec.rb
340
- - spec/lib/moose_inventory/cli/group_rmvar_spec.rb
341
- - spec/lib/moose_inventory/cli/group_spec.rb
342
- - spec/lib/moose_inventory/cli/host_add_spec.rb
343
- - spec/lib/moose_inventory/cli/host_addgroup_spec.rb
344
- - spec/lib/moose_inventory/cli/host_addvar_spec.rb
345
- - spec/lib/moose_inventory/cli/host_get_spec.rb
346
- - spec/lib/moose_inventory/cli/host_list_spec.rb
347
- - spec/lib/moose_inventory/cli/host_listvar_spec.rb
348
- - spec/lib/moose_inventory/cli/host_rm_spec.rb
349
- - spec/lib/moose_inventory/cli/host_rmgroup_spec.rb
350
- - spec/lib/moose_inventory/cli/host_rmvar_spec.rb
351
- - spec/lib/moose_inventory/cli/host_spec.rb
352
- - spec/lib/moose_inventory/config/config_spec.rb
353
- - spec/lib/moose_inventory/db/db_spec.rb
354
- - spec/lib/moose_inventory/db/models_spec.rb
355
- - spec/shared/shared_config_setup.rb
356
- - spec/spec_helper.rb
484
+ test_files: []