moose-inventory 1.0.9 → 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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +15 -1
  3. data/.github/workflows/release.yml +58 -0
  4. data/.gitleaks.toml +9 -0
  5. data/.rubocop.yml +28 -0
  6. data/BACKLOG.md +130 -24
  7. data/Gemfile.lock +36 -1
  8. data/README.md +26 -6
  9. data/Rakefile +1 -1
  10. data/docs/release/publishing.md +44 -48
  11. data/docs/release/release-readiness.md +14 -0
  12. data/docs/security-audit-2026-05-26-rerun.md +75 -0
  13. data/docs/security-audit-2026-05-26.md +63 -0
  14. data/lib/moose_inventory/cli/group.rb +3 -0
  15. data/lib/moose_inventory/cli/group_add.rb +89 -73
  16. data/lib/moose_inventory/cli/group_addchild.rb +77 -60
  17. data/lib/moose_inventory/cli/group_addhost.rb +78 -65
  18. data/lib/moose_inventory/cli/group_rm.rb +101 -71
  19. data/lib/moose_inventory/cli/group_rmchild.rb +99 -53
  20. data/lib/moose_inventory/cli/group_rmhost.rb +64 -56
  21. data/lib/moose_inventory/cli/helpers.rb +76 -0
  22. data/lib/moose_inventory/cli/host.rb +3 -0
  23. data/lib/moose_inventory/cli/host_add.rb +47 -62
  24. data/lib/moose_inventory/cli/host_addgroup.rb +73 -64
  25. data/lib/moose_inventory/cli/host_rmgroup.rb +58 -55
  26. data/lib/moose_inventory/db/db.rb +27 -7
  27. data/lib/moose_inventory/inventory_context.rb +50 -0
  28. data/lib/moose_inventory/operations/add_associations.rb +127 -0
  29. data/lib/moose_inventory/operations/add_groups.rb +115 -0
  30. data/lib/moose_inventory/operations/add_hosts.rb +110 -0
  31. data/lib/moose_inventory/operations/group_child_relations.rb +118 -0
  32. data/lib/moose_inventory/operations/group_cleanup.rb +55 -0
  33. data/lib/moose_inventory/operations/remove_associations.rb +101 -0
  34. data/lib/moose_inventory/operations/remove_groups.rb +79 -0
  35. data/lib/moose_inventory/version.rb +1 -1
  36. data/moose-inventory.gemspec +3 -0
  37. data/scripts/check.sh +2 -0
  38. data/scripts/ci/check_permissions.sh +3 -0
  39. data/scripts/ci/check_rubocop.sh +28 -0
  40. data/scripts/ci/check_secrets.sh +26 -0
  41. data/scripts/ci/check_security.sh +18 -0
  42. data/scripts/ci/install_security_tools.sh +47 -0
  43. data/scripts/install_dependencies.sh +2 -0
  44. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +40 -0
  45. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +45 -0
  46. data/spec/lib/moose_inventory/db/db_spec.rb +162 -0
  47. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +77 -0
  48. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +65 -0
  49. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +69 -0
  50. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +76 -0
  51. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +78 -0
  52. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +57 -0
  53. metadata +90 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bba43a0d585b334c19629209ae0f323d88ac1c618de4a926769765a5146933b7
4
- data.tar.gz: 701d64c584a0e0d10266466a94350aa69731a15f623ca37f9edac917c5dd2a38
3
+ metadata.gz: 9740a165b6ef321e367391e80f09876ad3028230b30d27fa62357adeb9cf35ed
4
+ data.tar.gz: d02659ba937e0bf50f8357803d0f04028da75c7a6e190db3b03119d01b9a461a
5
5
  SHA512:
6
- metadata.gz: ef297abb3d7836f1c7f1a20d46a1f79eee14957a74651628fa2fa523ffd5ed26de9f374e551ae861cd8b68d6cc1a646fba52a85209929b2259a078b2409b1a9f
7
- data.tar.gz: d9cfa2e8a85065415858a47aa4e2e1878483e8e982bda25a9d37f05f61c0373e7b7b6bd4ec0f1ba9f0ac3dcf9f796b458c96f794f29466e91aed179a0b6293af
6
+ metadata.gz: 8e6c10ad4baa0694035f230787cf564ba95be6eacf17a70c156cdf327cf0cd134b8924d2f5c5427c5f4ed725b46f116e1bcf89f389f8d9f3ce5a2222b6c6d461
7
+ data.tar.gz: dd88578501502714954c6c4674120e6eeb0b7b05116c9dd78edc97c7abb51a306290bdfc8b7c30caba75464a81315fd294e55c9e16d3b9c696817674a4b68f35
@@ -1,6 +1,7 @@
1
1
  name: CI
2
2
 
3
3
  on:
4
+ workflow_dispatch:
4
5
  push:
5
6
  branches: [master]
6
7
  pull_request:
@@ -9,6 +10,7 @@ on:
9
10
  permissions:
10
11
  contents: read
11
12
 
13
+
12
14
  jobs:
13
15
  test:
