train-k8s-container-mitre 2.0.3 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6aef3c36a97fd15eb144078a356e94c15711cad2ce7f267fd76a68d2d96043ef
4
- data.tar.gz: fb7929665b4f7cac1d057f6277ca86defa5f28511a040fac38aff31b4adf762c
3
+ metadata.gz: 6255dfedd08c1ccc04f6c69fdd56f530f927ece9876c248813ceabe38ab93134
4
+ data.tar.gz: 4976598e8fec6ae7274a468be4aedda447251dc66c59acf10c0af924b47b1be2
5
5
  SHA512:
6
- metadata.gz: 1625625532721a6da204352a46e4ee65168c21b68a9ef03bb660613fa78a03acded5d370ad1ac6ab63f6fb5faad79d3c6db7fd1cc915715c5e503b16f6b611cb
7
- data.tar.gz: fea6a3be4230ee420687fd5d116145eba00b8693d9706dfed4581253ee56cb0410b45ee8359090b7c1daba67964155a388999f817425b145ff9db369737e2ddd
6
+ metadata.gz: '0959c3bbc96a96c717f0f4129ef6612ac874e599920bfd399179423e7884745accee2d9415473fa0e0dc7d50061aae01db81343be7dd4883e55465019716d9bc'
7
+ data.tar.gz: 3085e763b733098b172a3c73e9eb06698dd54f1632d65a0fe6b2545c7ea4dd5056a5ad49bc38cf37e469d19beb3a88dd7629b7243a8d9d848fc57a0e106153d8
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "2.0.3"
2
+ ".": "2.1.1"
3
3
  }
