cem_acpt 0.11.0 → 0.11.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.worktreeinclude +1 -0
  4. data/CLAUDE.md +64 -25
  5. data/Gemfile.lock +1 -1
  6. data/README.md +20 -7
  7. data/docs/ARCHITECTURE.md +1042 -0
  8. data/docs/rfcs/0000-template.md +54 -0
  9. data/docs/rfcs/0001-fix-bolt-missing-skip-path.md +105 -0
  10. data/docs/rfcs/0002-fix-default-character-substitutions.md +119 -0
  11. data/docs/rfcs/0003-windows-image-builder-template.md +110 -0
  12. data/docs/rfcs/0004-image-name-truncation-off-by-one.md +108 -0
  13. data/docs/rfcs/0005-os-dispatch-replace-windows-heuristic.md +117 -0
  14. data/docs/rfcs/0006-configurable-windows-bucket.md +96 -0
  15. data/docs/rfcs/0007-logging-quiet-and-typos.md +121 -0
  16. data/docs/rfcs/0008-namespace-platform-classes.md +110 -0
  17. data/docs/rfcs/0009-bolt-log-formatter-cleanup.md +111 -0
  18. data/docs/rfcs/0010-dead-code-cleanup.md +83 -0
  19. data/docs/rfcs/0011-provisioner-factory-consistency.md +89 -0
  20. data/docs/rfcs/README.md +34 -0
  21. data/lib/cem_acpt/cli.rb +10 -1
  22. data/lib/cem_acpt/config/cem_acpt.rb +4 -1
  23. data/lib/cem_acpt/image_builder/errors.rb +24 -0
  24. data/lib/cem_acpt/image_builder.rb +28 -1
  25. data/lib/cem_acpt/image_name_builder.rb +8 -1
  26. data/lib/cem_acpt/platform/gcp.rb +112 -106
  27. data/lib/cem_acpt/platform.rb +21 -19
  28. data/lib/cem_acpt/provision/terraform/linux.rb +1 -1
  29. data/lib/cem_acpt/provision/terraform/os_data.rb +23 -0
  30. data/lib/cem_acpt/provision/terraform/windows.rb +7 -1
  31. data/lib/cem_acpt/provision/terraform.rb +20 -16
  32. data/lib/cem_acpt/test_runner/log_formatter/bolt_summary_results_formatter.rb +2 -1
  33. data/lib/cem_acpt/test_runner/log_formatter.rb +0 -1
  34. data/lib/cem_acpt/test_runner.rb +21 -8
  35. data/lib/cem_acpt/utils/winrm_runner.rb +4 -3
  36. data/lib/cem_acpt/utils.rb +0 -12
  37. data/lib/cem_acpt/version.rb +1 -1
  38. data/lib/cem_acpt.rb +19 -7
  39. data/specifications/CEM-6713.md +165 -0
  40. data/specifications/CEM-6714.md +271 -0
  41. data/specifications/CEM-6715.md +133 -0
  42. data/specifications/CEM-6716.md +160 -0
  43. data/specifications/CEM-6717.md +239 -0
  44. data/specifications/CEM-6718.md +120 -0
  45. data/specifications/CEM-6719.md +173 -0
  46. metadata +26 -11
  47. data/.claude/settings.local.json +0 -7
  48. data/lib/cem_acpt/action_result.rb +0 -91
  49. data/lib/cem_acpt/puppet_helpers.rb +0 -38
  50. data/lib/cem_acpt/test_runner/log_formatter/bolt_error_formatter.rb +0 -65
  51. data/lib/cem_acpt/test_runner/log_formatter/bolt_output_formatter.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e3e1c15beb777d80ea6a65241d1433901f6d627eabd4f11be9547f79e941c03
4
- data.tar.gz: bef63cc44f4e536da21599b01d00dc51524f60240e42ad22f23df6e5fadb36b7
3
+ metadata.gz: df61aa1c290a076e460b4c790babb19d0e0729e7d543feb96a9fb40e1589e50a
4
+ data.tar.gz: 800a652e59491e42f0e3fdd43db93e397956309e2b575d33e0f2c1497ebd8311
5
5
  SHA512:
