abide_dev_utils 0.18.4 → 0.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +7 -2
- data/CLAUDE.md +45 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +252 -168
- data/abide_dev_utils.gemspec +2 -2
- data/docs/ARCHITECTURE.md +264 -0
- data/files/fact_sets/redhat-10-x86_64.facts +606 -0
- data/files/fact_sets/windows-2025-x86_64.facts +169 -0
- data/lib/abide_dev_utils/ppt/facter_utils.rb +7 -3
- data/lib/abide_dev_utils/ppt/score_module.rb +14 -5
- data/lib/abide_dev_utils/version.rb +1 -1
- metadata +23 -19
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
This document describes the file/directory layout of `abide_dev_utils` so contributors and AI assistants can find the right place to make a change. For build/test commands, see `CLAUDE.md` and `README.md`.
|
|
4
|
+
|
|
5
|
+
`abide_dev_utils` is a developer helper for the **`puppetlabs-sce_linux`** and **`puppetlabs-sce_windows`** Puppet SCE modules. Most of the design choices in this repo (the `sce/` subsystem, the fixture-cloning rake task, the local fact sets in `files/`) exist to support those two modules, so when something in the architecture seems oddly specific, it's almost always because one of those modules needed it.
|
|
6
|
+
|
|
7
|
+
## Top-level layout
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
abide_dev_utils/
|
|
11
|
+
├── exe/ ← gem-installed CLI binary
|
|
12
|
+
├── bin/ ← in-repo dev binaries + setup script
|
|
13
|
+
├── lib/ ← all library + CLI code (see lib/ section below)
|
|
14
|
+
├── spec/ ← RSpec tests, mirroring lib/ layout
|
|
15
|
+
├── files/ ← static resources shipped with the gem
|
|
16
|
+
├── docs/ ← contributor-facing docs (this file lives here)
|
|
17
|
+
├── pkg/ ← rake build output (.gem files); not committed source
|
|
18
|
+
├── Gemfile / .gemspec ← dependency + gem metadata
|
|
19
|
+
├── Rakefile ← spec/rubocop/build tasks + sce:fixtures clone task
|
|
20
|
+
├── new_diff.rb ← ad-hoc one-off script (not wired into the CLI)
|
|
21
|
+
└── README.md / CHANGELOG.md / LICENSE.txt / CODEOWNERS
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The unusual ones:
|
|
25
|
+
|
|
26
|
+
- **`exe/abide`** is the Bundler-recommended location for installed binaries; `spec.executables = ['abide']` in the gemspec wires it up.
|
|
27
|
+
- **`bin/abide.rb`** is a duplicate entry point used during development so you can `ruby bin/abide.rb ...` without installing the gem. `bin/console` is an IRB session with the gem preloaded; `bin/setup` is the `bundle install` bootstrap.
|
|
28
|
+
- **`new_diff.rb`** is a developer scratch script that exercises the XCCDF diff code; it's not part of the public CLI surface.
|
|
29
|
+
- **`pkg/`** is rake build output. Don't edit anything in there.
|
|
30
|
+
- **`files/fact_sets/`** holds locally-stored fact sets used as a FacterDB fallback. `abide sce generate reference` (the `REFERENCE.md` generator) relies on the `facterdb` gem to look up facts for every OS that `sce_linux` / `sce_windows` declare in their `metadata.json`. When one of those modules adds support for a brand-new OS release, FacterDB doesn't always have a matching fact set yet — in that case we drop a `<os>-<version>-<arch>.facts` file (e.g. `windows-2025-x86_64.facts`) into `files/fact_sets/` and `ppt/facter_utils.rb` loads it instead. Once FacterDB ships the fact set upstream, the file here can be removed.
|
|
31
|
+
|
|
32
|
+
## `lib/abide_dev_utils/` — library + CLI
|
|
33
|
+
|
|
34
|
+
The whole gem lives under one namespace. `lib/abide_dev_utils.rb` is the require-everything entry point; the rest of the structure pairs each top-level CLI namespace with a sibling library directory.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
lib/abide_dev_utils.rb ← top-level require: pulls in every domain
|
|
38
|
+
lib/abide_dev_utils/
|
|
39
|
+
├── cli.rb ← cmdparse setup; registers the 6 top-level commands
|
|
40
|
+
├── cli/ ← one file per top-level CLI namespace
|
|
41
|
+
│
|
|
42
|
+
├── sce.rb sce/ ← `abide sce ...` library
|
|
43
|
+
├── xccdf.rb xccdf/ ← `abide xccdf ...` library
|
|
44
|
+
├── ppt.rb ppt/ ← `abide puppet ...` library + shared Puppet helpers
|
|
45
|
+
├── jira.rb jira/ ← `abide jira ...` library
|
|
46
|
+
├── comply.rb ← `abide comply ...` library (deprecated, no subdir)
|
|
47
|
+
│
|
|
48
|
+
├── config.rb ← reads ~/.abide_dev.yaml
|
|
49
|
+
├── files.rb ← Reader/Writer dispatching on extension
|
|
50
|
+
├── output.rb ← simple/text/json/yaml/progress writers
|
|
51
|
+
├── validate.rb ← file/directory/hashable/puppet_module_directory checks
|
|
52
|
+
├── prompt.rb ← interactive y/n prompt used by jira flows
|
|
53
|
+
├── markdown.rb ← tiny Markdown builder used by sce reference generator
|
|
54
|
+
├── gcloud.rb ← google-cloud-storage wrapper (loaded but unused by CLI)
|
|
55
|
+
├── puppet_strings.rb ← shared puppet-strings helpers
|
|
56
|
+
├── mixins.rb ← misc reusable mixins
|
|
57
|
+
├── dot_number_comparable.rb ← <=> for dotted CIS ids ("1.2.10" > "1.2.2")
|
|
58
|
+
├── constants.rb ← CliConstants
|
|
59
|
+
├── version.rb ← VERSION string (bump before `rake release`)
|
|
60
|
+
│
|
|
61
|
+
├── errors.rb errors/ ← typed exception classes, namespaced per domain
|
|
62
|
+
└── resources/ ← ERB templates shipped with the gem (e.g. generic_spec.erb)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `cli/` — CLI command classes
|
|
66
|
+
|
|
67
|
+
One file per top-level `abide <namespace>` command. Each file defines a `*Command` class plus its subcommands.
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
cli/
|
|
71
|
+
├── abstract.rb ← AbideCommand base class (handles [DEPRECATED] tagging, mixes in Config)
|
|
72
|
+
├── sce.rb ← `abide sce {generate,update-config,validate} ...`
|
|
73
|
+
├── xccdf.rb ← `abide xccdf {to_hiera,diff,gen-map}`
|
|
74
|
+
├── puppet.rb ← `abide puppet {coverage,new,...}`
|
|
75
|
+
├── jira.rb ← `abide jira {auth,from_coverage,from_xccdf,new_issue,get_issue}`
|
|
76
|
+
├── comply.rb ← `abide comply report` (DEPRECATED)
|
|
77
|
+
└── test.rb ← `abide test` (DEPRECATED, currently broken)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
All command classes inherit from `Abide::CLI::AbideCommand` (defined in `cli/abstract.rb`), which wraps `CmdParse::Command`, mixes in `AbideDevUtils::Config`, and prefixes short/long descriptions with `[DEPRECATED]` when `deprecated: true` is passed. Don't subclass `CmdParse::Command` directly when adding new commands.
|
|
81
|
+
|
|
82
|
+
### `sce/` — Security Compliance Enforcement domain
|
|
83
|
+
|
|
84
|
+
The largest subsystem. Operates on Puppet SCE modules on disk (`puppetlabs-sce_linux`, `puppetlabs-sce_windows`, etc.) and produces coverage reports, reference docs, and validation output.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
sce.rb ← top-level entry; defines update_legacy_config_from_diff
|
|
88
|
+
sce/
|
|
89
|
+
├── benchmark_loader.rb ← walks a Puppet module's supported_os × frameworks
|
|
90
|
+
│ and constructs Benchmark objects (errors are
|
|
91
|
+
│ collected, not raised)
|
|
92
|
+
├── benchmark.rb ← Benchmark / Resource / Control domain model
|
|
93
|
+
│ (Control mixes in DotNumberComparable)
|
|
94
|
+
│
|
|
95
|
+
├── generate.rb generate/ ← `abide sce generate ...`
|
|
96
|
+
│ ├── coverage_report.rb ← coverage-report subcommand
|
|
97
|
+
│ └── reference.rb ← reference (REFERENCE.md) subcommand
|
|
98
|
+
│
|
|
99
|
+
├── validate.rb validate/ ← `abide sce validate ...`
|
|
100
|
+
│ ├── resource_data.rb ← validates data/resource_data/*.yaml
|
|
101
|
+
│ ├── strings.rb ← runs puppet-strings over the module
|
|
102
|
+
│ └── strings/ ← per-Puppet-type validators
|
|
103
|
+
│ ├── base_validator.rb
|
|
104
|
+
│ ├── puppet_class_validator.rb
|
|
105
|
+
│ ├── puppet_defined_type_validator.rb
|
|
106
|
+
│ └── validation_finding.rb
|
|
107
|
+
│
|
|
108
|
+
├── mapping/ ← id ↔ id mapping (control numbers, hiera titles, ...)
|
|
109
|
+
│ └── mapper.rb ← Mapper, MapData, ALL_TYPES / FRAMEWORK_TYPES enums
|
|
110
|
+
│
|
|
111
|
+
└── hiera_data.rb hiera_data/ ← parsing the SCE module's data/ directory
|
|
112
|
+
├── mapping_data.rb ← entry point for data/mapping/*.yaml
|
|
113
|
+
├── mapping_data/
|
|
114
|
+
│ ├── map_data.rb ← parses one mapping YAML file
|
|
115
|
+
│ └── mixins.rb ← MixinCIS / MixinSTIG (per-framework lookup logic)
|
|
116
|
+
└── resource_data/ ← (placeholder; reserved for resource_data parsers)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`sce.rb` plus everything in `sce/` is what powers the `abide sce` CLI. The pattern of *"top-level `.rb` requires the subdirectory"* is consistent across the codebase — `sce/generate.rb` requires `sce/generate/*.rb`, and so on.
|
|
120
|
+
|
|
121
|
+
### `xccdf/` — XCCDF parsing and conversion
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
xccdf.rb ← entry points (gen_map, to_hiera, diff) +
|
|
125
|
+
│ XCCDF::Common (CIS/STIG regex constants) +
|
|
126
|
+
│ XCCDF::Benchmark
|
|
127
|
+
xccdf/
|
|
128
|
+
├── parser.rb parser/ ← Nokogiri-based parser
|
|
129
|
+
│ ├── helpers.rb
|
|
130
|
+
│ └── objects.rb objects/
|
|
131
|
+
│ ├── numbered_object.rb ← controls/profiles with dotted numbers
|
|
132
|
+
│ └── diffable_object.rb ← objects participating in benchmark diffing
|
|
133
|
+
│
|
|
134
|
+
├── diff.rb ← BenchmarkDiff (used by `abide xccdf diff` and the
|
|
135
|
+
│ currently-disabled `sce update-config from-diff`)
|
|
136
|
+
└── utils.rb ← shared XCCDF helpers
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`XCCDF::Common` (in `xccdf.rb`) is the **single source of truth** for CIS vs STIG conventions: control-id regexes, profile-level codes, the `normalize_string` / `normalize_control_name` / `normalize_profile_name` helpers that the README documents. Touching the constants in `Common` affects mapping generation, Hiera key naming, and diffing simultaneously.
|
|
140
|
+
|
|
141
|
+
### `ppt/` — Puppet-module utilities
|
|
142
|
+
|
|
143
|
+
Used both by the `sce/` subsystem (to read manifests off disk) and directly by the `abide puppet ...` commands.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
ppt.rb ← top-level helpers: rename_puppet_class, build_new_object,
|
|
147
|
+
│ audit/fix_class_names, add_cis_comment, score_module
|
|
148
|
+
ppt/
|
|
149
|
+
├── puppet_module.rb ← PuppetModule class: reads metadata.json, hiera.yaml;
|
|
150
|
+
│ exposes supported_os used by BenchmarkLoader
|
|
151
|
+
├── class_utils.rb ← Puppet class name ↔ on-disk path conversions
|
|
152
|
+
├── code_introspection.rb ← parses Puppet manifests (used by Resource.manifest)
|
|
153
|
+
├── hiera.rb ← Hiera::Config wrapper for a module's hiera.yaml
|
|
154
|
+
├── facter_utils.rb ← FacterDB integration; can also load files/fact_sets/*.facts
|
|
155
|
+
├── strings.rb ← puppet-strings helpers
|
|
156
|
+
├── api.rb ← misc Puppet API glue
|
|
157
|
+
├── new_obj.rb ← `abide puppet new` ERB-based generator
|
|
158
|
+
│ (honours c-/d- filename prefixes for spec dir routing)
|
|
159
|
+
├── score_module.rb ← stub; Ppt.score_module currently prints "not implemented"
|
|
160
|
+
│
|
|
161
|
+
└── code_gen.rb code_gen/ ← AST-style wrappers for code generation
|
|
162
|
+
├── generate.rb
|
|
163
|
+
├── data_types.rb
|
|
164
|
+
├── resource.rb
|
|
165
|
+
├── resource_types.rb
|
|
166
|
+
└── resource_types/
|
|
167
|
+
├── base.rb
|
|
168
|
+
├── class.rb
|
|
169
|
+
├── manifest.rb
|
|
170
|
+
├── parameter.rb
|
|
171
|
+
└── strings.rb
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `jira/` — Jira integration
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
jira.rb ← top-level flows: new_issues_from_coverage,
|
|
178
|
+
│ new_issues_from_xccdf, summary helpers.
|
|
179
|
+
│ Defines summary prefixes (COV_PARENT_SUMMARY_PREFIX,
|
|
180
|
+
│ COV_CHILD_SUMMARY_PREFIX, UPD_EPIC_SUMMARY_PREFIX)
|
|
181
|
+
│ used to recognise issues this tool created.
|
|
182
|
+
jira/
|
|
183
|
+
├── client.rb ← jira-ruby client wrapper
|
|
184
|
+
├── client_builder.rb ← builds a client from ~/.abide_dev.yaml's jira section
|
|
185
|
+
├── dry_run.rb ← drop-in replacement returned when --dry-run is set
|
|
186
|
+
├── finder.rb ← search existing issues
|
|
187
|
+
├── issue_builder.rb ← payload construction for create/update
|
|
188
|
+
└── helper.rb ← project-level convenience (all_project_issues_attrs, etc.)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### `errors/` — typed exceptions
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
errors.rb ← requires the per-domain files
|
|
195
|
+
errors/
|
|
196
|
+
├── base.rb ← AbideDevUtils::Errors::* base class
|
|
197
|
+
├── general.rb ← cross-cutting errors (FileNotFoundError, etc.)
|
|
198
|
+
├── sce.rb ← BenchmarkLoadError (carries osname, major_version,
|
|
199
|
+
│ framework, module_name, original_error fields that
|
|
200
|
+
│ cli/sce.rb pretty-prints via respond_to?)
|
|
201
|
+
├── xccdf.rb ← UnsupportedXCCDFError, ProfilePartsError, ControlPartsError
|
|
202
|
+
├── ppt.rb ← Puppet-module errors (ClassFileNotFoundError, ...)
|
|
203
|
+
├── jira.rb ← Jira-specific errors
|
|
204
|
+
├── comply.rb ← Comply scraper errors (deprecated)
|
|
205
|
+
└── gcloud.rb ← GCS errors
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
When introducing a new "soft" error that the CLI should pretty-print rather than raise, follow the `BenchmarkLoadError` pattern: subclass the matching domain error and expose extra metadata as accessors. The CLI uses `respond_to?` to decide which fields to render.
|
|
209
|
+
|
|
210
|
+
### `comply.rb` — deprecated Selenium scraper
|
|
211
|
+
|
|
212
|
+
A single file (no `comply/` subdirectory) that drives `selenium-webdriver` against the Puppet Comply UI. It's deprecated and still loaded mostly so the deprecation message stays visible. Don't extend it.
|
|
213
|
+
|
|
214
|
+
## `spec/` — tests
|
|
215
|
+
|
|
216
|
+
The spec layout mirrors `lib/abide_dev_utils/`:
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
spec/
|
|
220
|
+
├── spec_helper.rb ← requires every file under lib/ (catches load-order
|
|
221
|
+
│ regressions); exposes TestResources / OutputHelpers
|
|
222
|
+
├── abide_dev_utils_spec.rb ← top-level smoke tests
|
|
223
|
+
├── abide_dev_utils/ ← mirrors lib/abide_dev_utils/ one-to-one
|
|
224
|
+
│ ├── cli_spec.rb
|
|
225
|
+
│ ├── xccdf_spec.rb
|
|
226
|
+
│ ├── xccdf/
|
|
227
|
+
│ │ ├── parser_spec.rb
|
|
228
|
+
│ │ ├── parser/objects_spec.rb
|
|
229
|
+
│ │ └── diff/benchmark_spec.rb
|
|
230
|
+
│ ├── sce/benchmark_spec.rb
|
|
231
|
+
│ └── ppt/
|
|
232
|
+
│ ├── facter_utils_spec.rb
|
|
233
|
+
│ └── new_obj_spec.rb
|
|
234
|
+
│
|
|
235
|
+
├── resources/ ← committed test inputs (work without network)
|
|
236
|
+
│ ├── cis/ ← real CIS XCCDF files for parser tests
|
|
237
|
+
│ │ ├── CIS_CentOS_Linux_7_Benchmark_v3.0.0-xccdf.xml
|
|
238
|
+
│ │ └── CIS_Microsoft_Windows_Server_2016_..._v1.2.0-xccdf.xml
|
|
239
|
+
│ └── test_files/ ← small synthetic XCCDFs for diff/version tests
|
|
240
|
+
│ ├── Test_XCCDF-v1.0.0-xccdf.xml
|
|
241
|
+
│ └── Test_XCCDF-v1.1.0-xccdf.xml
|
|
242
|
+
│
|
|
243
|
+
└── fixtures/ ← real Puppet SCE modules cloned at test time by
|
|
244
|
+
`rake sce:fixtures`. Not committed; required by
|
|
245
|
+
any spec that exercises BenchmarkLoader.
|
|
246
|
+
├── puppetlabs-sce_linux/ ← clone of git@github.com:puppetlabs/puppetlabs-sce_linux
|
|
247
|
+
└── puppetlabs-sce_windows/ ← clone of git@github.com:puppetlabs/puppetlabs-sce_windows
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`spec_helper.rb` exposes helpers via mixins: `sce_linux_fixture` / `sce_windows_fixture` (prefer the `sce_*` clone, fall back to `cem_*`), `test_xccdf_files`, `capture_stdout`, `capture_stderr`. RSpec is configured with `disable_monkey_patching!`, `verify_partial_doubles = true`, and `fail_fast = false` — keep partial doubles realistic.
|
|
251
|
+
|
|
252
|
+
## How a request flows through the codebase
|
|
253
|
+
|
|
254
|
+
Tracing `abide sce generate coverage-report` end-to-end is a good way to internalise the layout:
|
|
255
|
+
|
|
256
|
+
1. **`exe/abide`** loads `lib/abide_dev_utils/cli.rb` and calls `Abide::CLI.execute`.
|
|
257
|
+
2. **`cli.rb`** registers `SceCommand` (from `cli/sce.rb`) on the cmdparse parser.
|
|
258
|
+
3. **`cli/sce.rb`** routes `generate coverage-report` to `SceGenerateCoverageReport#execute`, which collects flags into `@data` and calls `AbideDevUtils::Sce::Generate::CoverageReport.generate(...)`.
|
|
259
|
+
4. **`sce/generate/coverage_report.rb`** asks `BenchmarkLoader::PupMod` (in `sce/benchmark_loader.rb`) to load benchmarks from the current directory.
|
|
260
|
+
5. **`benchmark_loader.rb`** instantiates a `Ppt::PuppetModule` (from `ppt/puppet_module.rb`), reads `metadata.json` for `supported_os`, and constructs one `Sce::Benchmark` per (OS, version, framework) cell.
|
|
261
|
+
6. Each **`Sce::Benchmark`** (in `sce/benchmark.rb`) builds a `Mapping::Mapper` (from `sce/mapping/mapper.rb`) over the module's `data/mapping/*.yaml` files, and a list of `Resource` objects whose manifests are parsed by `Ppt::CodeIntrospection::Manifest` (from `ppt/code_introspection.rb`).
|
|
262
|
+
7. The coverage report is serialised through **`output.rb`** as YAML/JSON/text, optionally written to a file via **`files.rb`**'s `Writer`.
|
|
263
|
+
|
|
264
|
+
Every other command follows the same shape: `cli/<name>.rb` parses options → top-level domain module orchestrates → domain classes do the work → `Output` writes the result.
|