moose-inventory 2.0 → 2.1.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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +2 -0
  3. data/.gitignore +6 -1
  4. data/.rubocop.yml +21 -0
  5. data/BACKLOG.md +638 -9
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +1 -1
  8. data/README.md +315 -39
  9. data/Rakefile +2 -0
  10. data/bin/moose-inventory +2 -1
  11. data/docs/architecture/architecture-and-trust-boundaries.md +444 -0
  12. data/docs/compatibility/cli-output-compatibility.md +76 -0
  13. data/docs/governance/approval-register.md +37 -0
  14. data/docs/maintenance/database-backup-restore-guidance.md +162 -0
  15. data/docs/maintenance/package-maintenance-and-agent-boundaries.md +260 -0
  16. data/docs/process/conformance-gap-analysis-2026-05-28.md +192 -0
  17. data/docs/product/product-brief.md +161 -0
  18. data/docs/product/requirements-baseline.md +477 -0
  19. data/docs/qa/qa-documentation-and-release-gates.md +283 -0
  20. data/docs/release/package-provenance-hardening.md +126 -0
  21. data/docs/release/publishing.md +11 -3
  22. data/docs/release/release-environment-protection.md +78 -0
  23. data/docs/release/release-readiness.md +23 -4
  24. data/docs/security/accepted-risk-register.md +84 -0
  25. data/docs/security/security-privacy-process.md +287 -0
  26. data/docs/security-audit-2026-05-26-rerun.md +2 -2
  27. data/docs/security-audit-2026-05-29-snapshot-import-fuzz.md +58 -0
  28. data/docs/ux/cli-workflow-notes.md +287 -0
  29. data/examples/ansible/ansible.cfg +3 -0
  30. data/examples/ansible/inventory/moose_inventory.yml +5 -0
  31. data/examples/ansible/inventory_plugins/moose_inventory.py +100 -0
  32. data/examples/ci/README.md +16 -0
  33. data/examples/ci/github-actions/inventory-review.yml +38 -0
  34. data/examples/ci/inventory/example-snapshot.yml +19 -0
  35. data/examples/ci/scripts/validate-inventory-snapshot.sh +30 -0
  36. data/lib/moose_inventory/cli/application.rb +135 -5
  37. data/lib/moose_inventory/cli/association_rendering.rb +74 -0
  38. data/lib/moose_inventory/cli/association_rendering_support.rb +89 -0
  39. data/lib/moose_inventory/cli/audit.rb +62 -0
  40. data/lib/moose_inventory/cli/audit_recording.rb +40 -0
  41. data/lib/moose_inventory/cli/child_relation_rendering.rb +110 -0
  42. data/lib/moose_inventory/cli/console.rb +135 -0
  43. data/lib/moose_inventory/cli/db.rb +64 -0
  44. data/lib/moose_inventory/cli/factory.rb +28 -0
  45. data/lib/moose_inventory/cli/formatter.rb +8 -12
  46. data/lib/moose_inventory/cli/group.rb +5 -2
  47. data/lib/moose_inventory/cli/group_add.rb +11 -9
  48. data/lib/moose_inventory/cli/group_addchild.rb +23 -65
  49. data/lib/moose_inventory/cli/group_addhost.rb +16 -67
  50. data/lib/moose_inventory/cli/group_addvar.rb +27 -47
  51. data/lib/moose_inventory/cli/group_get.rb +8 -42
  52. data/lib/moose_inventory/cli/group_list.rb +7 -40
  53. data/lib/moose_inventory/cli/group_listvars.rb +9 -55
  54. data/lib/moose_inventory/cli/group_rm.rb +12 -10
  55. data/lib/moose_inventory/cli/group_rmchild.rb +26 -82
  56. data/lib/moose_inventory/cli/group_rmhost.rb +18 -53
  57. data/lib/moose_inventory/cli/group_rmvar.rb +30 -41
  58. data/lib/moose_inventory/cli/group_tags.rb +33 -0
  59. data/lib/moose_inventory/cli/helpers.rb +68 -1
  60. data/lib/moose_inventory/cli/host.rb +6 -3
  61. data/lib/moose_inventory/cli/host_add.rb +69 -29
  62. data/lib/moose_inventory/cli/host_addgroup.rb +22 -58
  63. data/lib/moose_inventory/cli/host_addvar.rb +28 -52
  64. data/lib/moose_inventory/cli/host_get.rb +9 -37
  65. data/lib/moose_inventory/cli/host_list.rb +24 -21
  66. data/lib/moose_inventory/cli/host_listvars.rb +9 -62
  67. data/lib/moose_inventory/cli/host_rm.rb +60 -42
  68. data/lib/moose_inventory/cli/host_rmgroup.rb +25 -44
  69. data/lib/moose_inventory/cli/host_rmvar.rb +31 -45
  70. data/lib/moose_inventory/cli/host_tags.rb +33 -0
  71. data/lib/moose_inventory/cli/listvars_support.rb +55 -0
  72. data/lib/moose_inventory/cli/plan_rendering.rb +50 -0
  73. data/lib/moose_inventory/cli/relation_transaction_support.rb +51 -0
  74. data/lib/moose_inventory/cli/tag_support.rb +97 -0
  75. data/lib/moose_inventory/cli/variable_rendering.rb +67 -0
  76. data/lib/moose_inventory/config/config.rb +185 -108
  77. data/lib/moose_inventory/db/db.rb +170 -195
  78. data/lib/moose_inventory/db/exceptions.rb +6 -3
  79. data/lib/moose_inventory/db/models.rb +16 -0
  80. data/lib/moose_inventory/db/schema_migrations.rb +248 -0
  81. data/lib/moose_inventory/inventory_context.rb +68 -2
  82. data/lib/moose_inventory/operations/add_associations.rb +20 -16
  83. data/lib/moose_inventory/operations/add_groups.rb +21 -13
  84. data/lib/moose_inventory/operations/add_hosts.rb +30 -17
  85. data/lib/moose_inventory/operations/add_variables.rb +77 -0
  86. data/lib/moose_inventory/operations/entity_variable_operation_support.rb +46 -0
  87. data/lib/moose_inventory/operations/group_child_relations.rb +23 -16
  88. data/lib/moose_inventory/operations/group_cleanup.rb +23 -8
  89. data/lib/moose_inventory/operations/import_inventory_snapshot.rb +41 -0
  90. data/lib/moose_inventory/operations/inventory_doctor.rb +172 -0
  91. data/lib/moose_inventory/operations/inventory_snapshot.rb +60 -0
  92. data/lib/moose_inventory/operations/inventory_snapshot_applier.rb +112 -0
  93. data/lib/moose_inventory/operations/inventory_snapshot_preview.rb +174 -0
  94. data/lib/moose_inventory/operations/inventory_snapshot_validator.rb +174 -0
  95. data/lib/moose_inventory/operations/operation_event_support.rb +27 -0
  96. data/lib/moose_inventory/operations/query_inventory/base_query.rb +24 -0
  97. data/lib/moose_inventory/operations/query_inventory/group_queries.rb +86 -0
  98. data/lib/moose_inventory/operations/query_inventory/host_queries.rb +106 -0
  99. data/lib/moose_inventory/operations/query_inventory.rb +47 -0
  100. data/lib/moose_inventory/operations/remove_associations.rb +30 -18
  101. data/lib/moose_inventory/operations/remove_groups.rb +12 -12
  102. data/lib/moose_inventory/operations/remove_hosts.rb +68 -0
  103. data/lib/moose_inventory/operations/remove_variables.rb +67 -0
  104. data/lib/moose_inventory/runtime_options.rb +31 -0
  105. data/lib/moose_inventory/version.rb +3 -1
  106. data/lib/moose_inventory.rb +10 -7
  107. data/moose-inventory.gemspec +19 -35
  108. data/scripts/check.sh +1 -0
  109. data/scripts/ci/check_generated_artifacts.sh +41 -0
  110. data/scripts/ci/check_permissions.sh +2 -0
  111. data/scripts/ci/check_rubocop.sh +30 -25
  112. data/scripts/ci/check_security.sh +4 -1
  113. data/scripts/files.rb +5 -4
  114. data/spec/examples/ci_examples_spec.rb +37 -0
  115. data/spec/lib/moose_inventory/ansible_plugin_examples_spec.rb +29 -0
  116. data/spec/lib/moose_inventory/cli/application_doctor_spec.rb +50 -0
  117. data/spec/lib/moose_inventory/cli/application_import_export_spec.rb +132 -0
  118. data/spec/lib/moose_inventory/cli/application_spec.rb +25 -15
  119. data/spec/lib/moose_inventory/cli/audit_spec.rb +56 -0
  120. data/spec/lib/moose_inventory/cli/cli_spec.rb +15 -19
  121. data/spec/lib/moose_inventory/cli/console_spec.rb +98 -0
  122. data/spec/lib/moose_inventory/cli/factory_spec.rb +27 -0
  123. data/spec/lib/moose_inventory/cli/formatter_spec.rb +95 -3
  124. data/spec/lib/moose_inventory/cli/group_add_spec.rb +140 -116
  125. data/spec/lib/moose_inventory/cli/group_addchild_spec.rb +89 -35
  126. data/spec/lib/moose_inventory/cli/group_addhost_spec.rb +81 -84
  127. data/spec/lib/moose_inventory/cli/group_addvar_spec.rb +65 -68
  128. data/spec/lib/moose_inventory/cli/group_get_spec.rb +17 -33
  129. data/spec/lib/moose_inventory/cli/group_list_spec.rb +16 -38
  130. data/spec/lib/moose_inventory/cli/group_listvar_spec.rb +33 -40
  131. data/spec/lib/moose_inventory/cli/group_rm_spec.rb +136 -96
  132. data/spec/lib/moose_inventory/cli/group_rmchild_spec.rb +66 -41
  133. data/spec/lib/moose_inventory/cli/group_rmhost_spec.rb +76 -78
  134. data/spec/lib/moose_inventory/cli/group_rmvar_spec.rb +57 -63
  135. data/spec/lib/moose_inventory/cli/group_spec.rb +2 -0
  136. data/spec/lib/moose_inventory/cli/helpers_spec.rb +146 -0
  137. data/spec/lib/moose_inventory/cli/host_add_spec.rb +170 -116
  138. data/spec/lib/moose_inventory/cli/host_addgroup_spec.rb +100 -83
  139. data/spec/lib/moose_inventory/cli/host_addvar_spec.rb +92 -74
  140. data/spec/lib/moose_inventory/cli/host_get_spec.rb +14 -33
  141. data/spec/lib/moose_inventory/cli/host_list_spec.rb +41 -33
  142. data/spec/lib/moose_inventory/cli/host_listvar_spec.rb +45 -53
  143. data/spec/lib/moose_inventory/cli/host_rm_spec.rb +66 -48
  144. data/spec/lib/moose_inventory/cli/host_rmgroup_spec.rb +73 -83
  145. data/spec/lib/moose_inventory/cli/host_rmvar_spec.rb +56 -63
  146. data/spec/lib/moose_inventory/cli/host_spec.rb +2 -0
  147. data/spec/lib/moose_inventory/cli/tags_spec.rb +81 -0
  148. data/spec/lib/moose_inventory/config/config_spec.rb +41 -3
  149. data/spec/lib/moose_inventory/db/db_spec.rb +396 -36
  150. data/spec/lib/moose_inventory/db/exceptions_spec.rb +18 -0
  151. data/spec/lib/moose_inventory/db/models_spec.rb +7 -3
  152. data/spec/lib/moose_inventory/db_lifecycle_spec.rb +73 -0
  153. data/spec/lib/moose_inventory/inventory_context_spec.rb +10 -0
  154. data/spec/lib/moose_inventory/operations/add_associations_spec.rb +34 -0
  155. data/spec/lib/moose_inventory/operations/add_groups_spec.rb +15 -0
  156. data/spec/lib/moose_inventory/operations/add_hosts_spec.rb +13 -0
  157. data/spec/lib/moose_inventory/operations/add_variables_spec.rb +103 -0
  158. data/spec/lib/moose_inventory/operations/group_child_relations_spec.rb +46 -0
  159. data/spec/lib/moose_inventory/operations/import_inventory_snapshot_spec.rb +239 -0
  160. data/spec/lib/moose_inventory/operations/inventory_doctor_spec.rb +77 -0
  161. data/spec/lib/moose_inventory/operations/inventory_snapshot_spec.rb +50 -0
  162. data/spec/lib/moose_inventory/operations/operation_event_support_spec.rb +78 -0
  163. data/spec/lib/moose_inventory/operations/query_inventory_spec.rb +146 -0
  164. data/spec/lib/moose_inventory/operations/remove_associations_spec.rb +35 -0
  165. data/spec/lib/moose_inventory/operations/remove_groups_spec.rb +21 -0
  166. data/spec/lib/moose_inventory/operations/remove_hosts_spec.rb +55 -0
  167. data/spec/lib/moose_inventory/operations/remove_variables_spec.rb +83 -0
  168. data/spec/shared/shared_config_setup.rb +4 -3
  169. data/spec/spec_helper.rb +50 -40
  170. data/spec/support/cli_harness.rb +33 -0
  171. metadata +81 -41