6
- metadata.gz: 28f8b379445b92a4ff5e7df0fcd1a2f7385d7a6ee86c47bfdd825be23beb79c60752580e8c62c29f39d5fa5c3f623cc4834c4237679f74b19b847448ed16518f
7
- data.tar.gz: 681f5f556c8ddcdc523db369c207e19c96e7378a82299862d10002fa9cc2d02ea8e6a3a416d84fd68594d194218e415f1a137b511bd0786386e0330a714518c5
6
+ metadata.gz: a4a93419e474a066291ead08cbb28222f635f218b3df394b92f8c23d2fc1d63d55b9c5e240229c86db22a7b98e0e8673a5f13c7d02bd0d3633976942cc22be08
7
+ data.tar.gz: 614ecdad289b17a01ffcaea724aa928372cf578a4270f641e592549a6f2d017235646fe5ab8b3274e23801755935b6d7e17cdd39072aee28cbc7692b86e5b663
data/.gitignore CHANGED
@@ -16,3 +16,11 @@ profile.txt
16
16
 
17
17
  # local dev
18
18
  run_script.rb
19
+
20
+ # Ignore .env files which may contain sensitive information
21
+ .env
22
+ .env.*.local
23
+
24
+ # Local Claude configuration
25
+ .claude/settings.local.json
26
+ .claude/worktrees/
data/.worktreeinclude ADDED
@@ -0,0 +1 @@
1
+ .env
data/CLAUDE.md CHANGED
@@ -2,75 +2,113 @@
2
2
 
3
3
  ## What This Project Is
4
4
 
5
- `cem_acpt` is a Ruby gem providing an acceptance testing CLI for Puppet SCE (Security Compliance Enforcement), formerly known as Puppet CEM (Compliance Enforcement Modules). It provisions cloud nodes via Terraform, applies a Puppet manifest to the node, runs infrastructure tests via Goss, and tears everything down. It is also capable of running Puppet Bolt tests, which validate Bolt tasks and plans. A second binary, `cem_acpt_image`, builds the base VM images used by the test runner.
5
+ `cem_acpt` is a Ruby gem providing an acceptance testing CLI for Puppet SCE (Security Compliance Enforcement, formerly Puppet CEM / Compliance Enforcement Modules). It provisions cloud nodes via Terraform, applies a Puppet manifest, runs infrastructure tests via Goss (and optionally Bolt task/plan tests), then tears everything down. Both Linux nodes (over SSH) and Windows nodes (over WinRM) are supported.
6
+
7
+ A second binary, `cem_acpt_image`, builds the base VM images used by the test runner.
8
+
9
+ The gem name is intentionally unchanged after the CEM → SCE rename. The consuming Puppet modules were renamed to `sce_linux` / `sce_windows`, but this gem stays `cem_acpt`.
10
+
11
+ ## Where to Read More
12
+
13
+ Before diving into the summary below, skim:
14
+ - `docs/ARCHITECTURE.md` — fuller architecture writeup
15
+ - `docs/rfcs/` — design decisions (Windows image builder, OS dispatch, platform namespacing, logging behavior, etc.). Check here before proposing structural changes.
6
16
 
7
17
  ## Commands
8
18
 
9
19
  ```bash
10
20
  bundle install # Install dependencies
11
21
 
12
- bundle exec rake spec # Run all the spec tests
22
+ bundle exec rake spec # Run all spec tests
13
23
  bundle exec rake spec SPEC=spec/path/to/file_spec.rb # Run a single spec file
14
24
 
15
25
  rubocop # Lint
16
26
  rubocop -a # Auto-fix lint issues
17
27
 
18
28
  bundle exec rake build # Build the gem (saves to pkg/cem_acpt-<semver>.gem)
19
- bundle exec gem install pkg/cem_acpt-X.X.X.gem # Install the gem with the given semver (X.X.X should be replaced with a version)
29
+ bundle exec gem install pkg/cem_acpt-X.X.X.gem # Install built gem
20
30
 
21
31
  bundle exec exe/cem_acpt -h # CLI help
22
- bundle exec exe/cem_acpt -Y # Print merged config (useful for debugging)
32
+ bundle exec exe/cem_acpt -Y # Print merged config as YAML
23
33
  bundle exec exe/cem_acpt -X # Explain config merge sources
24
34
  ```
25
35
 
26
- RuboCop target is Ruby 3.2. Line length limit is 200. Many complexity metrics (AbcSize, MethodLength, ClassLength) are disabled.
36
+ CI runs `bundle exec rake spec` on PRs against `main` (see `.github/workflows/spec.yml`). Lint is not currently gated in CI, but RuboCop should be clean before merging.
37
+
38
+ RuboCop targets Ruby 3.2 with a 200-char line limit. The config in `.rubocop.yml` is intentionally permissive — many cops (complexity, layout, style) are disabled. Check `.rubocop.yml` before assuming a rule is enforced.
27
39
 
28
40
  ## Architecture
29
41
 
30
42
  ### Entry Points