14
16
  runs-on: ubuntu-latest
@@ -18,7 +20,7 @@ jobs:
18
20
  ruby-version: ['3.2', '3.3', '3.4']
19
21
  steps:
20
22
  - name: Check out repository
21
- uses: actions/checkout@v4
23
+ uses: actions/checkout@v5
22
24
 
23
25
  - name: Set up Ruby
24
26
  uses: ruby/setup-ruby@v1
@@ -26,10 +28,22 @@ jobs:
26
28
  ruby-version: ${{ matrix.ruby-version }}
27
29
  bundler-cache: true
28
30
 
31
+ - name: Set up Go for security tools
32
+ uses: actions/setup-go@v6
33
+ with:
34
+ go-version: '1.25.x'
35
+ cache: false
36
+
29
37
  - name: Install native build dependencies
38
+ timeout-minutes: 5
30
39
  run: |
31
40
  sudo apt-get update
32
41
  sudo apt-get install -y build-essential default-libmysqlclient-dev libpq-dev libsqlite3-dev
33
42
 
43
+ - name: Install security audit tools
44
+ run: ./scripts/ci/install_security_tools.sh
45
+
34
46
  - name: Run local check gate
47
+ env:
48
+ MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS: '1'
35
49
  run: ./scripts/check.sh
@@ -0,0 +1,58 @@
1
+ name: Release gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write
11
+
12
+ jobs:
13
+ push:
14
+ runs-on: ubuntu-latest
15
+ environment: release
16
+ steps:
17
+ - name: Check out repository
18
+ uses: actions/checkout@v5
19
+ with:
20
+ persist-credentials: false
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: '3.4'
26
+ bundler-cache: true
27
+
28
+ - name: Set up Go for security tools
29
+ uses: actions/setup-go@v6
30
+ with:
31
+ go-version: '1.25.x'
32
+ cache: false
33
+
34
+ - name: Install native build dependencies
35
+ timeout-minutes: 5
36
+ run: |
37
+ sudo apt-get update
38
+ sudo apt-get install -y build-essential default-libmysqlclient-dev libpq-dev libsqlite3-dev
39
+
40
+ - name: Install security audit tools
41
+ run: ./scripts/ci/install_security_tools.sh
42
+
43
+ - name: Verify tag matches gem version
44
+ run: |
45
+ version="$(ruby -e "require './lib/moose_inventory/version'; puts Moose::Inventory::VERSION")"
46
+ tag="${GITHUB_REF_NAME#v}"
47
+ if [ "$tag" != "$version" ]; then
48
+ echo "Tag v$tag does not match gem version $version" >&2
49
+ exit 1
50
+ fi
51
+
52
+ - name: Run local check gate
53
+ env:
54
+ MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS: '1'
55
+ run: ./scripts/check.sh
56
+
57
+ - name: Publish gem to RubyGems
58
+ uses: rubygems/release-gem@v1
data/.gitleaks.toml ADDED
@@ -0,0 +1,9 @@
1
+ title = "moose-inventory gitleaks config"
2
+
3
+ [allowlist]
4
+ description = "Ignore generated/local audit artifacts that are not part of the packaged source surface."
5
+ paths = [
6
+ '''^\.openclaw-security-audit/''',
7
+ '''^spec/reports/''',
8
+ '''^tmp/''',
9
+ ]
data/.rubocop.yml ADDED
@@ -0,0 +1,28 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 3.2
5
+
6
+ Metrics/AbcSize:
7
+ Max: 32
8
+
9
+ Metrics/MethodLength:
10
+ Max: 25
11
+
12
+ Metrics/CyclomaticComplexity:
13
+ Max: 7
14
+
15
+ Metrics/PerceivedComplexity:
16
+ Max: 8
17
+
18
+ Metrics/BlockLength:
19
+ Exclude:
20
+ - spec/lib/moose_inventory/operations/add_hosts_spec.rb
21
+ - spec/lib/moose_inventory/operations/add_groups_spec.rb
22
+ - spec/lib/moose_inventory/operations/add_associations_spec.rb
23
+ - spec/lib/moose_inventory/operations/remove_associations_spec.rb
24
+ - spec/lib/moose_inventory/operations/group_child_relations_spec.rb
25
+ - spec/lib/moose_inventory/operations/remove_groups_spec.rb
26
+
27
+ Style/Documentation:
28
+ Enabled: false
data/BACKLOG.md CHANGED
@@ -1,18 +1,51 @@
1
1
  # Moose Inventory Release Readiness Backlog
2
2
 
3
- Release readiness status counts: 5 done / 2 open.
3
+ Release readiness status counts: 12 done / 1 open.
4
4
 
5
5
  ## Open
6
6
 