@@ -0,0 +1,84 @@
1
+ # Moose Inventory Accepted-Risk Register
2
+
3
+ ## Approval status
4
+
5
+ Status: **Approved register - no accepted risks currently approved here**
6
+
7
+ Russ / Rusty Frink Desiato approved this register's structure and use as part of the Moose Inventory security/privacy process baseline on 2026-05-29. Approval reference: `GOV-SEC-001`.
8
+
9
+ Russ / Rusty Frink Desiato separately approved this accepted-risk register as the maintained accepted-risk register baseline for Moose Inventory on 2026-05-29. Approval reference: `GOV-RISK-REG-001`.
10
+
11
+ This register records security, privacy, release, and supply-chain risks that are intentionally accepted rather than fixed before a defined milestone. A proposed risk is not accepted until an approver records an explicit approval decision.
12
+
13
+ Approved references:
14
+
15
+ - `GOV-TAILOR-001`: Moose Inventory is approved as Class 4 with target profile Software Library / Package.
16
+ - `GOV-PRODUCT-001`: `docs/product/product-brief.md` is approved as the product-framing baseline.
17
+ - `GOV-REQ-001`: `docs/product/requirements-baseline.md` is approved as the requirements and acceptance criteria baseline.
18
+ - `GOV-UX-001`: `docs/ux/cli-workflow-notes.md` is approved as the CLI UX/workflow baseline.
19
+ - `GOV-ARCH-001`: `docs/architecture/architecture-and-trust-boundaries.md` is approved as the architecture and trust-boundary baseline.
20
+ - `GOV-SEC-001`: this register's structure and use are approved as part of the security/privacy process baseline.
21
+ - `GOV-RISK-REG-001`: this register is approved as the maintained accepted-risk register baseline.
22
+
23
+ Scope limit: this register records accepted-risk decisions only. It does not approve a release, compliance claim, public advisory, RubyGems publishing, future architecture/security changes, or acceptance of any proposed/monitored risk listed below. Approval of the register baseline does not convert proposed or monitored risks into accepted risks.
24
+
25
+ ## Acceptance rules
26
+
27
+ Each accepted risk must include:
28
+
29
+ - risk ID;
30
+ - decision and scope;
31
+ - severity;
32
+ - affected assets/workflows;
33
+ - rationale for acceptance;
34
+ - compensating controls;
35
+ - owner;
36
+ - review date or trigger;
37
+ - approver and approval date;
38
+ - related issue/commit/document evidence where applicable.
39
+
40
+ Evidence is not approval. A finding listed under proposed or monitored risks remains unaccepted until explicitly approved.
41
+
42
+ ## Accepted risks
43
+
44
+ _No accepted risks are currently recorded._
45
+
46
+ ## Proposed or monitored risks
47
+
48
+ | ID | Status | Severity | Risk | Current controls | Required decision / next action |
49
+ | --- | --- | --- | --- | --- | --- |
50
+ | RISK-SEC-001 | Monitored, not accepted as permanent | Medium | GitHub secret scanning is unavailable/disabled in current repository evidence, so GitHub-native secret scanning cannot be relied on as a control. | Local/CI `gitleaks` gate, `MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS=1 ./scripts/check.sh`, docs warning against committing secrets. | Revisit if GitHub secret scanning becomes available. If releases rely on this limitation long-term, record an explicit accepted-risk decision or enable equivalent control. |
51
+ | RISK-SEC-002 | Evaluated, not accepted as release blocker | Low | Additional signed provenance/artifact attestations beyond RubyGems trusted publishing are not a current requirement. | RubyGems trusted publishing/OIDC, package sanity check, release workflow gate, package provenance hardening evaluation. | Revisit if security-sensitive consumers, release policy, or supply-chain requirements justify checksums, GitHub artifact attestations, signatures, or SBOM publication. |
52
+ | RISK-SEC-003 | Open process gap, not accepted | Medium | Public vulnerability intake is informal without a repo-local `SECURITY.md` or private advisory workflow documented for users. | GitHub issues for non-sensitive reports, maintainer/private coordination where available, security audit docs. | Decide whether to add public `SECURITY.md` as part of security/privacy baseline approval or maintenance runbook work. |
53
+ | RISK-SEC-004 | Open UX gap, not accepted | Medium | Destructive CLI commands do not yet have a consistent explicit confirmation / `--yes` pattern. | Explicit command names, dry-run support, tests, UX implementation backlog. | Complete UX implementation backlog item before expanding destructive behavior. |
54
+ | RISK-SEC-005 | Mitigated release-governance gap, monitor next release | Low | GitHub `release` environment protection rules were absent when first documented on 2026-05-29. They are now configured with required reviewer `RusDavies`, self-review prevention disabled, admin bypass disabled, and a custom `v*` deployment policy. Self-review prevention is disabled because OpenClaw/automation pushes use Russ's GitHub account, and `RusDavies` is currently the only required reviewer. GitHub reports the custom policy object as `type: branch`, so tag-deployment behavior still needs verification on the next real release. | Release workflow only runs on `v*` tags, verifies tag/version alignment, runs full security-required check gate, uses RubyGems trusted publishing/OIDC, and now requires environment review before the release job proceeds. | Verify next real `v*` tag release can deploy after approval. If the custom policy blocks tags, adjust the environment policy or document the GitHub limitation. |
55
+
56
+ ## Accepted-risk template
57
+
58
+ ```markdown
59
+ ### RISK-SEC-XXX: Short risk name
60
+
61
+ - Status: Proposed | Accepted | Retired
62
+ - Severity: Critical | High | Medium | Low
63
+ - Affected assets/workflows:
64
+ - Decision scope:
65
+ - Risk statement:
66
+ - Rationale for acceptance:
67
+ - Compensating controls:
68
+ - Owner:
69
+ - Review trigger/date:
70
+ - Approver:
71
+ - Approval date:
72
+ - Evidence:
73
+ ```
74
+
75
+ ## Review cadence
76
+
77
+ Review this register:
78
+
79
+ - before each material public release;
80
+ - when `scripts/check.sh` or security tooling changes;
81
+ - when a security audit finds a new issue;
82
+ - when a dependency advisory affects the supported dependency set;
83
+ - when release infrastructure, RubyGems trusted publishing, or GitHub environment protection changes;
84
+ - when a proposed risk is accepted, retired, or no longer accurate.
@@ -0,0 +1,287 @@
1
+ # Moose Inventory Security and Privacy Process
2
+
3
+ ## Approval status
4
+
5
+ Status: **Approved**
6
+
7
+ Russ / Rusty Frink Desiato approved this document as the Moose Inventory security and privacy process baseline on 2026-05-29. Approval reference: `GOV-SEC-001`.
8
+
9
+ This document captures the maintained security and privacy process baseline for Moose Inventory. It is prepared from the approved product, requirements, CLI UX, and architecture baselines, plus current security-audit evidence and verification scripts.
10
+
11
+ Approved references:
12
+
13
+ - `GOV-TAILOR-001`: Moose Inventory is approved as Class 4 with target profile Software Library / Package.
14
+ - `GOV-PRODUCT-001`: `docs/product/product-brief.md` is approved as the product-framing baseline.
15
+ - `GOV-REQ-001`: `docs/product/requirements-baseline.md` is approved as the requirements and acceptance criteria baseline.
16
+ - `GOV-UX-001`: `docs/ux/cli-workflow-notes.md` is approved as the CLI UX/workflow baseline.
17
+ - `GOV-ARCH-001`: `docs/architecture/architecture-and-trust-boundaries.md` is approved as the architecture and trust-boundary baseline.
18
+ - `GOV-SEC-001`: this document is approved as the security and privacy process baseline.
19
+
20
+ Scope limit: this document covers security and privacy process expectations for a Ruby CLI/RubyGem package. It is not release approval, accepted-risk approval, public/compliance-claim approval, RubyGems publishing approval, or approval to operate Moose Inventory as a hosted service. Approval of this baseline does not approve any proposed or monitored risk in the accepted-risk register.
21
+
22
+ ## Security posture summary
23
+
24
+ Moose Inventory is a local/automation-run CLI and RubyGem. It is not a hosted service and does not provide authentication, multi-user authorization, network listeners, or a managed SaaS control plane.
25
+
26
+ The main security responsibilities are:
27
+
28
+ - avoid leaking inventory, environment, and credential data;
29
+ - avoid unsafe mutation of inventory state;
30
+ - preserve package and release integrity;
31
+ - keep dependencies and CI/release tooling scanned;
32
+ - give maintainers a clear vulnerability intake and patch process;
33
+ - record accepted risks explicitly instead of smuggling them through vibes, the least trustworthy transport layer.
34
+
35
+ ## Assets and data classification
36
+
37
+ | Asset / data | Classification | Location / flow | Handling expectation |
38
+ | --- | --- | --- | --- |
39
+ | Inventory host and group names | Internal / environment-sensitive | User database, CLI output, snapshot exports, Ansible integration | Treat as potentially sensitive infrastructure metadata. Avoid publishing real inventories in examples, issues, logs, or screenshots. |
40
+ | Host/group variables | Internal to confidential depending on user content | User database, CLI output, snapshot exports, Ansible integration | Values may contain endpoints, usernames, tokens, or operational details. Users should not store secrets as inventory variables unless their environment explicitly protects them. |
41
+ | Database configuration | Confidential when credentials are present | YAML config files and selected environment sections | Prefer `password_env`; discourage committed plaintext passwords. Doctor should flag plaintext DB password configuration. |
42
+ | Environment variables containing DB passwords | Secret | User shell, CI environment, process environment | Do not log. Do not print in diagnostics. Rotate outside Moose Inventory if exposed. |
43
+ | SQLite database file | Internal to confidential | User-selected local filesystem path | User controls filesystem permissions, backups, and deletion. Backup copies inherit sensitivity of source data. |
44
+ | MySQL/MariaDB/PostgreSQL database state | Internal to confidential | User-managed database server | User controls database users, network access, server backup, restore, and encryption posture. |
45
+ | Audit/change records | Internal / environment-sensitive | User database audit tables and CLI audit output | Preserve append-only intent. Treat as operational history; avoid leaking in public bug reports. |
46
+ | Snapshot import/export files | Internal to confidential | Files passed to `import`/`export`, CI artifacts | Treat as inventory data. Review before sharing. Avoid storing secrets in exported snapshots. |
47
+ | CI/release artifacts and built gem | Public once released | GitHub Actions, RubyGems, local `tmp/pkg` | Verify package sanity and release workflow integrity before publishing. |
48
+ | Security-audit and release evidence | Internal to public depending on repo visibility | `docs/`, CI logs, release records | Avoid secrets. Make limitations explicit. Evidence is not approval by itself. |
49
+
50
+ ## Data flows
51
+
52
+ ### Local CLI mutation flow
53
+
54
+ ```text
55
+ Human / automation caller
56
+ |
57
+ v
58
+ moose-inventory CLI arguments/options
59
+ |
60
+ v
61
+ config discovery + selected environment
62
+ |
63
+ v
64
+ operation object validation
65
+ |
66
+ v
67
+ transactional database write
68
+ |
69
+ v
70
+ CLI output + audit/change record where applicable
71
+ ```
72
+
73
+ Security expectations:
74
+
75
+ - Validate arguments before mutation where practical.
76
+ - Keep dry-run non-mutating.
77
+ - Use transactions for write operations where practical.
78
+ - Do not print configured database passwords or environment-variable values.
79
+ - Keep destructive or high-risk changes explicit and reviewable.
80
+
81
+ ### Snapshot import/export flow
82
+
83
+ ```text
84
+ inventory.yml / inventory.json
85
+ |
86
+ v
87
+ parser + snapshot validator
88
+ |
89
+ v
90
+ transactional import apply OR validation failure
91
+ |
92
+ v
93
+ exported snapshot / CLI report / audit evidence
94
+ ```
95
+
96
+ Security expectations:
97
+
98
+ - Validate before write.
99
+ - Treat snapshot files as potentially confidential.
100
+ - Do not make import a destructive sync unless separately designed, documented, tested, and approved.
101
+ - Future preview/diff behavior should remain non-mutating.
102
+
103
+ ### Release and dependency flow
104
+
105
+ ```text
106
+ source + Gemfile.lock + workflows
107
+ |
108
+ v
109
+ scripts/check.sh
110
+ |
111
+ +--> RSpec / coverage
112
+ +--> RuboCop
113
+ +--> git diff --check
114
+ +--> permissions check
115
+ +--> OSV / bundler-audit
116
+ +--> gitleaks
117
+ +--> package sanity
118
+ |
119
+ v
120
+ reviewed tag + GitHub release workflow
121
+ |
122
+ v
123
+ RubyGems trusted publishing / OIDC
124
+ ```
125
+
126
+ Security expectations:
127
+
128
+ - Release jobs must require the same security-tool coverage expected by CI.
129
+ - A passing check is evidence, not release approval.
130
+ - Trusted publishing is the current package provenance baseline.
131
+ - Additional signed provenance or artifact attestations are future hardening, not a current blocker unless separately approved.
132
+
133
+ ## Threat and abuse-case model
134
+
135
+ | ID | Threat / abuse case | Impact | Current controls | Follow-up posture |
136
+ | --- | --- | --- | --- | --- |
137
+ | T-001 | User commits plaintext DB passwords in config | Credential disclosure | README guidance, `password_env`, doctor finding for plaintext password config, local `gitleaks` gate | Keep plaintext password support for compatibility; prefer `password_env`; track secret-scanning limits in risk register. |
138
+ | T-002 | Inventory snapshots or audit output are shared publicly | Infrastructure metadata disclosure | Documentation guidance, export is explicit, audit output is user-invoked | Treat snapshots/audit as sensitive; future docs should repeat sharing guidance near examples. |
139
+ | T-003 | Wrong config/environment is selected | Accidental mutation of wrong inventory DB | Explicit `--config`, `--env`, config validation, dry-run support | Future destructive confirmation should show environment/config context. |
140
+ | T-004 | Destructive commands remove intended inventory state without enough friction | Operational disruption | Explicit command names, dry-run coverage, backlog item for destructive confirmation | Implement confirmation/`--yes` behavior before expanding destructive workflows. |
141
+ | T-005 | Malformed import file causes partial or inconsistent writes | Data corruption | Snapshot validation before apply, transactional import | Keep import validation coverage with schema changes. |
142
+ | T-006 | Duplicate/conflicting DB records bypass application logic | Corrupt inventory behavior | Schema uniqueness/index migrations, duplicate cleanup/refusal | Keep migration tests and future-schema refusal. |
143
+ | T-007 | CLI input reaches shell execution | Command injection | Application uses Ruby/Sequel operations, not shell execution for inventory mutations | Security reviews should re-check new integrations for shell invocation. |
144
+ | T-008 | Dependency vulnerability ships in a release | User environment compromise | OSV query, `osv-scanner`, `bundler-audit`, release parity enforcement | Patch according to vulnerability policy below; accept residual risk only through risk register. |
145
+ | T-009 | Secret scanner is unavailable in GitHub repository settings | Missed committed secrets | Local/CI `gitleaks` gate | Track as accepted/monitored residual risk until GitHub secret scanning is available/enabled. |
146
+ | T-010 | Release workflow publishes unreviewed or tampered package | Supply-chain compromise | GitHub Actions release workflow, trusted publishing/OIDC, package sanity, tag/version checks | Document confirmed release environment protections after maintainers verify settings. |
147
+ | T-011 | Database server backups/restores are assumed to be handled by Moose Inventory | Data loss or false assurance | Architecture says server-backed DB operations remain user-managed; `docs/maintenance/database-backup-restore-guidance.md` documents native-tool backup/restore boundaries for SQLite, MySQL/MariaDB, and PostgreSQL | Keep backup/restore guidance current when database lifecycle commands change. |
148
+ | T-012 | AI-assisted maintenance performs external or irreversible actions without approval | Governance/security failure | Workspace process and approval register | Repo-local AI-agent boundaries remain a separate process item. |
149
+
150
+ ## Authentication and authorization model
151
+
152
+ Moose Inventory does not authenticate users itself. It relies on the caller's local operating-system account, shell environment, filesystem permissions, and configured database credentials.
153
+
154
+ Authorization boundaries:
155
+
156
+ - CLI execution authority is inherited from the local user or automation account running the command.
157
+ - SQLite access is controlled by filesystem permissions.
158
+ - MySQL/MariaDB/PostgreSQL access is controlled by the configured database account and server policy.
159
+ - GitHub/RubyGems release authority is controlled outside the gem by repository, workflow, environment, and trusted-publishing configuration.
160
+
161
+ Security expectations:
162
+
163
+ - Use least-privilege database accounts where practical.
164
+ - Avoid sharing config files that contain credentials.
165
+ - Keep release and package-publishing authority human-owned and separately approved.
166
+ - Do not imply Moose Inventory provides RBAC or tenant isolation.
167
+
168
+ ## Secrets handling model
169
+
170
+ Preferred posture:
171
+
172
+ - Use `password_env` for DB passwords.
173
+ - Store secrets in the caller's environment, shell secret manager, CI secret store, or database/platform secret mechanism.
174
+ - Keep plaintext `password` only as a compatibility option.
175
+
176
+ Rules:
177
+
178
+ - Do not print DB passwords in normal output, errors, doctor reports, or audit records.
179
+ - Do not add examples that contain real secrets, tokens, host inventories, or live infrastructure details.
180
+ - Do not commit `.env`, real config files, live inventory exports, database files, or secret-containing logs.
181
+ - If a secret is committed, rotate it outside Moose Inventory and record the incident/cleanup evidence.
182
+
183
+ ## Logging and audit expectations
184
+
185
+ Moose Inventory has an append-only audit/change-history feature for inventory mutations. That audit log is product evidence and operational history, not a rollback system and not a tamper-proof security ledger.
186
+
187
+ Expectations:
188
+
189
+ - Mutating commands should record meaningful audit/change evidence where supported.
190
+ - Dry-runs should not mutate inventory state or audit history.
191
+ - Audit output may contain host/group names and variable names; treat it as environment-sensitive.
192
+ - Audit records should not include database passwords or environment-variable secret values.
193
+ - Any future richer audit export should document confidentiality and retention expectations.
194
+
195
+ ## Privacy posture
196
+
197
+ Moose Inventory does not intentionally collect personal data, telemetry, analytics, or hosted-service user behavior.
198
+
199
+ Privacy expectations:
200
+
201
+ - No built-in telemetry without separate product approval.
202
+ - No external network calls during normal inventory operations except database connections explicitly configured by the user.
203
+ - Dependency/security checks in maintainer workflows may contact external advisory services such as OSV and Ruby advisory sources; this is release/maintenance evidence, not runtime telemetry.
204
+ - User inventories may include personal data if users put it there. Treat exported snapshots, audit records, and DB backups according to the sensitivity of user-provided content.
205
+
206
+ ## Vulnerability intake and security patch policy
207
+
208
+ ### Intake channels
209
+
210
+ Current maintained intake channels:
211
+
212
+ - GitHub issues for non-sensitive bugs and security-hardening requests.
213
+ - Direct maintainer contact or private coordination for sensitive vulnerability details when available.
214
+ - Security audit findings recorded under `docs/security-audit-*.md`.
215
+
216
+ Future improvement:
217
+
218
+ - Add a `SECURITY.md` file if maintainers want a public vulnerability-reporting policy on GitHub.
219
+
220
+ ### Triage severity
221
+
222
+ Use the highest applicable severity:
223
+
224
+ - Critical: credible package compromise, credential disclosure in release tooling, arbitrary code execution reachable through normal CLI use, or destructive data corruption with no workaround.
225
+ - High: dependency vulnerability reachable in supported use, unsafe secret exposure, release workflow bypass, or destructive mutation bug likely to affect real inventory.
226
+ - Medium: validation bypass, denial-of-service condition, confusing security-sensitive UX, or hardening gap with plausible user impact.
227
+ - Low: documentation clarity, defense-in-depth, non-reachable dependency advisory, or scanner/process improvement.
228
+
229
+ ### Patch targets
230
+
231
+ Targets are guidance, not an SLA promise:
232
+
233
+ - Critical: stop release activity, prepare fix or mitigation immediately, and require human approval before publishing.
234
+ - High: prioritize before feature work and target the next patch release.
235
+ - Medium: add to backlog with owner/evidence and fix in an upcoming maintenance slice.
236
+ - Low: handle opportunistically or with related docs/process work.
237
+
238
+ ### Release and disclosure
239
+
240
+ - Do not publish a release that knowingly ships an unresolved critical/high security issue unless a human approver records accepted risk.
241
+ - Release notes should describe security fixes at an appropriate level without handing attackers a nicely gift-wrapped exploit manual.
242
+ - If a published gem is compromised or materially unsafe, a human maintainer must decide whether to yank, deprecate, patch, or publish an advisory.
243
+
244
+ ## Security acceptance criteria
245
+
246
+ Security-ready for a release candidate means:
247
+
248
+ - `MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS=1 ./scripts/check.sh` passes or exceptions are explicitly recorded.
249
+ - No known unresolved critical/high findings remain unless accepted through the risk register.
250
+ - Dependency/advisory scans are current enough for the release decision.
251
+ - Secret scan passes or any finding is triaged, cleaned, and rotated where needed.
252
+ - Package sanity passes for the gem artifact.
253
+ - Release docs and checklist identify any accepted risks, limitations, and non-goals.
254
+ - Approval records distinguish evidence from human approval.
255
+
256
+ ## Accepted-risk register relationship
257
+
258
+ Accepted risks live in `docs/security/accepted-risk-register.md`.
259
+
260
+ Rules:
261
+
262
+ - A risk entry may be proposed by an agent or maintainer, but acceptance requires explicit human approval.
263
+ - Each accepted risk must include scope, reason, compensating controls, owner, review trigger/date, and approval reference.
264
+ - Empty or pending risk tables are useful evidence; they do not mean all risk is approved.
265
+
266
+ ## Current known limitations and compensating controls
267
+
268
+ | Limitation | Current posture | Compensating control / next action |
269
+ | --- | --- | --- |
270
+ | GitHub secret scanning is unavailable/disabled for this repository in current evidence | Not accepted as a permanent claim; tracked as residual posture | Local/CI `gitleaks` gate remains required. Revisit if GitHub secret scanning becomes available. |
271
+ | MySQL/MariaDB/PostgreSQL backups/restores are user-managed | Architecture scope boundary | Expanded guidance lives in `docs/maintenance/database-backup-restore-guidance.md`; update it when database lifecycle commands change. |
272
+ | Public vulnerability intake is informal | Draft process only | Consider adding `SECURITY.md` or GitHub private vulnerability reporting if maintainers want public intake clarity. |
273
+ | Destructive CLI confirmation is not fully implemented | UX follow-up backlog | Implement explicit confirmation / `--yes` behavior before expanding destructive workflows. |
274
+ | Additional package provenance is not required beyond trusted publishing | Architecture decision | Evaluate signed provenance/artifact attestations as future hardening if justified. |
275
+
276
+ ## Review cadence
277
+
278
+ Review this document when any of the following changes:
279
+
280
+ - supported database adapters or schema migration behavior;
281
+ - import/export or audit data handling;
282
+ - release workflow, trusted publishing, or security scanning tools;
283
+ - vulnerability intake expectations;
284
+ - public security/compliance claims;
285
+ - a security incident, secret exposure, or accepted-risk decision.
286
+
287
+ At minimum, revisit before each material public release.
@@ -52,7 +52,7 @@ Reviewed security-relevant surfaces and changes since the prior audit:
52
52
  - Impact: a release tag created from an unexpected commit or during a tooling/path issue could publish without the same dedicated SCA/secret-scan enforcement as CI.