31
43
 
32
- - `exe/cem_acpt` `lib/cem_acpt.rb` dispatches to `TestRunner::Runner`
33
- - `exe/cem_acpt_image` → `lib/cem_acpt.rb` → dispatches to `ImageBuilder::TerraformBuilder`
34
- - CLI parsing lives in `lib/cem_acpt/cli.rb` (Ruby `OptionParser`)
44
+ - `exe/cem_acpt` and `exe/cem_acpt_image` both call into `CemAcpt.run` in `lib/cem_acpt.rb`, which dispatches on the command:
45
+ - `:cem_acpt` → `TestRunner::Runner`
46
+ - `:cem_acpt_image` `ImageBuilder::TerraformBuilder`
47
+ - `:print_yaml_config` / `:print_explain_config` → handle the `-Y` / `-X` debugging flags
48
+ - `:version` → prints gem version
49
+ - CLI parsing lives in `lib/cem_acpt/cli.rb` (Ruby `OptionParser`).
35
50
 
36
51
  ### Configuration System (`lib/cem_acpt/config/`)
37
52
 
38
- Config is merged from four sources, lowest to highest priority:
53
+ Config is built by merging four sources, with each later source overriding earlier ones:
54
+
39
55
  1. Environment variables (`CEM_ACPT_` prefix; nested keys use `__`)
40
56
  2. User config at `~/.cem_acpt/config.yaml`
41
57
  3. `--config FILE` option
42
58
  4. Other CLI flags
43
59
 
44
- `Config::Base` handles the merge logic via `deep_merge`. Subclasses `Config::CemAcpt` and `Config::CemAcptImage` define the schema for each command.
60
+ `Config::Base` handles the merge via `deep_merge`. `Config::CemAcpt` and `Config::CemAcptImage` define the schema for each command. Use `-Y` to print the merged result and `-X` to see which source contributed each value.
45
61
 
46
62
  ### Test Runner Lifecycle (`lib/cem_acpt/test_runner.rb`)
47
63
 
48
- 1. **Pre-provision** Build the Puppet module tarball (`Utils::Puppet`)
49
- 2. **Provision** Spin up GCP nodes via Terraform (`Provision::Terraform`), generate ephemeral SSH keys, install the module
50
- 3. **Execute** Run action groups: `:goss` (async, HTTP) and `:bolt` (sync, Puppet tasks)
51
- 4. **Cleanup** `terraform destroy` unless `--no-destroy-nodes`
64
+ 1. **Pre-provision** Build the Puppet module tarball (`Utils::Puppet`).
65
+ 2. **Provision** Spin up nodes via the configured platform (currently only GCP) using Terraform (`Provision::Terraform`), generate ephemeral SSH keys (or set up WinRM for Windows), and install the module.
66
+ 3. **Execute** Run action groups: `:goss` (async, HTTP) and `:bolt` (sync, Puppet tasks). Filter with `--only-actions` / `--except-actions`.
67
+ 4. **Cleanup** `terraform destroy` unless `--no-destroy-nodes`.
52
68
 
53
69
  ### Platform Abstraction (`lib/cem_acpt/platform/`)
54
70
 
55
- `Platform::Base` defines the interface; `Platform::Gcp` implements GCP-specific behaviour. Platforms are loaded dynamically by name from the config.
71
+ `Platform::Base` defines the interface; `Platform::TestBase` extends it for test-node platforms. `Platform::Gcp` is the only concrete implementation today, but platforms are loaded dynamically by name from config — so adding e.g. AWS means a new file here plus a Terraform tree under `lib/terraform/`.
56
72
 
57
73
  ### Actions (`lib/cem_acpt/actions.rb`)
58
74
 
59
- The `Actions` class orchestrates test execution. Action groups can be filtered with `--only-actions` / `--except-actions`. Goss actions run async via `async-http`; Bolt actions run synchronously.
75
+ The `Actions` class orchestrates test execution. Actions register themselves via `register_action`/`register_group` and run in `order` order. Goss actions run asynchronously via `async-http`; Bolt actions run synchronously.
76
+
77
+ ### Transports
78
+
79
+ - **SSH** (`lib/cem_acpt/utils/ssh.rb`) — Linux nodes
80
+ - **WinRM** (`lib/cem_acpt/utils/winrm_runner.rb`) — Windows nodes
81
+ - **Goss HTTP API** (`lib/cem_acpt/goss/api.rb`) — assertions, on a port exposed by the provisioned node
60
82
 
61
83
  ### Terraform Templates (`lib/terraform/`)
62
84
 