7
- 1. Resolve GitHub Actions Node.js 20 deprecation warning.
8
- - Current CI passes, but GitHub warns that `actions/checkout@v4` is running on Node.js 20 and Node.js 24 will become the default.
9
- - Review available `actions/checkout` updates or GitHub-recommended configuration, then update the workflow so CI stays warning-free before Node.js 20 removal.
7
+ 1. Verify RubyGems trusted publishing with the next real release tag.
8
+ - RubyGems trusted publisher is configured for repository `RusDavies/moose-inventory`, workflow `release.yml`, and environment `release`.
9
+ - Verify the full trusted-publishing path when publishing the next real version tag.
10
+ - Do not retag already-published `v1.0.9`.
11
+
12
+ ## Done
13
+
14
+ 1. Align release workflow with required CI security tooling.
15
+ - Security audit rerun found that `.github/workflows/release.yml` ran `./scripts/check.sh` without installing or requiring the dedicated security tools, meaning tag-based releases could skip `gitleaks`/`osv-scanner` enforcement if those tools were absent.
16
+ - Added Go setup with cache disabled, installed pinned security tools through `scripts/ci/install_security_tools.sh`, required `MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS=1` during the release check gate, and added the same native-dependency timeout used by CI.
17
+ - Documented the rerun in `docs/security-audit-2026-05-26-rerun.md`; final trusted-publishing proof remains gated on the next real release tag.
18
+
19
+ 1. Add manual GitHub Actions CI trigger and harden CI runner setup.
20
+ - Added `workflow_dispatch` to `.github/workflows/ci.yml` so CI can be manually triggered when push events fail to enqueue during a GitHub Actions incident.
21
+ - Verified both push-triggered CI and manual `workflow_dispatch` CI runs succeeded on `master`.
22
+ - Disabled unused `actions/setup-go` caching for the Go-based security tools so the workflow no longer emits a missing-`go.mod` cache warning.
23
+ - Added a timeout to the native dependency installation step so runner package-manager stalls fail fast instead of hanging the matrix indefinitely.
24
+
25
+ 1. Diagnose missing GitHub Actions runs after security-tooling merge.
26
+ - Confirmed the affected commits were pushed and visible on GitHub, with GitHub PushEvents recorded but no check runs created.
27
+ - Confirmed the workflow was active and visible, and GitHub Actions was degraded during the missing-run window due to platform-side authentication/startup issues.
28
+ - Conclusion: the missing runs were caused by a GitHub Actions incident, not by the repository workflow configuration.
29
+
30
+ 1. Install optional local/CI security audit tools.
31
+ - Added `bundler-audit` as a development dependency and wired it into `scripts/ci/check_security.sh`.
32
+ - Added `scripts/ci/install_security_tools.sh` to install pinned `gitleaks` and `osv-scanner` CLI tools into `tmp/security-tools/bin` when they are not already on `PATH`.
33
+ - Added `scripts/ci/check_secrets.sh` and `.gitleaks.toml` so generated audit, coverage, and package-sanity artifacts stay out of dedicated secret scans.
34
+ - Updated GitHub Actions CI to install the Go-based audit tools and require them during `./scripts/check.sh`; local runs skip missing optional tools unless `MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS=1` is set.
35
+
36
+ 1. Configure RubyGems trusted publisher for the existing gem.
37
+ - Repository-side trusted publishing workflow is present in `.github/workflows/release.yml`.
38
+ - RubyGems trusted publisher is configured for the `moose-inventory` gem with repository `RusDavies/moose-inventory`, workflow `release.yml`, and environment `release`.
39
+ - Evidence: RubyGems trusted publisher page shows GitHub Actions for `RusDavies/moose-inventory`, workflow `release.yml`, environment `release`.
10
40
 
11
41
  1. Add GitHub Actions RubyGems trusted publishing.
12
- - Manual publishing is documented in `docs/release/publishing.md`.
13
- - Future improvement: configure RubyGems trusted publishing, publish from reviewed `v*` tags, and avoid long-lived RubyGems API keys on developer machines.
42
+ - Added `.github/workflows/release.yml` triggered by `v*` tags.
43
+ - The workflow verifies the tag matches `Moose::Inventory::VERSION`, runs `./scripts/check.sh`, and publishes with `rubygems/release-gem@v1` using OIDC/trusted publishing.
44
+ - Updated `docs/release/publishing.md` and `docs/release/release-readiness.md` with trusted publishing release instructions and RubyGems setup requirements.
14
45
 
15
- ## Done
46
+ 1. Resolve GitHub Actions Node.js 20 deprecation warning.
47
+ - Updated the CI workflow to use `actions/checkout@v5`, which runs on the Node.js 24 runtime.
48
+ - Verified with full `./scripts/check.sh` and a post-merge GitHub Actions run with no Node.js 20 deprecation annotations.
16
49
 
17
50
  1. Decide and declare the supported Ruby version floor.
18
51
  - Set `spec.required_ruby_version` to `>= 3.2` in the gemspec.
@@ -41,33 +74,38 @@ Release readiness status counts: 5 done / 2 open.
41
74
 
42
75
  # Moose Inventory GitHub Issues Backlog
43
76
 
44
- GitHub issues status counts: 0 done / 4 open.
77
+ GitHub issues status counts: 4 done / 0 open.
45
78
 
46
79
  ## Open
47
80
 