53
53
  - Fix applied: release workflow now sets up Go with cache disabled, installs the pinned security CLIs via `scripts/ci/install_security_tools.sh`, runs native dependency installation with a 5-minute timeout, and runs `./scripts/check.sh` with `MOOSE_INVENTORY_REQUIRE_SECURITY_TOOLS=1`.
54
54
  - Verification: full local required-tool gate passed after the workflow change.
55
- - Residual risk: release workflow can only be fully proven on the next real release tag because already-published `v1.0.9` must not be retagged.
55
+ - Residual risk after later verification: trusted publishing was proven on release tag `v2.0`, but the workflow still has a false-negative path where post-publish waiting can fail if the RubyGems full index lags even after a successful publish.
56
56
 
57
57
  ## Reviewed areas with no actionable finding
58
58
 
@@ -68,7 +68,7 @@ Reviewed security-relevant surfaces and changes since the prior audit:
68
68
  - This was a local/source and CI/release workflow audit, not an active test against live external databases or RubyGems publishing.
69
69
  - GitHub code scanning is not configured, so there were no CodeQL/code-scanning results to review.
70
70
  - GitHub secret scanning is disabled for the repository; local `gitleaks` coverage was used instead.
71
- - The release trusted-publishing path still needs verification on the next real version tag.
71
+ - The release trusted-publishing path was later verified on `v2.0`; the remaining limitation is that workflow success/failure still depends on RubyGems full-index propagation timing.
72
72
 