63
- Terraform HCL lives inside the gem under `lib/terraform/`. Paths:
64
- - `lib/terraform/gcp/linux/` and `lib/terraform/gcp/windows/` test node provisioning
65
- - `lib/terraform/image/gcp/linux/` image-building node provisioning
85
+ Terraform HCL ships inside the gem:
86
+ - `lib/terraform/gcp/linux/` and `lib/terraform/gcp/windows/` test-node provisioning
87
+ - `lib/terraform/image/gcp/linux/` and `lib/terraform/image/gcp/windows/` — image-building provisioning
66
88
 
67
89
  ### Logging (`lib/cem_acpt/logging/`)
68
90
 
69
- Supports simultaneous STDOUT + file logging. Pass `-I` / `--CI` for GitHub Actions–formatted output. Pass `--trace` to enable Ruby `TracePoint` debugging.
91
+ Supports simultaneous STDOUT + file logging. `-I` / `--CI` enables GitHub Actions–formatted output. `--trace` enables Ruby `TracePoint` debugging. Most subsystems include `CemAcpt::Logging` to get a `logger` method.
92
+
93
+ ## Where to Add Things
94
+
95
+ | Adding… | Touch |
96
+ | ----------------------------- | ---------------------------------------------------------------------------------------------- |
97
+ | A new platform (e.g. AWS) | `lib/cem_acpt/platform/<name>.rb` (subclass `Platform::TestBase`) + `lib/terraform/<name>/...` |
98
+ | A new action group | Register in `lib/cem_acpt/actions.rb`; add a subdir under `lib/cem_acpt/<group>/` |
99
+ | A new config option | Add to `lib/cem_acpt/config/cem_acpt.rb` (or `cem_acpt_image.rb`) and wire into `cli.rb` |
100
+ | A new Bolt helper | `lib/cem_acpt/bolt/` — see `inventory.rb`, `tasks.rb`, `tests.rb` for the existing pattern |
101
+ | A new utility (SSH/WinRM/etc) | `lib/cem_acpt/utils/` |
70
102
 
71
103
  ## Test Structure
72
104
 
73
- Acceptance test cases live under `spec/acceptance/` (in the consuming module, not this gem):
105
+ ### Unit tests (this repo)
106
+
107
+ Specs live under `spec/`, mirroring the layout of `lib/`. Fixtures live in `spec/fixtures/`. Run with `bundle exec rake spec`.
108
+
109
+ ### Acceptance tests (consuming module)
110
+
111
+ Acceptance test cases live in the **consuming module** (e.g. `sce_linux`, `sce_windows`), not in this gem. They follow this layout:
74
112
 
75
113
  ```
76
114
  spec/acceptance/<framework>_<os>-<version>_<firewall>_<profile>_<level>/
@@ -79,9 +117,10 @@ spec/acceptance/<framework>_<os>-<version>_<firewall>_<profile>_<level>/
79
117
  bolt.yaml # (optional) Bolt task assertions
80
118
  ```
81
119
 
82
- Unit tests mirror `lib/` under `spec/`. Fixtures are in `spec/fixtures/`.
83
-
84
120
  ## Conventions
85
121
 
86
- - Document all Ruby code using Yard comments
87
- - All changes should have tests
122
+ - Document Ruby code with YARD comments.
123
+ - All changes should have tests.
124
+ - Subsystem-specific error classes live alongside the subsystem (e.g. `lib/cem_acpt/bolt/errors.rb`); follow that pattern rather than reusing generic `StandardError`.
125
+ - Use `CemAcpt::Utils::FinalizerQueue` for ordered cleanup of provisioned resources rather than ad-hoc `ensure` blocks.
126
+ - Mix in `CemAcpt::Logging` to get a logger; don't instantiate one directly.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.11.0)
4
+ cem_acpt (0.11.1)
5
5
  async-http (>= 0.60, < 0.70)
6
6
  bcrypt_pbkdf (>= 1.0, < 2.0)
7
7
  deep_merge (>= 1.2, < 2.0)
data/README.md CHANGED
@@ -16,7 +16,7 @@ gem install cem_acpt
16
16
 
17
17
  ### Quickstart
18
18
 