data/ARCHITECTURE.md ADDED
@@ -0,0 +1,546 @@
1
+ # Architecture Overview
2
+
3
+ This document provides a technical overview of the train-k8s-container plugin architecture.
4
+
5
+ ## High-Level Architecture
6
+
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────────────────────────┐
9
+ │ InSpec / Cinc Auditor │
10
+ │ │
11
+ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
12
+ │ │ Profile │───▶│ Resources │───▶│ Train │───▶│ Transport │ │
13
+ │ │ Controls │ │ (file, user │ │ Framework │ │ Plugin │ │
14
+ │ └─────────────┘ │ package..) │ └─────────────┘ └──────┬──────┘ │
15
+ └──────────────────────────────────────────────────────────────────┼─────────┘
16
+
17
+ ┌────────────────────────────────────┘
18
+
19
+ ┌─────────────────────────────────────────────────────────────────────────────┐
20
+ │ train-k8s-container Plugin │
21
+ │ │
22
+ │ ┌───────────────────────────────────────────────────────────────────────┐ │
23
+ │ │ Connection │ │
24
+ │ │ • URI parsing (k8s-container://namespace/pod/container) │ │
25
+ │ │ • Parameter validation │ │
26
+ │ │ • File operations via Train::File::Remote::Linux │ │
27
+ │ └───────────────────────────────────┬───────────────────────────────────┘ │
28
+ │ │ │
29
+ │ ┌────────────────────────────┼────────────────────────────┐ │
30
+ │ ▼ ▼ ▼ │
31
+ │ ┌─────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ │
32
+ │ │ ShellDetector │ │ KubectlExecClient │ │ Platform │ │
33
+ │ │ │ │ │ │ │ │
34
+ │ │ • OS detection │ │ • Command execution │ │ • Detect+Context│ │
35
+ │ │ • Shell probing │ │ • PTY sessions │ │ • OS families │ │
36
+ │ │ • Linux family │ │ • Retry handling │ │ • Kubernetes │ │
37
+ │ └────────┬────────┘ └──────────┬──────────┘ │ context │ │
38
+ │ │ │ └─────────────────┘ │
39
+ │ │ ┌──────────┴──────────┐ │
40
+ │ │ ▼ ▼ │
41
+ │ │ ┌─────────────────┐ ┌─────────────────┐ │
42
+ │ │ │ SessionManager │ │ ResultProcessor │ │
43
+ │ │ │ (Singleton) │ │ │ │
44
+ │ │ │ │ │ • ANSI cleanup │ │
45
+ │ │ │ • Connection │ │ • Exit codes │ │
46
+ │ │ │ pooling │ │ • Error detect │ │
47
+ │ │ │ • Thread-safe │ └─────────────────┘ │
48
+ │ │ └────────┬────────┘ │
49
+ │ │ │ │
50
+ │ │ ▼ │
51
+ │ │ ┌─────────────────┐ │
52
+ │ │ │ PtySession │ │
53
+ │ │ │ │ │
54
+ │ │ │ • Persistent │ │
55
+ │ │ │ shell session │ │
56
+ │ │ │ • Command queue │ │
57
+ │ │ └─────────────────┘ │
58
+ │ │ │
59
+ │ ┌────────┴──────────────────────────────────────────────────────────┐ │
60
+ │ │ Support Modules │ │
61
+ │ │ │ │
62
+ │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │
63
+ │ │ │ KubectlCommand │ │ KubernetesName │ │ AnsiSanitizer │ │ │
64
+ │ │ │ Builder │ │ Validator │ │ │ │ │
65
+ │ │ │ │ │ │ │ • CVE-2021-25743 │ │ │
66
+ │ │ │ • Shell escaping │ │ • RFC 1123 │ │ mitigation │ │ │
67
+ │ │ │ • Windows/Unix │ │ • Injection │ │ • ANSI stripping │ │ │
68
+ │ │ └──────────────────┘ │ prevention │ └──────────────────┘ │ │
69
+ │ │ └──────────────────┘ │ │
70
+ │ └────────────────────────────────────────────────────────────────────┘ │
71
+ └─────────────────────────────────────────────────────────────────────────────┘
72
+
73
+
74
+ ┌─────────────────────────────────────────────────────────────────────────────┐
75
+ │ kubectl exec │
76
+ │ │
77
+ │ kubectl exec --stdin <pod> -n <namespace> -c <container> -- <cmd> │
78
+ └─────────────────────────────────────────────────────────────────────────────┘
79
+
80
+
81
+ ┌─────────────────────────────────────────────────────────────────────────────┐
82
+ │ Kubernetes Cluster │
83
+ │ │
84
+ │ ┌─────────────────────────────────────────────────────────────────┐ │
85
+ │ │ Target Pod │ │
86
+ │ │ ┌─────────────────────────────────────────────────────────┐ │ │
87
+ │ │ │ Target Container │ │ │
88
+ │ │ │ │ │ │
89
+ │ │ │ /bin/bash, /bin/sh, /bin/ash ──or── distroless │ │ │
90
+ │ │ │ │ │ │
91
+ │ │ └─────────────────────────────────────────────────────────┘ │ │
92
+ │ └─────────────────────────────────────────────────────────────────┘ │
93
+ └─────────────────────────────────────────────────────────────────────────────┘
94
+ ```
95
+
96
+ ## Command Execution Flow
97
+
98
+ ```
99
+ ┌──────────────────────────────────────────────────────────────────────────────┐
100
+ │ Command Execution Flow │
101
+ └──────────────────────────────────────────────────────────────────────────────┘
102
+
103
+ InSpec Control Plugin Components kubectl
104
+ ───────────── ───────────────── ───────
105
+
106
+ │ command('whoami')
107
+
108
+ ┌─────────┐
109
+ │ Control │
110
+ └────┬────┘
111
+
112
+
113
+ ┌─────────────────┐
114
+ │ Connection │ ─── parse URI, validate params
115
+ └────────┬────────┘
116
+
117
+
118
+ ┌─────────────────┐
119
+ │ KubectlExec │
120
+ │ Client │
121
+ └────────┬────────┘
122
+
123
+ │ Check for existing session
124
+
125
+ ┌─────────────────┐ ┌─────────────────┐
126
+ │ SessionManager │────▶│ PtySession │ (if pooled session exists)
127
+ │ (Singleton) │ │ (persistent) │
128
+ └────────┬────────┘ └────────┬────────┘
129
+ │ │
130
+ │ No session? │ Has session?
131
+ │ Create new │ Reuse
132
+ ▼ ▼
133
+ ┌─────────────────┐ ┌─────────────────┐
134
+ │ KubectlCommand │ │ Send command │
135
+ │ Builder │ │ via PTY pipe │
136
+ └────────┬────────┘ └────────┬────────┘
137
+ │ │
138
+ ▼ ▼
139
+ ┌─────────────────┐ ┌─────────────────┐
140
+ │ Mixlib:: │ │ Read response │
141
+ │ ShellOut │ │ until marker │
142
+ └────────┬────────┘ └────────┬────────┘
143
+ │ │
144
+ ▼ ▼
145
+ ┌───────────────────────────────┐
146
+ │ kubectl exec │ ───▶ Container
147
+ └───────────────┬───────────────┘
148
+
149
+
150
+ ┌─────────────────┐
151
+ │ ResultProcessor │
152
+ │ │
153
+ │ • Parse exit │
154
+ │ code │
155
+ │ • Strip ANSI │
156
+ │ • Detect errors │
157
+ └────────┬────────┘
158
+
159
+
160
+ ┌─────────────────┐
161
+ │ RetryHandler │ ─── Retry on transient errors
162
+ │ │ (exponential backoff)
163
+ └────────┬────────┘
164
+
165
+
166
+ Train::Extras::CommandResult
167
+ (stdout, stderr, exit_code)
168
+ ```
169
+
170
+ ## File Structure
171
+
172
+ ```
173
+ lib/train-k8s-container/
174
+ ├── transport.rb # Train plugin registration
175
+ ├── connection.rb # Main connection class
176
+ ├── kubectl_exec_client.rb # Command execution engine
177
+ ├── platform.rb # OS detection (Detect+Context)
178
+ ├── version.rb # Version constant
179
+
180
+ ├── session_manager.rb # Connection pool (Singleton)
181
+ ├── pty_session.rb # Persistent PTY shell session
182
+
183
+ ├── shell_detector.rb # Shell/OS detection
184
+ ├── kubectl_command_builder.rb # Command string building
185
+ ├── result_processor.rb # Output parsing & validation
186
+ ├── retry_handler.rb # Exponential backoff retry
187
+
188
+ ├── ansi_sanitizer.rb # ANSI escape removal (CVE fix)
189
+ ├── kubernetes_name_validator.rb # RFC 1123 validation
190
+ └── errors.rb # Custom error classes
191
+ ```
192
+
193
+ ## Component Details
194
+
195
+ ### Core Components
196
+
197
+ #### Transport (`transport.rb`)
198
+
199
+ Registers the `k8s-container` transport with Train:
200
+
201
+ ```ruby
202
+ module TrainPlugins::K8sContainer
203
+ class Transport < Train.plugin(1)
204
+ name 'k8s-container'
205
+ # ...
206
+ end
207
+ end
208
+ ```
209
+
210
+ Connection options:
211
+ - `pod` - Target pod name (required)
212
+ - `container_name` - Target container (required)
213
+ - `namespace` - Kubernetes namespace (default: `default`)
214
+ - `kubeconfig` - Path to kubeconfig file
215
+
216
+ #### Connection (`connection.rb`)
217
+
218
+ Main connection handler:
219
+ - Parses URI format: `k8s-container://<namespace>/<pod>/<container>`
220
+ - Validates required parameters (pod, container)
221
+ - Provides `run_command()` for command execution
222
+ - Provides file access via `Train::File::Remote::Linux`
223
+
224
+ #### KubectlExecClient (`kubectl_exec_client.rb`)
225
+
226
+ Command execution engine:
227
+ - Detects available shell via `ShellDetector`
228
+ - Routes commands through `SessionManager` for pooling
229
+ - Falls back to direct execution for distroless containers
230
+ - Integrates `RetryHandler` for transient errors
231
+
232
+ #### Platform (`platform.rb`)
233
+
234
+ OS detection using **Detect+Context** pattern:
235
+
236
+ ```ruby
237
+ def platform
238
+ # 1. Use Train's scanner to detect actual OS
239
+ @platform = Train::Platforms::Detect.scan(self)
240
+
241
+ # 2. Add Kubernetes context families
242
+ add_k8s_families(@platform)
243
+
244
+ @platform
245
+ end
246
+ ```
247
+
248
+ Result: `os.linux?` returns `true` while `platform.families` includes `kubernetes`, `container`.
249
+
250
+ ### Session Management (Connection Pooling)
251
+
252
+ #### SessionManager (`session_manager.rb`)
253
+
254
+ Thread-safe singleton that pools PTY sessions:
255
+
256
+ ```ruby
257
+ class SessionManager
258
+ include Singleton
259
+
260
+ # One session per namespace/pod/container
261
+ def get_session(session_key, kubectl_cmd:, shell:, timeout:, logger:)
262
+ @mutex.synchronize do
263
+ unless @sessions[session_key]&.healthy?
264
+ @sessions[session_key] = PtySession.new(...)
265
+ @sessions[session_key].connect
266
+ end
267
+ @sessions[session_key]
268
+ end
269
+ end
270
+ end
271
+ ```
272
+
273
+ Benefits:
274
+ - Reuses kubectl exec connections across multiple commands
275
+ - Significantly faster for profiles with many controls
276
+ - Automatic cleanup on session failure or process exit
277
+
278
+ #### PtySession (`pty_session.rb`)
279
+
280
+ Persistent PTY-based shell session:
281
+
282
+ ```ruby
283
+ # Instead of spawning kubectl for each command:
284
+ kubectl exec pod -c container -- /bin/sh -c "command1"
285
+ kubectl exec pod -c container -- /bin/sh -c "command2"
286
+ kubectl exec pod -c container -- /bin/sh -c "command3"
287
+
288
+ # Maintains one persistent session:
289
+ kubectl exec pod -c container -- /bin/bash
290
+ > command1
291
+ > command2
292
+ > command3
293
+ ```
294
+
295
+ Features:
296
+ - Uses Ruby's `PTY.spawn` for interactive session
297
+ - Sends commands with exit code markers
298
+ - Parses output and extracts real exit codes
299
+ - Health checking via process status
300
+
301
+ ### Shell & OS Detection
302
+
303
+ #### ShellDetector (`shell_detector.rb`)
304
+
305
+ Detects available shell in container:
306
+
307
+ ```
308
+ Detection Order (Unix):
309
+ 1. /bin/bash - Ubuntu, Debian, RHEL
310
+ 2. /bin/sh - POSIX standard
311
+ 3. /bin/ash - Alpine, BusyBox
312
+ 4. /bin/zsh - Less common
313
+
314
+ Detection Order (Windows):
315
+ 1. cmd.exe - Command prompt
316
+ 2. powershell.exe - PowerShell 5.1
317
+ 3. pwsh.exe - PowerShell Core
318
+ ```
319
+
320
+ Also detects Linux distribution family from `/etc/os-release`:
321
+ - Debian family: ubuntu, debian, linuxmint, kali
322
+ - RedHat family: rhel, centos, fedora, rocky, almalinux
323
+ - Alpine, Arch, SUSE, Gentoo
324
+
325
+ ### Command Building & Processing
326
+
327
+ #### KubectlCommandBuilder (`kubectl_command_builder.rb`)
328
+
329
+ Builds properly escaped kubectl commands:
330
+
331
+ ```ruby
332
+ builder = KubectlCommandBuilder.new(
333
+ kubectl_path: '/usr/bin/kubectl',
334
+ pod: 'my-pod',
335
+ namespace: 'default',
336
+ container_name: 'app'
337
+ )
338
+
339
+ # Unix shell
340
+ builder.with_shell('/bin/bash', 'cat /etc/passwd')
341
+ # => "kubectl exec --stdin my-pod -n default -c app -- /bin/bash -c 'cat /etc/passwd'"
342
+
343
+ # Windows shell
344
+ builder.with_windows_shell('cmd.exe', 'dir')
345
+ # => "kubectl exec --stdin my-pod -n default -c app -- cmd.exe /c 'dir'"
346
+
347
+ # Direct binary (distroless)
348
+ builder.direct_binary('cat /etc/os-release')
349
+ # => "kubectl exec --stdin my-pod -n default -c app -- cat /etc/os-release"
350
+ ```
351
+
352
+ #### ResultProcessor (`result_processor.rb`)
353
+
354
+ Processes command output:
355
+
356
+ 1. **Validation**: Detects connection errors and silent failures
357
+ 2. **Sanitization**: Strips ANSI sequences, normalizes line endings
358
+ 3. **Exit code parsing**: Extracts real exit code from kubectl messages
359
+
360
+ Connection error patterns detected:
361
+ - `error dialing backend`
362
+ - `connection refused`
363
+ - `pods "name" not found`
364
+ - `Error from server`
365
+
366
+ ### Security Components
367
+
368
+ #### AnsiSanitizer (`ansi_sanitizer.rb`)
369
+
370
+ Addresses **CVE-2021-25743** (terminal escape sequence injection):
371
+
372
+ ```ruby
373
+ module AnsiSanitizer
374
+ CSI_REGEX = /\e\[([;\d]+)?[A-Za-z]/ # Colors, cursor
375
+ OSC_REGEX = /\e\][^\a]*\a/ # Terminal title
376
+ CURSOR_REGEX = /\e\[A|\e\[C|\e\[K/ # Movement
377
+
378
+ def self.sanitize(text)
379
+ # Remove all ANSI escape sequences
380
+ end
381
+ end
382
+ ```
383
+
384
+ #### KubernetesNameValidator (`kubernetes_name_validator.rb`)
385
+
386
+ Validates names per **RFC 1123** DNS subdomain rules:
387
+
388
+ ```ruby
389
+ VALID_NAME_REGEX = /\A[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)?\z/
390
+ MAX_NAME_LENGTH = 253
391
+
392
+ def self.validate!(name, resource_type:)
393
+ # Prevents command injection via malformed names
394
+ end
395
+ ```
396
+
397
+ ### Error Handling
398
+
399
+ #### RetryHandler (`retry_handler.rb`)
400
+
401
+ Exponential backoff for transient errors:
402
+
403
+ ```ruby
404
+ RetryHandler.with_retry(max_retries: 3, logger: logger) do
405
+ # Network operation
406
+ end
407
+
408
+ # Retry delays: 1s, 2s, 4s (exponential backoff)
409
+ ```
410
+
411
+ Retryable errors:
412
+ - `NetworkError` - Silent failures, timeouts
413
+ - `ConnectionError` - kubectl connection issues
414
+
415
+ #### Custom Errors (`errors.rb`)
416
+
417
+ ```ruby
418
+ K8sContainerError < Train::TransportError # Base class
419
+ KubectlNotFoundError # kubectl binary not in PATH
420
+ ContainerNotFoundError # Container doesn't exist in pod
421
+ PodNotFoundError # Pod doesn't exist in namespace
422
+ ShellNotAvailableError # Distroless container, no shell
423
+ ```
424
+
425
+ ## Platform Detection Deep Dive
426
+
427
+ ### Why "Detect + Context" Pattern?
428
+
429
+ When connecting to an **operating system** (container, VM, bare metal), Train must detect the actual OS for InSpec resources to work correctly.
430
+
431
+ **Wrong approach** - `force_platform!('k8s-container')`:
432
+ - Platform name becomes `k8s-container` instead of `ubuntu`
433
+ - `os.linux?` returns `false`
434
+ - Resources like `user`, `package`, `service` fail
435
+
436
+ **Correct approach** - Detect + Context:
437
+ - Detect actual OS: `ubuntu`, `alpine`, `centos`
438
+ - Add context families: `kubernetes`, `container`
439
+ - `os.linux?` returns `true` ✓
440
+ - Resources work correctly ✓
441
+
442
+ ### Detection Commands
443
+
444
+ Train's scanner executes these to identify the OS:
445
+
446
+ ```bash
447
+ uname -s # "Linux"
448
+ uname -m # Architecture
449
+ cat /etc/os-release # OS identification
450
+ cat /etc/debian_version # Debian family
451
+ cat /etc/alpine-release # Alpine
452
+ cat /etc/redhat-release # RHEL family
453
+ ```
454
+
455
+ ### Result
456
+
457
+ ```bash
458
+ $ cinc-auditor detect -t k8s-container:///my-pod/my-container
459
+
460
+ Name: ubuntu
461
+ Families: debian, linux, unix, os, kubernetes, container
462
+ Release: 22.04
463
+ Arch: aarch64
464
+ ```
465
+
466
+ ## URI Format
467
+
468
+ ```
469
+ k8s-container://<namespace>/<pod>/<container>
470
+ ```
471
+
472
+ | Component | Required | Default | Example |
473
+ |-----------|----------|---------|---------|
474
+ | namespace | No | `default` | `production` |
475
+ | pod | Yes | - | `web-app-7d4b8c9f-x2k4m` |
476
+ | container | Yes | - | `nginx` |
477
+
478
+ **Examples:**
479
+ ```bash
480
+ # Full URI
481
+ k8s-container://production/web-app/nginx
482
+
483
+ # Default namespace
484
+ k8s-container:///my-pod/my-container
485
+ ```
486
+
487
+ ## Testing Architecture
488
+
489
+ ### Test Structure
490
+
491
+ ```
492
+ spec/
493
+ ├── train-k8s-container/ # Unit tests (mocked)
494
+ │ ├── connection_spec.rb
495
+ │ ├── kubectl_exec_client_spec.rb
496
+ │ ├── platform_spec.rb
497
+ │ ├── shell_detector_spec.rb
498
+ │ ├── session_manager_spec.rb
499
+ │ └── ...
500
+
501
+ └── integration/ # Integration tests (real cluster)
502
+ ├── platform_detection_spec.rb
503
+ ├── command_execution_spec.rb
504
+ └── ...
505
+ ```
506
+
507
+ ### CI Matrix
508
+
509
+ | Test Type | Ruby | Kubernetes | Description |
510
+ |-----------|------|------------|-------------|
511
+ | Unit | 3.1, 3.2, 3.3 | N/A | Mocked, fast |
512
+ | Integration | 3.1, 3.2, 3.3 | 1.29, 1.30, 1.31 | Real kind cluster |
513
+ | Pod-to-Pod | 3.3 | 1.30 | Scanner inside cluster |
514
+
515
+ ## Key Design Decisions
516
+
517
+ 1. **kubectl over Kubernetes Ruby client**
518
+ - Simpler dependency management
519
+ - Leverages user's existing kubeconfig and auth
520
+ - Works with any kubectl-compatible cluster
521
+
522
+ 2. **Connection pooling via PTY sessions**
523
+ - Dramatically improves performance for multi-control profiles
524
+ - Single kubectl process instead of one per command
525
+ - Thread-safe singleton pattern
526
+
527
+ 3. **Detect+Context over force_platform**
528
+ - Ensures InSpec resources work correctly
529
+ - Provides Kubernetes awareness via family tags
530
+ - Compatible with existing profiles
531
+
532
+ 4. **RFC 1123 validation**
533
+ - Prevents command injection via malformed names
534
+ - Enforces Kubernetes naming standards
535
+
536
+ 5. **ANSI sanitization (CVE-2021-25743)**
537
+ - Strips terminal escape sequences
538
+ - Prevents injection attacks via kubectl output
539
+
540
+ 6. **Cinc Auditor in CI**
541
+ - Open-source, license-free InSpec distribution
542
+ - No Chef license required for testing
543
+
544
+ 7. **OIDC trusted publishing**
545
+ - Secure gem publishing without API keys
546
+ - Leverages GitHub Actions identity
data/CHANGELOG.md CHANGED
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.1.1](https://github.com/mitre/train-k8s-container/compare/v2.1.0...v2.1.1) (2025-12-12)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Parse PR number from JSON in auto-merge step ([09a3667](https://github.com/mitre/train-k8s-container/commit/09a3667cb67010c58837d3ff1ddcf5b197dc3d0d))
14
+
15
+
16
+ ### Documentation
17
+
18
+ * Add ARCHITECTURE.md with technical overview ([acfe73a](https://github.com/mitre/train-k8s-container/commit/acfe73a5ad16faa9b481d0c7802d2a8f6f64efb9))
19
+ * Enhance ARCHITECTURE.md with comprehensive technical details ([519675d](https://github.com/mitre/train-k8s-container/commit/519675db04d3766ac3d00575989e748da738a7ea))
20
+ * Fix inaccurate claims in README acknowledgments ([fa2e53c](https://github.com/mitre/train-k8s-container/commit/fa2e53c0eee41638edfa04a583bdcea4fd7eb272))
21
+ * Update release process documentation for automated workflow ([23d1fcf](https://github.com/mitre/train-k8s-container/commit/23d1fcfb38b1415c12029564b92dbcb9df34715d))
22
+
23
+ ## [2.1.0](https://github.com/mitre/train-k8s-container/compare/v2.0.3...v2.1.0) (2025-12-12)
24
+
25
+
26
+ ### Features
27
+
28
+ * Enable auto-merge for release-please PRs ([f098f5a](https://github.com/mitre/train-k8s-container/commit/f098f5a150d5532b4def7702e9427448d65764bb))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * Remove duplicate push trigger from release workflow ([f1b4c87](https://github.com/mitre/train-k8s-container/commit/f1b4c872f8e1617c38149bc0172ba20e49ba3dc8))
34
+
8
35
  ## [2.0.3](https://github.com/mitre/train-k8s-container/compare/v2.0.2...v2.0.3) (2025-12-12)
9
36
 
10
37
 
data/CONTRIBUTING.md CHANGED
@@ -135,60 +135,149 @@ open coverage/index.html
135
135
  5. **CI Passing**: All GitHub Actions checks must pass
136
136
  6. **Merge**: Maintainers will merge approved PRs
137
137
 
138
- ## Release Process
138
+ ## Versioning and Commit Messages
139
+
140
+ This project uses [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/). Your commit message prefix determines how the version number changes.
141
+
142
+ **Official References:**
143
+ - [Conventional Commits Specification](https://www.conventionalcommits.org/en/v1.0.0/)
144
+ - [Angular Commit Message Guidelines](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#-commit-message-format) (original source)
145
+ - [Semantic Versioning](https://semver.org/)
146
+
147
+ ### Commit Prefix → Version Bump
148
+
149
+ | Commit Prefix | Version Change | When to Use |
150
+ |---------------|----------------|-------------|
151
+ | `feat:` | **Minor** (2.0.0 → 2.1.0) | New features, capabilities, or enhancements |
152
+ | `fix:` | **Patch** (2.0.0 → 2.0.1) | Bug fixes, corrections, error handling |
153
+ | `docs:` | **Patch** | Documentation changes only |
154
+ | `style:` | **Patch** | Code style, formatting (no logic change) |
155
+ | `refactor:` | **Patch** | Code restructuring (no behavior change) |
156
+ | `perf:` | **Patch** | Performance improvements |
157
+ | `test:` | **Patch** | Adding or updating tests |
158
+ | `chore:` | **Patch** | Maintenance, dependencies, tooling |
159
+ | `ci:` | **Patch** | CI/CD pipeline changes |
160
+ | `build:` | **Patch** | Build system changes |
161
+ | `revert:` | **Patch** | Reverting a previous commit |
162
+ | `feat!:` | **Major** (2.0.0 → 3.0.0) | Breaking changes (note the `!`) |
163
+ | `fix!:` | **Major** | Breaking bug fix |
164
+ | `BREAKING CHANGE:` | **Major** | In commit body, forces major bump |
165
+
166
+ ### Type Descriptions
167
+
168
+ - **feat**: A new feature for the user (not a build script feature)
169
+ - **fix**: A bug fix for the user (not a build script fix)
170
+ - **docs**: Documentation only changes (README, CONTRIBUTING, inline docs)
171
+ - **style**: Changes that don't affect code meaning (whitespace, formatting, semicolons)
172
+ - **refactor**: Code change that neither fixes a bug nor adds a feature
173
+ - **perf**: Code change that improves performance
174
+ - **test**: Adding missing tests or correcting existing tests
175
+ - **chore**: Changes to build process, auxiliary tools, libraries
176
+ - **ci**: Changes to CI configuration files and scripts
177
+ - **build**: Changes that affect the build system or external dependencies
178
+ - **revert**: Reverts a previous commit (include reverted commit SHA in body)
179
+
180
+ ### Examples
139
181
 
140
- Releases are automated using [release-please](https://github.com/googleapis/release-please) and managed by project maintainers.
182
+ ```bash
183
+ # Patch version bump (2.1.0 → 2.1.1)
184
+ git commit -m "fix: handle nil response in platform detection"
185
+ git commit -m "docs: update installation instructions"
186
+ git commit -m "chore: update rubocop dependency"
187
+ git commit -m "test: add integration tests for Alpine containers"
141
188
 
142
- ### How It Works
189
+ # Minor version bump (2.1.0 → 2.2.0)
190
+ git commit -m "feat: add support for Windows containers"
191
+ git commit -m "feat: add retry logic for transient kubectl failures"
143
192
 
144
- 1. **Commit with Conventional Commits**: Use prefixes like `feat:`, `fix:`, `docs:`, `chore:`
145
- - `feat:` triggers a minor version bump (e.g., 2.0.0 → 2.1.0)
146
- - `fix:` triggers a patch version bump (e.g., 2.0.0 → 2.0.1)
147
- - `feat!:` or `BREAKING CHANGE:` triggers a major version bump
193
+ # Major version bump (2.1.0 3.0.0)
194
+ git commit -m "feat!: change URI format to k8s://namespace/pod/container"
195
+ git commit -m "fix!: remove deprecated connection options"
196
+ ```
148
197
 
149
- 2. **Release PR Created Automatically**: When commits are pushed to `main`, release-please creates/updates a Release PR that:
150
- - Bumps the version in `VERSION` file
151
- - Updates `CHANGELOG.md` with commit messages
152
- - Shows the proposed version change
198
+ ### Commit Message Format
153
199
 
154
- 3. **Merge to Release**: When maintainers merge the Release PR:
155
- - A git tag is created (e.g., `v2.1.0`)
156
- - GitHub Actions builds and publishes the gem to RubyGems.org
157
- - A GitHub Release is created with auto-generated notes
200
+ ```
201
+ <type>(<optional scope>): <description>
158
202
 
159
- ### Example Workflow
203
+ [optional body]
160
204
 
205
+ [optional footer(s)]
206
+ ```
207
+
208
+ **Examples:**
161
209
  ```bash
162
- # Make changes with conventional commit messages
163
- git commit -m "feat: add support for Windows containers"
164
- git push origin main
210
+ # Simple
211
+ git commit -m "fix: handle empty shell response"
165
212
 
166
- # release-please automatically creates a PR like:
167
- # "chore(main): release 2.1.0"
213
+ # With scope
214
+ git commit -m "feat(platform): add FreeBSD detection"
168
215
 
169
- # After review, maintainer merges the PR
170
- # Tag v2.1.0 is created
171
- # → Gem is published to RubyGems.org
216
+ # With body
217
+ git commit -m "feat: add Windows container support
218
+
219
+ This adds support for Windows containers running in Kubernetes.
220
+ Tested with Windows Server 2022 and Windows Server Core images."
221
+
222
+ # Breaking change with body
223
+ git commit -m "feat!: require Ruby 3.1+
224
+
225
+ BREAKING CHANGE: Ruby 2.7 and 3.0 are no longer supported.
226
+ This allows us to use pattern matching and other Ruby 3.1 features."
172
227
  ```
173
228
 
174
- ### Manual Releases (Emergency Only)
229
+ ## Release Process
175
230
 
176
- For hotfixes that need immediate release without waiting for release-please:
231
+ Releases are **fully automated** using [release-please](https://github.com/googleapis/release-please) with auto-merge enabled.
177
232
 
178
- ```bash
179
- # Update VERSION manually
180
- echo "2.0.2" > VERSION
233
+ ### How It Works
234
+
235
+ 1. **Release PR Created Automatically**: When commits are pushed to `main`, release-please creates/updates a Release PR with auto-merge enabled that:
236
+ - Bumps the version in `lib/train-k8s-container/version.rb`
237
+ - Updates `CHANGELOG.md` with commit messages
238
+ - Shows the proposed version change
239
+
240
+ 2. **Auto-Merge When CI Passes**: The Release PR automatically merges once all CI checks pass:
241
+ - Unit tests (Ruby 3.1, 3.2, 3.3)
242
+ - Integration tests (Kubernetes 1.29, 1.30, 1.31)
243
+ - Security audit
244
+ - Branch protection enforces all checks must pass
245
+
246
+ 3. **Automatic Publishing**: After merge, release-please creates a GitHub Release which triggers:
247
+ - Gem build
248
+ - Publish to RubyGems.org (via OIDC trusted publishing)
249
+ - Gem artifact attached to GitHub Release
250
+
251
+ ### Complete Automated Flow
181
252
 
182
- # Update CHANGELOG.md manually
253
+ ```
254
+ Push commit → CI runs → Release PR created (auto-merge enabled)
255
+
256
+ CI passes on PR
257
+
258
+ PR auto-merges
259
+
260
+ GitHub Release created
261
+
262
+ Gem published to RubyGems
263
+ ```
264
+
265
+ ### Example
266
+
267
+ ```bash
268
+ # Make changes with conventional commit messages
269
+ git commit -m "feat: add support for Windows containers"
270
+ git push origin main
183
271
 
184
- # Commit, tag, and push
185
- git add VERSION CHANGELOG.md
186
- git commit -m "chore: release v2.0.2"
187
- git tag v2.0.2
188
- git push origin main --tags
272
+ # Everything else is automatic:
273
+ # 1. release-please creates PR: "chore(main): release 2.2.0"
274
+ # 2. CI runs on the PR
275
+ # 3. PR auto-merges when CI passes
276
+ # 4. Tag v2.2.0 is created
277
+ # 5. Gem is published to RubyGems.org
189
278
  ```
190
279
 
191
- **Note:** Manual releases should be rare. Prefer the automated release-please flow.
280
+ No manual intervention required for releases.
192
281
 
193
282
  ## Getting Help
194
283
 
data/DEVELOPMENT.md CHANGED
@@ -295,29 +295,24 @@ See `.github/workflows/ci.yml` for details.
295
295
 
296
296
  ## Releasing
297
297
 
298
- Releases are automated using [release-please](https://github.com/googleapis/release-please).
298
+ Releases are **fully automated** using [release-please](https://github.com/googleapis/release-please) with auto-merge enabled. No manual intervention required.
299
299
 
300
- ### Automated Release Process (Recommended)
300
+ ### How It Works
301
301
 
302
- 1. **Make commits using Conventional Commits format**:
302
+ 1. **Push commits with Conventional Commits format**:
303
303
  ```bash
304
304
  git commit -m "feat: add Windows container support"
305
305
  git commit -m "fix: handle empty shell response"
306
- git commit -m "docs: update installation instructions"
307
- ```
308
-
309
- 2. **Push to main** - release-please will automatically create a Release PR:
310
- ```bash
311
306
  git push origin main
312
- # release-please creates PR: "chore(main): release 2.1.0"
313
307
  ```
314
308
 
315
- 3. **Review and merge the Release PR** - this triggers:
316
- - Version bump in `VERSION` file
317
- - `CHANGELOG.md` update
318
- - Git tag creation (e.g., `v2.1.0`)
319
- - Gem build and publish to RubyGems.org
320
- - GitHub Release creation
309
+ 2. **Automatic flow**:
310
+ - Release-please creates/updates a Release PR with auto-merge enabled
311
+ - CI runs on the PR (unit tests, integration tests, security audit)
312
+ - Branch protection requires all checks to pass
313
+ - PR auto-merges when CI is green
314
+ - Release-please creates a GitHub Release
315
+ - `release-tag.yml` triggers and publishes gem to RubyGems.org
321
316
 
322
317
  ### Conventional Commits Cheat Sheet
323
318
 
@@ -329,25 +324,28 @@ Releases are automated using [release-please](https://github.com/googleapis/rele
329
324
  | `chore:` | Patch | `chore: update dependencies` |
330
325
  | `feat!:` | Major (2.0.0 → 3.0.0) | `feat!: change URI format` |
331
326
 
332
- ### Manual Release (Emergency Only)
333
-
334
- For hotfixes that can't wait for the release-please flow:
335
-
336
- ```bash
337
- # Update VERSION file
338
- echo "2.0.2" > VERSION
339
-
340
- # Update CHANGELOG.md manually
327
+ ### Complete Flow Diagram
341
328
 
342
- # Commit and tag
343
- git add VERSION CHANGELOG.md
344
- git commit -m "chore: release v2.0.2"
345
- git tag v2.0.2
346
- git push origin main --tags
347
329
  ```
330
+ Push commit → CI runs on main → Release-please creates PR (auto-merge on)
331
+
332
+ CI runs on PR
333
+
334
+ PR auto-merges when green
335
+
336
+ GitHub Release created (v2.x.x)
337
+
338
+ release-tag.yml triggers
339
+
340
+ Gem published to RubyGems.org
341
+ ```
342
+
343
+ ### Key Files
348
344
 
349
- The `release-tag.yml` workflow triggers on tag push and will:
350
- 1. Run tests
351
- 2. Build gem
352
- 3. Publish to RubyGems.org (via OIDC trusted publishing)
353
- 4. Create GitHub release
345
+ | File | Purpose |
346
+ |------|---------|
347
+ | `lib/train-k8s-container/version.rb` | VERSION constant (updated by release-please) |
348
+ | `release-please-config.json` | Release-please configuration |
349
+ | `.release-please-manifest.json` | Current version tracking |
350
+ | `.github/workflows/release-please.yml` | Creates PRs with auto-merge |
351
+ | `.github/workflows/release-tag.yml` | Publishes gem on release |
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  A Train transport plugin that enables Chef InSpec and Cinc Auditor to execute compliance checks against containers running in Kubernetes clusters via kubectl exec.
4
4
 
5
+ [![Gem Version](https://badge.fury.io/rb/train-k8s-container-mitre.svg)](https://badge.fury.io/rb/train-k8s-container-mitre)
5
6
  [![CI](https://github.com/mitre/train-k8s-container/actions/workflows/ci.yml/badge.svg)](https://github.com/mitre/train-k8s-container/actions/workflows/ci.yml)
6
7
  [![Security](https://github.com/mitre/train-k8s-container/actions/workflows/security.yml/badge.svg)](https://github.com/mitre/train-k8s-container/actions/workflows/security.yml)
7
8
 
@@ -29,7 +30,7 @@ This plugin allows InSpec/Cinc Auditor to scan containers running in Kubernetes
29
30
  **Important:** Always install Train plugins using `inspec plugin install` or `cinc-auditor plugin install`. Do NOT use `gem install` directly, as this can cause issues with plugin discovery and management.
30
31
 
31
32
  ```bash
32
- # Using Cinc Auditor (recommended - open source, license-free)
33
+ # Using Cinc Auditor (open source, license-free)
33
34
  cinc-auditor plugin install train-k8s-container-mitre
34
35
 
35
36
  # Or using Chef InSpec
@@ -204,6 +205,18 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
204
205
  4. Run `bundle exec rspec && bundle exec rake style`
205
206
  5. Submit a pull request
206
207
 
208
+ ### Versioning
209
+
210
+ This project uses [Conventional Commits](https://www.conventionalcommits.org/) for automated releases:
211
+
212
+ | Commit Prefix | Version Bump | Example |
213
+ |---------------|--------------|---------|
214
+ | `feat:` | Minor (2.1.0) | New features |
215
+ | `fix:` | Patch (2.0.1) | Bug fixes |
216
+ | `feat!:` | Major (3.0.0) | Breaking changes |
217
+
218
+ See [CONTRIBUTING.md](CONTRIBUTING.md#versioning-and-commit-messages) for full details.
219
+
207
220
  ## Security
208
221
 
209
222
  See [SECURITY.md](SECURITY.md) for security policy and reporting vulnerabilities.
@@ -224,13 +237,12 @@ This project is maintained by the MITRE SAF (Security Automation Framework) team
224
237
 
225
238
  ## Acknowledgments
226
239
 
227
- This project is a fork of [inspec/train-k8s-container](https://github.com/inspec/train-k8s-container), significantly enhanced with:
240
+ This project is a fork of [inspec/train-k8s-container](https://github.com/inspec/train-k8s-container), enhanced with:
228
241
 
229
242
  - Train v2 plugin architecture
230
243
  - Detect+Context platform detection pattern
231
244
  - Comprehensive CI/CD with pod-to-pod testing
232
- - Security hardening and SBOM generation
233
- - MITRE SAF ecosystem integration
245
+ - Automated releases via release-please
234
246
 
235
247
  ---
236
248
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TrainPlugins
4
4
  module K8sContainer
5
- VERSION = '2.0.3'
5
+ VERSION = '2.1.1'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train-k8s-container-mitre
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - MITRE SAF Team
@@ -49,6 +49,7 @@ files:
49
49
  - ".release-please-manifest.json"
50
50
  - ".rspec"
51
51
  - ".rubocop.yml"
52
+ - ARCHITECTURE.md
52
53
  - CHANGELOG.md
53
54
  - CODE_OF_CONDUCT.md
54
55
  - CONTRIBUTING.md