73
73
  ## Conclusion
74
74
 
@@ -0,0 +1,58 @@
1
+ # Snapshot Import Availability Fuzz Audit - 2026-05-29
2
+
3
+ Repository: `RusDavies/moose-inventory`
4
+ Local path: `/home/skippy/.openclaw/workspace/projects/moose-inventory`
5
+ Commit audited: `48da0472f8fadb7685777987545d51b4b62eb806`
6
+ Version audited: `2.1`
7
+ Audit context: follow-up to `code-security-audit` run `3`
8
+
9
+ ## Scope
10
+
11
+ This pass targeted snapshot import availability and malformed-input behavior for the local CLI import path:
12
+
13
+ ```bash
14
+ ruby -Ilib bin/moose-inventory --config spec/config/config.yml import SNAPSHOT.yml --preview
15
+ ```
16
+
17
+ The pass used preview mode to keep the fuzz cases non-mutating while still exercising YAML loading, snapshot normalization, validation, and preview generation.
18
+
19
+ ## Cases exercised
20
+
21
+ | Case | Result | Notes |
22
+ | --- | --- | --- |
23
+ | Baseline valid snapshot | Pass | Preview completed in 0.127s. |
24
+ | Malformed YAML | Graceful rejection | Reported a sanitized `ERROR: Could not parse inventory snapshot ...`. |
25
+ | YAML alias | Ungraceful rejection | Rejected safely, but emitted a Ruby/Psych stack trace. |
26
+ | Disallowed symbol key / duplicate-normalized-key probe | Ungraceful rejection | Rejected safely, but emitted a Ruby/Psych stack trace before project-level validation. |
27
+ | Group cycle | Graceful rejection | Reported `Invalid inventory snapshot: group hierarchy contains a cycle ...`. |
28
+ | Unknown child group reference | Graceful rejection | Reported `Invalid inventory snapshot: group ... references unknown child group ...`. |
29
+ | 5,000 variable entries | Pass | Preview completed in 0.157s. |
30
+ | 250-deep group chain | Pass | Preview completed in 0.142s. |
31
+ | 1,000-deep group chain | Pass | Preview completed in 0.187s. |
32
+ | 3,000-deep group chain | Pass | Preview completed in 0.306s. |
33
+
34
+ Raw local artifact: `.openclaw-security-audit/fuzz_snapshot_import_availability_run.json`.
35
+
36
+ ## Finding
37
+
38
+ ### P3 / Low: snapshot import does not sanitize all Psych safe-load exceptions
39
+
40
+ `Application#import` currently rescues `Psych::SyntaxError` around `YAML.safe_load_file`, but safe-load can also raise other Psych exceptions such as `Psych::AliasesNotEnabled` and `Psych::DisallowedClass` before Moose Inventory's snapshot validator runs.
41
+
42
+ Observed examples:
43
+
44
+ - YAML alias payload is rejected because aliases are disabled, but the CLI prints a Ruby/Psych stack trace.
45
+ - Symbol-tag payload is rejected because permitted classes are restricted, but the CLI prints a Ruby/Psych stack trace.
46
+
47
+ Security interpretation:
48
+
49
+ - The unsafe payloads were rejected, so this is not unsafe deserialization or code execution.
50
+ - The issue is availability/UX hardening and minor information disclosure through local stack traces and filesystem/gem paths.
51
+ - Reachability is local CLI import of an attacker-supplied or untrusted snapshot file.
52
+ - Priority is P3/low because the blast radius is local command failure/noisy logs rather than inventory corruption or privilege escalation.
53
+
54
+ ## Recommended remediation
55
+
56
+ Add a focused backlog item to handle non-syntax `Psych::Exception` failures in the import path with the same sanitized `ERROR: Could not parse inventory snapshot ...` style, and add regression cases for aliases/disallowed classes.
57
+
58
+ A later hardening pass may also consider explicit snapshot size/entity/depth limits, but this fuzz pass did not find practical timeout behavior at the bounded sizes tested.