19
- Make sure Terraform and the gcloud CLI are installed and in your PATH. Instructions for installing Terraform can be found [here](https://learn.hashicorp.com/tutorials/terraform/install-cli) and instructions for installing the gcloud CLI can be found [here](https://cloud.google.com/sdk/docs/install).Then, navigate to the root of the `cem_linux` module and run the following command:
19
+ Make sure Terraform and the gcloud CLI are installed and in your PATH. Instructions for installing Terraform can be found [here](https://learn.hashicorp.com/tutorials/terraform/install-cli) and instructions for installing the gcloud CLI can be found [here](https://cloud.google.com/sdk/docs/install).Then, navigate to the root of the `sce_linux` module and run the following command:
20
20
 
21
21
  ```bash
22
22
  cem_acpt --config ./cem_acpt_config.yaml
@@ -140,7 +140,7 @@ All Bolt tasks are ran with the `--format json` flag, which returns a JSON docum
140
140
 
141
141
  Example:
142
142
 
143
- In this example, we will go over how a Bolt task's output would be evaluated by a Bolt test hash. This example assumes one Bolt task named `cem_linux::audit_sssd_certmap` that takes no parameters was ran successfully against two nodes.
143
+ In this example, we will go over how a Bolt task's output would be evaluated by a Bolt test hash. This example assumes one Bolt task named `sce_linux::audit_sssd_certmap` that takes no parameters was ran successfully against two nodes.
144
144
 
145
145
  Bolt task JSON output:
146
146
 
@@ -150,7 +150,7 @@ Bolt task JSON output:
150
150
  {
151
151
  "target":"35.212.146.14",
152
152
  "action":"task",
153
- "object":"cem_linux::audit_sssd_certmap",
153
+ "object":"sce_linux::audit_sssd_certmap",
154
154
  "status":"success",
155
155
  "value":{
156
156
  "sssd_certmap_exists":false
@@ -159,7 +159,7 @@ Bolt task JSON output:
159
159
  {
160
160
  "target":"35.212.197.53",
161
161
  "action":"task",
162
- "object":"cem_linux::audit_sssd_certmap",
162
+ "object":"sce_linux::audit_sssd_certmap",
163
163
  "status":"success",
164
164
  "value":{
165
165
  "sssd_certmap_exists":false
@@ -174,7 +174,7 @@ Bolt task JSON output:
174
174
  Bolt test hash in `bolt.yaml`:
175
175
 
176
176
  ```yaml
177
- 'cem_linux::audit_sssd_certmap':
177
+ 'sce_linux::audit_sssd_certmap':
178
178
  status: 'success'
179
179
  value:
180
180
  match: 'false'
@@ -335,6 +335,19 @@ images:
335
335
 
336
336
  See [sample_config.yaml](sample_config.yaml) for a more complete example.
337
337
 
338
- ### Testing with cem_windows
338
+ ### Testing with sce_windows
339
339
 
340
- While testing with cem_windows follows pretty much the same outline as cem_linux, there are a few extra step that we have to do when bootstrapping the generated node. Two of the most prominents steps are enabling long path and using NSSM to start the goss service. When we enable long path on Windows, it allows the command `puppet module install` to install dependencies correctly (specifically the dsc modules). As for [NSSM](https://nssm.cc/), stands for Non-sucking service manager, it is necessary for us to use this tool because without it, we will not be able to create services for Goss. Windows services cannot run from an executable but rather through a Windows service project that can be build with Visual Studio. NSSM allows us to bypass having to create Windows service project for Goss and create services directly from the Goss executable.
340
+ While testing with sce_windows follows pretty much the same outline as sce_linux, there are a few extra step that we have to do when bootstrapping the generated node. Two of the most prominents steps are enabling long path and using NSSM to start the goss service. When we enable long path on Windows, it allows the command `puppet module install` to install dependencies correctly (specifically the dsc modules). As for [NSSM](https://nssm.cc/), stands for Non-sucking service manager, it is necessary for us to use this tool because without it, we will not be able to create services for Goss. Windows services cannot run from an executable but rather through a Windows service project that can be build with Visual Studio. NSSM allows us to bypass having to create Windows service project for Goss and create services directly from the Goss executable.
341
+
342
+ #### Configuring the GCS bucket
343
+
344
+ The Windows test path uploads the Puppet module tarball to a GCS bucket so the test instance can `gcloud storage cp` it back down. The bucket name is configurable via `platform.gcp.windows_bucket` (default: `win_cem_acpt`):
345
+
346
+ ```yaml
347
+ platform:
348
+ name: gcp
349
+ gcp:
350
+ windows_bucket: my-org-cem-acpt
351
+ ```
352
+
353
+ Alternatively, pass `--windows-bucket BUCKET` on the CLI or set `CEM_ACPT_PLATFORM__GCP__WINDOWS_BUCKET` in the environment. The bucket must exist and be writable by the account running `cem_acpt`; it must also be readable by the service account attached to the Windows test instance.