48
- 1. [#14 Passwords in config files](https://github.com/RusDavies/moose-inventory/issues/14)
49
- - README examples currently show database passwords stored directly in configuration files.
50
- - Determine whether Moose Inventory supports reading credentials from environment variables today.
51
- - If not, decide whether to add environment-variable credential support or at least document safer credential-handling guidance.
52
- - Update README/config examples so they do not accidentally encourage secret-in-repo bad practice.
81
+ _No open GitHub issue items._
82
+
83
+ ## Done
53
84
 
54
85
  1. [#13 Need to refactor](https://github.com/RusDavies/moose-inventory/issues/13)
55
- - CLI command modules contain similar methods across host/group operations, for example `GroupAdd` and `HostAdd`-style flows.
56
- - Existing code has historically needed complexity metric disables such as `Metrics/AbcSize` and `Metrics/CyclomaticComplexity`.
57
- - Evaluate cost/benefit before doing a broad refactor; identify specific low-risk extraction targets and regression coverage needed.
86
+ - Added shared `Moose::Inventory::Cli::Helpers` for command argument validation, name normalization, CSV option parsing, automatic `ungrouped` validation, association checks, and automatic group membership maintenance.
87
+ - Refactored representative host/group association commands to use the helper layer while preserving existing CLI output and behavior.
88
+ - Verified with focused CLI specs and full `./scripts/check.sh`.
58
89
 
59
90
  1. [#12 Allow `group rm` to recursively delete orphaned child groups](https://github.com/RusDavies/moose-inventory/issues/12)
60
- - Decide product semantics for recursive group deletion: default behavior, explicit switch, safety prompts/flags, and how to distinguish intentional tree deletion from accidental orphan cleanup.
61
- - If implemented, add tests for `group rm` and `group rmchild` orphan-child behavior, root-group handling, and host `ungrouped` behavior.
91
+ - Kept default deletion conservative: `group rm NAME` removes only the named group and preserves child groups as root groups.
92
+ - Added explicit `group rm --recursive NAME` to delete descendant groups only when they become orphaned by the removal.
93
+ - Added explicit `group rmchild --delete-orphans PARENT CHILD...` to remove parent-child associations and delete orphaned child subtrees.
94
+ - Preserved groups that still have another parent outside the removed edge/subtree.
95
+ - Preserved host safety by moving hosts whose last group is deleted to `ungrouped`.
96
+ - Added regression coverage for recursive deletion, shared-parent preservation, and host fallback to `ungrouped`.
62
97
 
63
98
  1. [#4 `--trace` doesn't do what it claims](https://github.com/RusDavies/moose-inventory/issues/4)
64
- - Reproduce current `--trace` behavior and confirm whether exceptions/backtraces are still truncated.
65
- - Fix trace handling so transaction errors emit useful full exception/backtrace information when `--trace` is enabled while preserving concise default errors.
66
- - Add regression coverage for both trace and non-trace error output.
67
-
68
- ## Done
99
+ - Reproduced the broken trace path: `--trace` attempted to print `$ERROR_INFO.backtrace` without requiring `English`, causing a secondary `NoMethodError` instead of a clean trace dump.
100
+ - Fixed Moose DB transaction trace handling to emit the actual exception full message/backtrace while preserving concise default errors.
101
+ - Added regression coverage for both trace and non-trace Moose DB transaction errors.
102
+ - Verified with full `./scripts/check.sh`.
69
103
 
70
- _No GitHub issue backlog items completed yet._
104
+ 1. [#14 Passwords in config files](https://github.com/RusDavies/moose-inventory/issues/14)
105
+ - Added `password_env` support for MySQL and PostgreSQL database configuration while preserving the existing `password` key for compatibility.
106
+ - Added regression coverage for missing password configuration, unset password environment variables, and environment-backed MySQL/PostgreSQL connection passwords.
107
+ - Updated README examples to use `password_env` instead of plaintext sample passwords and added credential-handling guidance.
108
+ - Verified with full `./scripts/check.sh`.
71
109
 
72
110
  ---
73
111
 
@@ -182,3 +220,71 @@ _No open modernization items._
182
220
  - Ansible-mode CLI specs now pass the fixture config when invoking the top-level CLI.
183
221
  - Updated the `--list` expectation for Ansible mode, which correctly includes empty `hosts` arrays.
184
222
  - Verified `bundle exec rspec --format documentation`: 242 examples, 0 failures; line coverage 95.16%.
223
+
224
+ ---
225
+
226
+ # Moose Inventory Code Quality Backlog
227
+
228
+ Code quality status counts: 10 done / 0 open.
229
+
230
+ ## Open
231
+
232
+ _No open code quality items._
233
+
234
+
235
+ ## Done
236
+
237
+ 1. Extract `group rm` to reuse the new group-cleanup / relation-operation seam.
238
+ - Added `Moose::Inventory::Operations::RemoveGroups` and reused `GroupCleanup` so top-level group deletion, recursive orphan cleanup, and host `ungrouped` reattachment now run through structured operation events instead of bespoke Thor logic.
239
+ - Converted `group rm` into a thinner adapter over `InventoryContext`, preserving `--recursive` behavior and existing CLI output.
240
+ - Added direct operation specs and expanded the targeted RuboCop gate to cover the new removal operation and adapter.
241
+ - Verified with focused specs and full `./scripts/check.sh`.
242
+
243
+ 1. Extract the shared group-parent/child association flow behind `group addchild` and `group rmchild`.
244
+ - Added `Moose::Inventory::Operations::GroupChildRelations` and `GroupCleanup` to own parent/child link creation, dissociation, and recursive orphan-group cleanup with structured events.
245
+ - Converted `group addchild` and `group rmchild` into thinner adapters over `InventoryContext`, including `--delete-orphans` behavior without leaving the recursion logic buried in the CLI layer.
246
+ - Added direct operation specs and expanded the targeted RuboCop gate to cover the new parent/child relation seam.
247
+ - Verified with focused specs and full `./scripts/check.sh`.
248
+
249
+ 1. Extract the shared host/group dissociation flow behind `host rmgroup` and `group rmhost`.
250
+ - Added `Moose::Inventory::Operations::RemoveAssociations` to own shared dissociation, missing-association handling, and automatic `ungrouped` reattachment behavior for existing primary entities.
251
+ - Converted `host rmgroup` and `group rmhost` into thinner adapters that retrieve the primary entity, delegate through `InventoryContext`, and render structured operation events.
252
+ - Added direct operation specs and expanded the targeted RuboCop gate to cover the new removal operation plus both adapter commands.
253
+ - Verified with focused specs and full `./scripts/check.sh`.
254
+
255
+ 1. Extract the shared host/group association flow behind `host addgroup` and `group addhost`.
256
+ - Added `Moose::Inventory::Operations::AddAssociations` to own the shared association, auto-create, duplicate-check, and `ungrouped` removal behavior for existing primary entities.
257
+ - Converted `host addgroup` and `group addhost` into thinner adapters that retrieve the primary entity, delegate through `InventoryContext`, and render structured operation events.
258
+ - Added direct operation specs and expanded the targeted RuboCop gate to cover the new operation plus both adapter commands.
259
+ - Verified with focused specs and full `./scripts/check.sh`.
260
+
261
+ 1. Extract `group add` into the operation/context/event pattern.
262
+ - Added `Moose::Inventory::Operations::AddGroups` with structured result/events and warning counts, mirroring the `host add` refactor pattern.
263
+ - Converted `group add` into a thin Thor adapter that validates input, delegates through `InventoryContext`, and renders operation events without changing CLI behavior.
264
+ - Added direct operation specs and extended the targeted RuboCop scope to cover the new operation/adapter/spec files.
265
+ - Verified with focused specs and full `./scripts/check.sh`.
266
+
267
+ 1. Reintroduce a small modern lint/complexity gate.
268
+ - Added RuboCop as a development dependency and a targeted `.rubocop.yml` for the newly refactored seam instead of the whole legacy tree.
269
+ - Added `scripts/ci/check_rubocop.sh` and wired it into `./scripts/check.sh` so lint/complexity checks run in the standard local and CI gate.
270
+ - Kept the initial lint scope focused on the context/operation/helper/adapter files and direct operation spec, with thresholds strict enough to catch drift without forcing a repo-wide cleanup right now.
271
+
272
+ 1. Separate first structured operation result from CLI rendering.
273
+ - Changed `Moose::Inventory::Operations::AddHosts` to return structured `Result`/`Event` objects instead of writing directly to stdout/stderr.
274
+ - Moved `host add` progress/warning rendering into the Thor adapter while preserving existing user-visible CLI output.
275
+ - Added direct operation specs proving inventory mutation and event emission without renderer output.
276
+ - Verified with focused specs and full `./scripts/check.sh`.
277
+
278
+ 1. Introduce an inventory context facade around DB access.
279
+ - Added `Moose::Inventory::InventoryContext` as a thin wrapper over the existing DB singleton for transaction/model operations.
280
+ - Wired the `AddHosts` operation through the context, reducing direct DB coupling in the first extracted operation while leaving legacy CLI commands stable.
281
+ - Verified with focused `host add` specs and full `./scripts/check.sh`.
282
+
283
+ 1. Extract first domain operation behind a Thor command.
284
+ - Added `Moose::Inventory::Operations::AddHosts` as the first operation/service object behind the CLI.
285
+ - Converted `host add` into a thin adapter that validates/normalizes CLI input and delegates inventory mutation to the operation.
286
+ - Preserved existing `host add` output and behavior under focused specs and full `./scripts/check.sh`.
287
+
288
+ 1. Extract shared CLI helpers for low-risk issue #13 refactor.
289
+ - Added helper methods for common validation, normalization, association checks, and automatic `ungrouped` membership handling.
290
+ - Refactored selected host/group CLI commands without changing user-visible output.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moose-inventory (1.0.9)
4
+ moose-inventory (2.0)
5
5
  indentation (~> 0)
6
6
  json (>= 2.7, < 3)
7
7
  mysql2 (>= 0.5.7, < 0.6)
@@ -13,15 +13,29 @@ PATH
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
+ ast (2.4.3)
16
17
  bigdecimal (4.1.2)
18
+ bundler-audit (0.9.3)
19
+ bundler (>= 1.2.0)
20
+ thor (~> 1.0)
17
21
  diff-lcs (1.6.2)
18
22
  docile (1.4.1)
19
23
  indentation (0.1.1)
20
24
  json (2.19.5)
25
+ language_server-protocol (3.17.0.5)
26
+ lint_roller (1.1.0)
21
27
  mysql2 (0.5.7)
22
28
  bigdecimal
29
+ parallel (1.28.0)
30
+ parser (3.3.11.1)
31
+ ast (~> 2.4.1)
32
+ racc
23
33
  pg (1.6.3-x86_64-linux)
34
+ prism (1.9.0)
35
+ racc (1.8.1)
36
+ rainbow (3.1.1)
24
37
  rake (13.4.2)
38
+ regexp_parser (2.12.0)
25
39
  rspec (3.13.2)
26
40
  rspec-core (~> 3.13.0)
27
41
  rspec-expectations (~> 3.13.0)
@@ -35,6 +49,21 @@ GEM
35
49
  diff-lcs (>= 1.2.0, < 2.0)
36
50
  rspec-support (~> 3.13.0)
37
51
  rspec-support (3.13.7)
52
+ rubocop (1.86.2)
53
+ json (~> 2.3)
54
+ language_server-protocol (~> 3.17.0.2)
55
+ lint_roller (~> 1.1.0)
56
+ parallel (>= 1.10)
57
+ parser (>= 3.3.0.2)
58
+ rainbow (>= 2.2.2, < 4.0)
59
+ regexp_parser (>= 2.9.3, < 3.0)
60
+ rubocop-ast (>= 1.49.0, < 2.0)
61
+ ruby-progressbar (~> 1.7)
62
+ unicode-display_width (>= 2.4.0, < 4.0)
63
+ rubocop-ast (1.49.1)
64
+ parser (>= 3.3.7.2)
65
+ prism (~> 1.7)
66
+ ruby-progressbar (1.13.0)
38
67
  sequel (5.104.0)
39
68
  bigdecimal
40
69
  simplecov (0.22.0)
@@ -45,15 +74,21 @@ GEM
45
74
  simplecov_json_formatter (0.1.4)
46
75
  sqlite3 (2.9.4-x86_64-linux-gnu)
47
76
  thor (1.5.0)
77
+ unicode-display_width (3.2.0)
78
+ unicode-emoji (~> 4.1)
79
+ unicode-emoji (4.2.0)
48
80
 
49
81
  PLATFORMS
50
82
  x86_64-linux
51
83
 
52
84
  DEPENDENCIES
53
85
  bundler (>= 2.2.33, < 3)
86
+ bundler-audit (>= 0.9, < 1)
54
87
  moose-inventory!
88
+ parallel (>= 1.10, < 2.0)
55
89
  rake (>= 13.0, < 14)
56
90
  rspec (~> 3)
91
+ rubocop (>= 1.72, < 2)
57
92
  simplecov (~> 0)
58
93
 
59
94
  BUNDLED WITH
data/README.md CHANGED
@@ -56,7 +56,7 @@ moose_ops:
56
56
  host: "localhost"
57
57
  database: "water"
58
58
  user: "duck"
59
- password: "quack"
59
+ password_env: "MOOSE_INVENTORY_MYSQL_PASSWORD"
60
60
 
61
61
  another_example_section:
62
62
  db:
@@ -64,7 +64,7 @@ another_example_section:
64
64
  host: "localhost"
65
65
  database: "grass"
66
66
  user: "cow"
67
- password: "moo"
67
+ password_env: "MOOSE_INVENTORY_POSTGRES_PASSWORD"
68
68
 
69
69
  ```
70
70
 
@@ -78,7 +78,16 @@ At present, each environment section contains only a **db** subsection, describ
78
78
 
79
79
  Each **db** section must include an **adapter** parameter. Currently supported adapter types are *sqlite3*, *mysql*, and *postgresql*. The test suite exercises SQLite with a local database file and includes adapter dispatch/error-path smoke coverage for MySQL and PostgreSQL without requiring live database servers.
80
80
 
81
- Additional parameters are also required in the **db** subsection, depending on the adapter type. For the *sqlite3* adapter only a **file** parameter is required; parent directories are created automatically. For both *mysql* and *postgresql*, **host**, **database**, **user**, and **password** are required.
81
+ Additional parameters are also required in the **db** subsection, depending on the adapter type. For the *sqlite3* adapter only a **file** parameter is required; parent directories are created automatically. For both *mysql* and *postgresql*, **host**, **database**, **user**, and either **password_env** or **password** are required.
82
+
83
+ Prefer **password_env** for MySQL and PostgreSQL configuration. Its value is the name of an environment variable that contains the database password, which keeps reusable configuration files from carrying plaintext credentials:
84
+
85
+ ```sh
86
+ export MOOSE_INVENTORY_MYSQL_PASSWORD='use-a-real-secret-here'
87
+ moose-inventory --env moose_ops host list
88
+ ```
89
+
90
+ The older **password** key is still supported for compatibility, but avoid committing configuration files that contain database passwords. If you must use **password**, keep that configuration file outside version control and restrict its file permissions.
82
91
 
83
92
 
84
93
  ## Usage
@@ -303,10 +312,14 @@ We can also list hosts, to get the host-centric view.
303
312
  - group2
304
313
  - group3
305
314
 
306
- Removing variables, groups, and hosts is just as easy. In the following examples, the output is again omitted for compactness; the reader is encouraged to work along to experience the tool. Note, that although we show how to remove the variables, it is not strictly necessary to do so in this example, since deleting hosts and groups would delete all associated variables anyway.
315
+ Removing variables, groups, and hosts is just as easy. In the following examples, the output is again omitted for compactness; the reader is encouraged to work along to experience the tool. Note, that although we show how to remove the variables, it is not strictly necessary to do so in this example, since deleting hosts and groups would delete all associated variables anyway.
316
+
317
+ By default, deleting a group preserves its child groups as root groups. Use `group rm --recursive` when child groups that become orphaned should also be deleted. Similarly, `group rmchild --delete-orphans` removes a parent-child association and deletes the child subtree only when it becomes orphaned by that removal. Hosts whose last group is deleted are automatically moved to `ungrouped`.
307
318
 
308
319
  $ moose-inventory group rmvar group1 location
309
320
  $ moose-inventory group rm group1 group2 group3
321
+ $ moose-inventory group rm --recursive old_parent_group
322
+ $ moose-inventory group rmchild --delete-orphans parent_group child_group
310
323
  $ moose-inventory host rmvar
311
324
  $ moose-inventory host rmvar host1 owner id
312
325
  $ moose-inventory host rm host1 host2 host3
@@ -371,7 +384,15 @@ Run the local verification gate before committing changes:
371
384
  ./scripts/check.sh
372
385
  ```
373
386
 
374
- The check script runs the RSpec suite and enforces the SimpleCov coverage minimum.
387
+ The check script runs the RSpec suite, enforces the SimpleCov coverage minimum, checks file permissions, queries OSV for locked RubyGems advisories, runs `bundler-audit`, runs `gitleaks` when available, and builds/smoke-tests the packaged gem.
388
+
389
+ Optional Go-based security tools used by CI can be installed locally with:
390
+
391
+ ```shell
392
+ ./scripts/ci/install_security_tools.sh
393
+ ```
394
+
395
+ That installs `gitleaks` and `osv-scanner` into `tmp/security-tools/bin` unless they are already on `PATH`. Fedora users can also run `./scripts/install_dependencies.sh` to install the native build dependencies and packaged `gitleaks`; `bundler-audit` is installed through Bundler.
375
396
 
376
397
  ## Contributing
377
398
  1. Fork it (https://github.com/RusDavies/moose-inventory/fork )
@@ -389,4 +410,3 @@ The check script runs the RSpec suite and enforces the SimpleCov coverage minimu
389
410
 
390
411
 
391
412
 
392
-
data/Rakefile CHANGED
@@ -1 +1 @@
1
-
1
+ require 'bundler/gem_tasks'
@@ -1,14 +1,24 @@
1
1
  # Publishing to RubyGems
2
2
 
3
- This project has historically been published manually to RubyGems as [`moose-inventory`](https://rubygems.org/gems/moose-inventory).
3
+ This project is published to RubyGems as [`moose-inventory`](https://rubygems.org/gems/moose-inventory).
4
4
 
5
- At the time this document was added:
5
+ The preferred publishing path is GitHub Actions trusted publishing from reviewed `v*` tags. Manual publishing remains documented as a fallback only.
6
6
 
7
- - The latest published RubyGems version was `1.0.8`.
8
- - The repository version was `1.0.9` in `lib/moose_inventory/version.rb`.
9
- - The repository had CI for checks, but no GitHub Actions publishing workflow.
7
+ ## Trusted publishing setup
10
8
 
11
- ## Release checklist
9
+ The repository side is `.github/workflows/release.yml`.
10
+
11
+ RubyGems has a trusted publisher configured for the existing `moose-inventory` gem on RubyGems.org with these values:
12
+
13
+ - Repository owner: `RusDavies`
14
+ - Repository name: `moose-inventory`
15
+ - Workflow filename: `release.yml`
16
+ - Environment: `release`
17
+ - Workflow repository owner/name: blank, because the workflow lives in this repository
18
+
19
+ The release workflow requires the GitHub environment name `release`. If that environment has protection rules, approve the deployment when releasing.
20
+
21
+ ## Trusted publishing release checklist
12
22
 
13
23
  1. Start from a clean `master` branch.
14
24
 
@@ -25,7 +35,7 @@ At the time this document was added:
25
35
  gem info moose-inventory --remote --all
26
36
  ```
27
37
 
28
- If the repository version is already higher than the latest RubyGems version, you can publish it as-is after checks pass. If not, bump `lib/moose_inventory/version.rb` first and commit that change before publishing.
38
+ If the repository version is not higher than the latest RubyGems version, bump `lib/moose_inventory/version.rb` first and commit that change before releasing.
29
39
 
30
40
  3. Run the local release gate.
31
41
 
@@ -33,56 +43,58 @@ At the time this document was added:
33
43
  ./scripts/check.sh
34
44
  ```
35
45
 
36
- This runs the spec suite, whitespace checks, executable-permission checks, OSV dependency advisory checks, and gem package sanity checks.
37
-
38
46
  4. Push the release commit and wait for CI to pass.
39
47
 
40
48
  ```bash
41
49
  git push origin master
42
50
  ```
43
51
 
44
- Do not publish to RubyGems until the GitHub Actions CI run for the pushed commit is green.
45
-
46
- 5. Build the gem from the exact commit you intend to release.
52
+ 5. Create and push the release tag from the exact commit to publish.
47
53
 
48
54
  ```bash
49
- rm -rf pkg tmp/pkg tmp/package-sanity
50
- gem build moose-inventory.gemspec
55
+ git tag -a v1.0.10 -m "Release moose-inventory 1.0.10"
56
+ git push origin v1.0.10
51
57
  ```
52
58
 
53
- The output should be named like `moose-inventory-1.0.9.gem`.
54
-
55
- 6. Inspect the built gem metadata if desired.
59
+ 6. Watch the `Release gem` workflow.
56
60
 
57
61
  ```bash
58
- gem specification moose-inventory-1.0.9.gem name version executables require_paths files --yaml
62
+ gh run list --workflow release.yml --limit 5
63
+ gh run watch <run-id> --exit-status
59
64
  ```
60
65
 
61
- 7. Publish to RubyGems.
66
+ The workflow verifies that the pushed tag version matches `Moose::Inventory::VERSION`, runs `./scripts/check.sh`, builds the gem through `rubygems/release-gem@v1`, and publishes using RubyGems trusted publishing/OIDC. No RubyGems API key should be stored in GitHub secrets for this workflow.
62
67
 
63
- ```bash
64
- gem push moose-inventory-1.0.9.gem
65
- ```
68
+ ## Verify the published version
66
69
 
67
- If RubyGems auth is not already configured, `gem push` will prompt for credentials or an API key.
70
+ After the workflow succeeds:
71
+
72
+ ```bash
73
+ gem info moose-inventory --remote --all
74
+ gem install moose-inventory -v 1.0.10
75
+ moose-inventory --help
76
+ ```
68
77
 
69
- 8. Verify the published version.
78
+ Use the actual released version in place of `1.0.10`.
79
+
80
+ ## Manual fallback
81
+
82
+ Manual publishing should only be used if trusted publishing is unavailable and a RubyGems owner explicitly chooses to publish from a local machine.
83
+
84
+ 1. Run `./scripts/check.sh`.
85
+ 2. Build the gem from the exact commit intended for release.
70
86
 
71
87
  ```bash
72
- gem info moose-inventory --remote --all
73
- gem install moose-inventory -v 1.0.9
74
- moose-inventory --help
88
+ rm -rf pkg tmp/pkg tmp/package-sanity
89
+ gem build moose-inventory.gemspec
75
90
  ```
76
91
 
77
- 9. Tag the release after RubyGems confirms it is live.
92
+ 3. Push the built gem.
78
93
 
79
94
  ```bash
80
- git tag -a v1.0.9 -m "Release v1.0.9"
81
- git push origin v1.0.9
95
+ gem push moose-inventory-1.0.10.gem
82
96
  ```
83
97
 
84
- ## Authentication notes
85
-
86
98
  Prefer a scoped RubyGems API key over an old global key:
87
99
 
88
100
  - Scope it to pushing gems, ideally only `moose-inventory` if RubyGems permits that for the account.
@@ -95,19 +107,3 @@ Check credential file permissions with:
95
107
  ls -l ~/.gem/credentials
96
108
  chmod 0600 ~/.gem/credentials
97
109
  ```
98
-
99
- ## Current publishing model
100
-
101
- Publishing is manual. There is no automated release workflow in this repository yet.
102
-
103
- A future improvement would be to configure RubyGems trusted publishing through GitHub Actions so releases can be published from a tagged, reviewed workflow without long-lived RubyGems API keys on a developer machine.
104
-
105
- Suggested future workflow:
106
-
107
- 1. Add RubyGems trusted publishing for this repository and gem.
108
- 2. Add a GitHub Actions workflow triggered by `v*` tags.
109
- 3. Have the workflow run `./scripts/check.sh`.
110
- 4. Build the gem.
111
- 5. Publish via trusted publishing only if the tag version matches `Moose::Inventory::VERSION`.
112
-
113
- Until that is implemented, use the manual process above.