openvox-lint 1.3.1 → 1.3.4

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: c93dcb31a47e58c1ff171d798789c1bfdc202cf9d0f950c6eb35c0942eeaa8ca
4
- data.tar.gz: 3bf2d9f13f3bc7e39f651626f1c4dcb22b628d45e5a330e146a14d2c3ec9e138
3
+ metadata.gz: c0c7d920c8af64b11f92c5b9c4937d1f767c45d544a78156f301de78e9512927
4
+ data.tar.gz: cf78162f1b74d6f748e809850f7650df7f556a47489417659f27611ca349b8b3
5
5
  SHA512:
6
- metadata.gz: e685e7c01d060ae7d1235ebb8d3164e0eac81a72ec0e4cb63f214aca7acde911ad16cc79c5fcbd0f5994d796a6ce8be13f62a43aba92e4c8c1e9d6126dc172e0
7
- data.tar.gz: 0b789ecf9210c095ab2c5abb128583e3fd7717aede849a45b0cf5ffc5419fc59d7b62a6ad4fc79495841fce369581fb67ad657a04bc60cdf666e105e3ad0259d
6
+ metadata.gz: e86b7d896d60e813091baa30e69b08422b4f48e0557610c06fabf0d296d05095b87ae5ca76131f6ad23952f528311248883ebd2072d0145f35e4c589a9fc6877
7
+ data.tar.gz: 4d4779b6164be6bf252527a8ad970e3ef8af117fab5c6315fba89bfac935bee6e1770d9a179e68c2fb3982542c87981c1accd21d0567825c7bd4130ca7f0b012
data/CHANGELOG.md CHANGED
@@ -2,6 +2,53 @@
2
2
 
3
3
  All notable changes to openvox-lint will be documented in this file.
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [1.3.4] - 2026-09-21
8
+
9
+ Patch release so the published gem matches tip. Resource indexes now see capitalized resource defaults. No new checks.
10
+
11
+ ### Fixed
12
+ - Resource indexes treat capitalized resource defaults (`File {`, `Notify {`) via CLASSREF.
13
+ - Class, define, and node bodies are still skipped using the previous semantic token. There is no formatting walk.
14
+ - Specs cover resource defaults against capitalized class and define names.
15
+
16
+ ## [1.3.3] - 2026-09-21
17
+
18
+ Patch release since 1.3.2. Safer CI and auto-fix, clearer checks and CLI, and an honest story for custom checks. No new checks.
19
+
20
+ ### Security
21
+ - Safer CI output. GitHub annotation format (`-f github`) can no longer let crafted lint messages inject extra commands into the Actions log.
22
+ - Safer config. An `.openvox-lint.rc` can no longer quietly enable rewrite/fix mode. `--fix` must be passed on the CLI.
23
+ - Safer auto-fix. `--fix` refuses to write if the path is a symlink or goes through one.
24
+ - CSV output escapes fields that contain commas, quotes, or newlines.
25
+
26
+ ### Architect
27
+ - Honest extension story. Docs say require your file and register the check. There is no gem auto-load plugin ecosystem.
28
+ - A duplicate check name always warns when it is overwritten.
29
+ - Dead-API cleanup, and the lexer comment no longer claims EPP tag scanning. See [docs/ARCHITECTURE_REVIEW.md](docs/ARCHITECTURE_REVIEW.md).
30
+
31
+ ### Quality
32
+ - `$::` topscope names no longer false-positive on `variable_is_lowercase` (#2).
33
+ - Broken heredocs (unterminated, or a junk end tag such as a comma after `END`) now fail with a clear error (#5).
34
+
35
+ ### CLI
36
+ - `--relative` rewrites paths in all output formats.
37
+ - An unknown `-f` fails closed and prints the allowlist.
38
+ - `--list-checks` shows name, severity, and description.
39
+ - `--help` documents `--no-<check>-check`.
40
+ - RC `--log-format` and `--format` behave like the CLI.
41
+
42
+ ### Systems
43
+ - The Ruby floor is now ≥ 2.6. Ruby 2.5 is no longer claimed, because CI cannot honestly test it.
44
+ - Missing or empty input paths fail closed instead of exiting 0 with a clean run (#7).
45
+ - The README CI badge and the release checklist keep the git tag, the RubyGems publish, and the GitHub Release in sync.
46
+
47
+ ## [1.3.2] - 2026-05-24
48
+
49
+ ### Fixed
50
+ - Strengthened resource detection logic in `compute_resource_indexes` to reliably exclude `class`/`define`/`node` bodies. This prevents multiple checks (especially `trailing_comma`) from incorrectly treating statements inside classes as resource attributes.
51
+
5
52
  ## [1.3.1] - 2026-05-23
6
53
 
7
54
  ### Fixed
@@ -244,7 +291,7 @@ All notable changes to openvox-lint will be documented in this file.
244
291
  - Token-based check plugin architecture with `OpenvoxLint.new_check` DSL
245
292
  - Doubly-linked token list for efficient navigation
246
293
  - Support for all Puppet 8 / OpenVox 8.x language constructs
247
- - Heredoc, EPP tag, regex, and string interpolation tokenization
294
+ - Heredoc, regex, and string interpolation tokenization (EPP tags were never scanned)
248
295
 
249
296
  - **38 Built-in Checks**
250
297
  - **Whitespace**: `trailing_whitespace`, `hard_tabs`, `line_length`, `space_before_arrow`, `strict_indent`
data/DOCUMENTATION.md CHANGED
@@ -10,8 +10,8 @@ reported in multiple output formats suitable for humans, CI systems, and IDEs.
10
10
  This document covers the architecture, every public API, every built-in check,
11
11
  the lexer token types, the plugin system, and integration guidance.
12
12
 
13
- **Version:** 1.3.1
14
- **Checks:** 37 built-in (with real --fix support for 5+ checks)
13
+ **Version:** 1.3.4
14
+ **Checks:** 37 built-in (with real --fix support for 5 checks)
15
15
  **License:** Apache 2.0
16
16
  **Compatibility:** OpenVox 8.x, Puppet 8.x, Puppet 7.x (with deprecation warnings)
17
17
 
@@ -45,6 +45,7 @@ the lexer token types, the plugin system, and integration guidance.
45
45
  - [Plugin Development](#plugin-development)
46
46
  - [Migration from puppet-lint](#migration-from-puppet-lint)
47
47
  - [File Inventory](#file-inventory)
48
+ - [Architecture Review](docs/ARCHITECTURE_REVIEW.md)
48
49
 
49
50
  ---
50
51
 
@@ -79,7 +80,7 @@ the lexer token types, the plugin system, and integration guidance.
79
80
  - **Zero runtime dependencies** — only Ruby standard library
80
81
  - **Token-based analysis** — works on token stream, not AST
81
82
  - **Puppet/OpenVox agnostic** — identical language support for both
82
- - **Extensible** — plugin system for custom checks
83
+ - **Extensible** — `OpenvoxLint.new_check` DSL for custom checks (require-your-file; see Plugin Development)
83
84
  - **CI-friendly** — multiple output formats, proper exit codes
84
85
 
85
86
  ---
@@ -94,7 +95,7 @@ The top-level namespace for all openvox-lint classes.
94
95
 
95
96
  | Constant | Value | Description |
96
97
  |----------|-------|-------------|
97
- | `VERSION` | `'1.3.1'` | Gem version string |
98
+ | `VERSION` | `'1.3.4'` | Gem version string |
98
99
 
99
100
  #### Class Methods
100
101
 
@@ -104,7 +105,7 @@ The top-level namespace for all openvox-lint classes.
104
105
  | `.configure { \|c\| }` | `Configuration` | Yields configuration for block-style setup |
105
106
  | `.reset_configuration!` | `Configuration` | Reset configuration to defaults (called by CLI) |
106
107
  | `.checks` | `Hash{Symbol => Class}` | Registry of loaded check classes |
107
- | `.new_check(name, &block)` | `Class` | Register a new check plugin (warns on duplicates) |
108
+ | `.new_check(name, &block)` | `Class` | Register a new check plugin (always warns on stderr if the name is already registered, then overwrites) |
108
109
 
109
110
  #### Exceptions
110
111
 
@@ -1490,10 +1491,19 @@ Use the module autoloader by placing files in the correct location:
1490
1491
 
1491
1492
  ## Plugin Development
1492
1493
 
1494
+ openvox-lint auto-loads **only** the 37 built-in files under this gem's
1495
+ `lib/openvox-lint/plugins/checks/*.rb` (see `lib/openvox-lint.rb`). There is
1496
+ no `--load FILE` CLI flag and no RubyGems plugin discovery comparable to
1497
+ `PuppetLint::Plugins.load_from_gems`. Custom checks are visible only after
1498
+ the process `require`s or `load`s the file that calls `OpenvoxLint.new_check`.
1499
+
1500
+ Registering a check name that is already present always prints a warning on
1501
+ stderr and overwrites the previous class.
1502
+
1493
1503
  ### Creating a Check Plugin
1494
1504
 
1495
1505
  ```ruby
1496
- # lib/openvox-lint/plugins/checks/my_custom_check.rb
1506
+ # my_custom_check.rb (any path; you must require this file yourself)
1497
1507
  OpenvoxLint.new_check(:my_custom_check) do
1498
1508
  def check
1499
1509
  tokens.each do |tok|
@@ -1508,13 +1518,23 @@ OpenvoxLint.new_check(:my_custom_check) do
1508
1518
 
1509
1519
  # Optional: implement auto-fix
1510
1520
  def fix(problem)
1511
- # Find and modify the problematic token
1512
- # Or raise NoFix if this instance can't be fixed
1521
+ # Mutate manifest_lines in place, or raise NoFix if this instance
1522
+ # cannot be fixed. Only five built-in checks currently implement #fix.
1513
1523
  raise OpenvoxLint::NoFix
1514
1524
  end
1515
1525
  end
1516
1526
  ```
1517
1527
 
1528
+ Load the file after `require 'openvox-lint'` and before `Linter#run`:
1529
+
1530
+ ```ruby
1531
+ require 'openvox-lint'
1532
+ require_relative 'my_custom_check'
1533
+ ```
1534
+
1535
+ To contribute a **built-in** check to this repository, place the file in
1536
+ `lib/openvox-lint/plugins/checks/` so the gem auto-loader picks it up.
1537
+
1518
1538
  ### Using Helper Methods
1519
1539
 
1520
1540
  ```ruby
@@ -1553,22 +1573,44 @@ end
1553
1573
 
1554
1574
  ### Distributing as a Gem
1555
1575
 
1576
+ A companion gem can depend on `openvox-lint` and ship check files, but
1577
+ **openvox-lint will not auto-discover them**. Consumers must require the
1578
+ entry point of your gem (or each check file) themselves.
1579
+
1556
1580
  ```ruby
1557
1581
  # openvox-lint-my_checks.gemspec
1558
1582
  Gem::Specification.new do |spec|
1559
1583
  spec.name = 'openvox-lint-my_checks'
1560
1584
  spec.version = '1.0.0'
1561
1585
  spec.summary = 'Custom checks for openvox-lint'
1562
-
1586
+
1563
1587
  spec.add_runtime_dependency 'openvox-lint', '~> 1.0'
1564
-
1588
+
1565
1589
  spec.files = Dir['lib/**/*']
1566
1590
  spec.require_paths = ['lib']
1567
1591
  end
1568
1592
  ```
1569
1593
 
1570
- Place check files in `lib/openvox-lint/plugins/checks/` and they will
1571
- be auto-loaded when the gem is required.
1594
+ ```ruby
1595
+ # lib/openvox-lint-my_checks.rb (your gem's require path)
1596
+ require 'openvox-lint'
1597
+ require_relative 'openvox-lint-my_checks/no_eval'
1598
+ ```
1599
+
1600
+ ```ruby
1601
+ # In a Rake task or wrapper script
1602
+ require 'openvox-lint'
1603
+ require 'openvox-lint-my_checks'
1604
+
1605
+ linter = OpenvoxLint::Linter.new
1606
+ linter.run('manifests/')
1607
+ ```
1608
+
1609
+ Putting files under `lib/openvox-lint/plugins/checks/` inside *your* gem
1610
+ does not register them. That glob is evaluated only against this gem's
1611
+ `__dir__` in `lib/openvox-lint.rb`. There is also no `--load` flag for
1612
+ `openvox-lint` CLI invocations; wrap the CLI or call `Linter` from Ruby
1613
+ after requiring your checks.
1572
1614
 
1573
1615
  ---
1574
1616
 
@@ -1579,22 +1621,24 @@ broader compatibility and additional checks.
1579
1621
 
1580
1622
  ### Key Differences
1581
1623
 
1582
- | Feature | puppet-lint 5.x | openvox-lint 1.x |
1583
- |---------|-----------------|------------------|
1584
- | Ruby requirement | 3.1 | 2.5 (works on RHEL 8, macOS system Ruby) |
1624
+ Snapshot as of 2026-09-18 against [puppetlabs/puppet-lint `main`](https://github.com/puppetlabs/puppet-lint) (README plus `lib/puppet-lint/plugins.rb`). See [docs/ARCHITECTURE_REVIEW.md](docs/ARCHITECTURE_REVIEW.md) for cites.
1625
+
1626
+ | Feature | puppet-lint (current `main`) | openvox-lint 1.x |
1627
+ |---------|------------------------------|------------------|
1628
+ | Ruby requirement | Documented for Puppet 7/8 environments (typically ≥ 3.1 in 5.x) | ≥ 2.6 as declared in this gemspec |
1585
1629
  | Runtime dependencies | None | None |
1586
- | Built-in checks | ~25 | 37 |
1587
- | Legacy facts detection | Via plugin | Built-in |
1588
- | Top-scope facts detection | Via plugin | Built-in |
1589
- | Deprecated Hiera 3 function detection | No | Built-in (ERROR) |
1590
- | Import statement detection | No | Built-in (ERROR) |
1591
- | Strict indent check | Via plugin | Built-in |
1592
- | GitHub Actions output | No | Built-in (`-f github`) |
1593
- | Code Climate output | No | Built-in (`-f codeclimate`) |
1594
- | CSV output | No | Built-in (`-f csv`) |
1630
+ | Built-in checks | Core style set plus built-in fact checks (including YAML) | 37 `.pp` checks |
1631
+ | Legacy facts detection | Built-in | Built-in |
1632
+ | Top-scope facts detection | Built-in | Built-in |
1633
+ | Deprecated Hiera 3 function detection | Not in the published core check list | Built-in (ERROR) |
1634
+ | Import statement detection | Not in the published core check list | Built-in (ERROR) |
1635
+ | Strict indent | 2-space / hard-tab rules in core | Built-in `strict_indent` |
1636
+ | GitHub Actions | `--sarif`, puppet-lint-action, env-based annotations | Built-in `-f github` |
1637
+ | Code Climate | `--codeclimate-report-file` | Built-in `-f codeclimate` |
1638
+ | CSV output | No native CSV formatter | Built-in (`-f csv`) |
1595
1639
  | OpenVox awareness | No | Yes |
1596
- | `--fix` support | Yes | Yes |
1597
- | Plugin system | Yes | Yes (compatible API) |
1640
+ | `--fix` support | Yes (token-rewriting; many core checks) | Yes, line-based, for five named checks |
1641
+ | Plugin system | `--load`, `--load-from-puppet`, gem auto-discovery | `new_check` DSL; require-your-file only (not drop-in compatible) |
1598
1642
 
1599
1643
  ### Command-Line Compatibility
1600
1644
 
@@ -1625,10 +1669,14 @@ Rename `.puppet-lint.rc` to `.openvox-lint.rc`. The format is identical:
1625
1669
 
1626
1670
  ### Plugin Migration
1627
1671
 
1628
- Plugin APIs are similar. Main differences:
1672
+ The `new_check` / `#check` / `#fix` / `notify` surface looks familiar, but
1673
+ the plugin **loading** model is not compatible:
1629
1674
 
1630
1675
  1. Module name: `OpenvoxLint` instead of `PuppetLint`
1631
1676
  2. Check registration: `OpenvoxLint.new_check(:name)` instead of `PuppetLint.new_check(:name)`
1677
+ 3. No `PuppetLint::Data` singleton — helpers live on `CheckPlugin`
1678
+ 4. No gem auto-discovery and no `--load` — `require` the check file yourself
1679
+ 5. `#fix` should mutate `manifest_lines`, not rewrite the token list
1632
1680
 
1633
1681
  ---
1634
1682
 
@@ -1660,6 +1708,7 @@ Plugin APIs are similar. Main differences:
1660
1708
  | `spec/spec_helper.rb` | RSpec test helper |
1661
1709
  | `spec/unit/lexer_spec.rb` | Lexer unit tests |
1662
1710
  | `spec/unit/checks_spec.rb` | Check unit tests |
1711
+ | `spec/unit/architecture_spec.rb` | Registry, resource-index, and lexer-honesty contracts |
1663
1712
  | `openvox-lint.gemspec` | Gem specification |
1664
1713
  | `Gemfile` | Development dependencies |
1665
1714
  | `Rakefile` | Rake tasks |
@@ -1667,3 +1716,4 @@ Plugin APIs are similar. Main differences:
1667
1716
  | `README.md` | User documentation |
1668
1717
  | `CHANGELOG.md` | Version history |
1669
1718
  | `DOCUMENTATION.md` | This file |
1719
+ | `docs/ARCHITECTURE_REVIEW.md` | Evidence-based architecture review |
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  [![Gem Version](https://img.shields.io/gem/v/openvox-lint)](https://rubygems.org/gems/openvox-lint)
4
4
  [![Gem Downloads](https://img.shields.io/gem/dt/openvox-lint)](https://rubygems.org/gems/openvox-lint)
5
- ![Ruby](https://img.shields.io/badge/ruby-%E2%89%A5%202.5-red)
5
+ [![CI](https://github.com/cvquesty/openvox-lint/actions/workflows/ci.yml/badge.svg?branch=development)](https://github.com/cvquesty/openvox-lint/actions/workflows/ci.yml)
6
+ ![Ruby](https://img.shields.io/badge/ruby-%E2%89%A5%202.6-red)
6
7
  ![License](https://img.shields.io/badge/license-Apache%202.0-blue)
7
8
  ![Checks](https://img.shields.io/badge/built--in%20checks-37-brightgreen)
8
9
  ![Status](https://img.shields.io/badge/status-stable-brightgreen)
@@ -42,8 +43,8 @@ Fully compatible with:
42
43
 
43
44
  | Requirement | Version | Notes |
44
45
  |------------|---------|-------|
45
- | **Ruby** | ≥ 2.5.0 | Required; check with `ruby --version`. Works with macOS system Ruby (2.6), RHEL 8 system Ruby (2.5), and all newer versions. |
46
- | **RubyGems** | ≥ 2.0 | Included with Ruby 2.5+ |
46
+ | **Ruby** | ≥ 2.6.0 | Required; check with `ruby --version`. Works with macOS system Ruby (2.6) and all newer versions. Ruby 2.5 is no longer claimed (dev dependency `rubocop ~> 1.50` needs ≥ 2.6). |
47
+ | **RubyGems** | ≥ 2.0 | Included with Ruby 2.6+ |
47
48
  | **Bundler** | ≥ 2.0 | `gem install bundler` if not present |
48
49
  | **OpenVox or Puppet** | 8.x | Optional; openvox-lint works standalone without an agent |
49
50
  | **Git** | ≥ 2.0 | For installation from source |
@@ -130,10 +131,11 @@ Options:
130
131
  -f, --format FORMAT Output format: text, json, csv, github, codeclimate
131
132
  --log-format FORMAT Custom log format string
132
133
  --fix Automatically fix problems where possible
134
+ --no-fix Do not automatically fix problems (overrides --fix)
133
135
  --fail-on-warnings Exit with error code on warnings
134
136
  --no-filename Suppress filename in output
135
137
  --no-column Suppress column number in output
136
- --relative Display relative file paths
138
+ --relative Display file paths relative to the current working directory
137
139
  --only-checks CHECKS Comma-separated list of checks to run
138
140
  --ignore-paths PATHS Comma-separated list of glob patterns to ignore
139
141
  --list-checks List all available checks
@@ -162,7 +164,7 @@ openvox-lint --fail-on-warnings manifests/
162
164
 
163
165
  ### Fix mode (`--fix`)
164
166
 
165
- `--fix` automatically corrects problems for the checks that implement fix logic. Fixes are applied in-place and are safe for the supported cases.
167
+ `--fix` automatically corrects problems for the checks that implement fix logic. Fixes are applied in-place and are safe for the supported cases. `--fix` must be passed on the command line; an RC file cannot enable it. `--no-fix` disables fix mode. Writes are refused when the target path is a symbolic link.
166
168
 
167
169
  Currently supported checks:
168
170
  - `trailing_whitespace` — removes trailing spaces/tabs
@@ -254,7 +256,7 @@ To see every check that openvox-lint can run:
254
256
  openvox-lint --list-checks
255
257
  ```
256
258
 
257
- This shows the check name, severity (warning or error), and description for all 37 built-in checks.
259
+ This lists every built-in check name and whether it is currently enabled. Severity and description live in this README and in [DOCUMENTATION.md](DOCUMENTATION.md).
258
260
 
259
261
  ---
260
262
 
@@ -295,12 +297,13 @@ openvox-lint ships with **37 built-in checks** organized into categories:
295
297
  | `variable_is_lowercase` | warning | All variables must be lowercase |
296
298
  | `variable_contains_dash` | warning | Variables must not contain dashes |
297
299
 
298
- ### Resources (7 checks)
300
+ ### Resources (8 checks)
299
301
 
300
302
  | Check | Severity | Description |
301
303
  |-------|----------|-------------|
302
304
  | `ensure_first_param` | warning | `ensure` must be the first attribute |
303
305
  | `ensure_not_symlink_target` | warning | Use `ensure => link` with `target` |
306
+ | `unquoted_ensure_value` | warning | `ensure` parameter values must be single-quoted strings |
304
307
  | `file_mode` | warning | File modes as 4-digit quoted octal or symbolic |
305
308
  | `unquoted_file_mode` | warning | File modes must be quoted strings |
306
309
  | `unquoted_resource_title` | warning | Resource titles must be quoted |
@@ -365,7 +368,20 @@ openvox-lint ships with **37 built-in checks** organized into categories:
365
368
 
366
369
  ### RC File
367
370
 
368
- Create `.openvox-lint.rc` in your project root or `~/.openvox-lint.rc`:
371
+ Create `.openvox-lint.rc` in your project root or `~/.openvox-lint.rc`.
372
+ Each line is a flag (with an optional value). Only the following flags are
373
+ read from the RC file; other CLI options (`--fix`, `--relative`,
374
+ `--no-filename`, `--no-column`) must be passed on the command line.
375
+ An RC file cannot enable `--fix` — pass `--fix` on the CLI to enable writes.
376
+
377
+ | Flag | Effect |
378
+ |------|--------|
379
+ | `--fail-on-warnings` | Exit 1 when warnings are found |
380
+ | `--no-<check_name>-check` | Disable a check |
381
+ | `--only-checks LIST` | Run only the named checks (comma-separated) |
382
+ | `--log-format FORMAT` | Named format (`text`, `json`, `csv`, `github`, `codeclimate`) or a custom format string (`%{path}`, `%{line}`, …) |
383
+ | `--format FORMAT` / `-f FORMAT` | Named output format only (same allowlist as CLI `-f`) |
384
+ | `--ignore-paths GLOBS` | Comma-separated globs to skip |
369
385
 
370
386
  ```
371
387
  # Disable specific checks
@@ -380,6 +396,12 @@ Create `.openvox-lint.rc` in your project root or `~/.openvox-lint.rc`:
380
396
 
381
397
  # Ignore paths
382
398
  --ignore-paths vendor/**/*.pp,pkg/**/*.pp
399
+
400
+ # --fix in an RC file is ignored; pass --fix on the CLI to enable writes
401
+
402
+ # Named format or a custom --log-format string
403
+ # --format json
404
+ # --log-format %{path}:%{line}:%{KIND}:%{check}:%{message}
383
405
  ```
384
406
 
385
407
  ### Inline Ignore Comments
@@ -502,10 +524,16 @@ openvox-lint --fail-on-warnings $files
502
524
 
503
525
  ## Writing Custom Checks
504
526
 
527
+ openvox-lint auto-loads **only** the built-in files shipped in this gem
528
+ (`lib/openvox-lint/plugins/checks/*.rb`). There is no `--load FILE` flag and
529
+ no RubyGems plugin discovery. A third-party check is picked up only when
530
+ something in the same Ruby process `require`s (or `load`s) the file after
531
+ `openvox-lint` itself.
532
+
505
533
  Create a Ruby file with a check plugin:
506
534
 
507
535
  ```ruby
508
- # lib/openvox-lint/plugins/checks/my_custom_check.rb
536
+ # my_custom_check.rb (any path you control)
509
537
  OpenvoxLint.new_check(:my_custom_check) do
510
538
  def check
511
539
  tokens.each do |tok|
@@ -520,7 +548,24 @@ OpenvoxLint.new_check(:my_custom_check) do
520
548
  end
521
549
  ```
522
550
 
523
- Place in `lib/openvox-lint/plugins/checks/` and it will be auto-loaded.
551
+ Load it explicitly before you run the linter:
552
+
553
+ ```ruby
554
+ require 'openvox-lint'
555
+ require_relative 'my_custom_check'
556
+
557
+ linter = OpenvoxLint::Linter.new
558
+ linter.run('manifests/')
559
+ ```
560
+
561
+ Duplicate `new_check` names always warn on stderr and overwrite the previous
562
+ registration. Putting a file under `lib/openvox-lint/plugins/checks/` in
563
+ *your* gem does not make openvox-lint load it.
564
+
565
+ To add a check to this repository, place it in
566
+ `lib/openvox-lint/plugins/checks/` so the built-in auto-loader picks it up.
567
+ See [DOCUMENTATION.md](DOCUMENTATION.md#plugin-development) and
568
+ [docs/ARCHITECTURE_REVIEW.md](docs/ARCHITECTURE_REVIEW.md).
524
569
 
525
570
  ---
526
571
 
@@ -548,7 +593,7 @@ bundle update openvox-lint
548
593
 
549
594
  ```bash
550
595
  cd openvox-lint
551
- git pull origin main
596
+ git pull origin development
552
597
  gem build openvox-lint.gemspec
553
598
  gem install openvox-lint-*.gem
554
599
  ```
@@ -619,12 +664,14 @@ openvox-lint/
619
664
  │ ├── linter.rb # File-level orchestrator
620
665
  │ ├── cli.rb # Command-line interface
621
666
  │ └── plugins/
622
- │ └── checks/ # 38 built-in check plugins
667
+ │ └── checks/ # 37 built-in check plugins
623
668
  │ ├── trailing_whitespace.rb
624
669
  │ ├── legacy_facts.rb
625
670
  │ ├── hiera3_function.rb
626
671
  │ └── ...
627
672
  ├── spec/ # RSpec test suite
673
+ ├── docs/
674
+ │ └── ARCHITECTURE_REVIEW.md # Evidence-based architecture notes
628
675
  ├── openvox-lint.gemspec
629
676
  ├── Gemfile
630
677
  ├── Rakefile
@@ -638,23 +685,25 @@ openvox-lint/
638
685
 
639
686
  ## Comparison with puppet-lint
640
687
 
641
- | Feature | puppet-lint 5.x | openvox-lint 1.3.1 |
642
- |---------|-----------------|------------------|
643
- | Ruby requirement | 3.1 | 2.5 (RHEL 8, macOS, all modern platforms) |
688
+ Snapshot as of 2026-09-18 against [puppetlabs/puppet-lint `main` README and `lib/puppet-lint/plugins.rb`](https://github.com/puppetlabs/puppet-lint). puppet-lint remains under active maintenance; treat this table as dated evidence, not a permanent scorecard.
689
+
690
+ | Feature | puppet-lint (current `main`) | openvox-lint 1.3.4 |
691
+ |---------|------------------------------|--------------------|
692
+ | Ruby requirement | Documented for Puppet 7/8 environments (typically ≥ 3.1 in 5.x) | ≥ 2.6 as declared in this gemspec |
644
693
  | Runtime dependencies | None | None |
645
- | Built-in checks | ~25 | 37 |
646
- | Legacy facts detection | Via plugin | Built-in |
647
- | Top-scope facts detection | Via plugin | Built-in |
648
- | Deprecated Hiera 3 function detection | No | Built-in (error) |
649
- | Import statement detection | No | Built-in (error) |
650
- | Strict indent check | Via plugin | Built-in |
651
- | GitHub Actions output | No | Built-in (`-f github`) |
652
- | Code Climate output | No | Built-in (`-f codeclimate`) |
653
- | CSV output | No | Built-in (`-f csv`) |
654
- | Custom log format | Yes | Yes (compatible) |
694
+ | Built-in checks | Core style set plus built-in `legacy_facts` / `top_scope_facts` (including YAML facts) | 37 `.pp` checks |
695
+ | Legacy facts detection | Built-in (not plugin-only) | Built-in |
696
+ | Top-scope facts detection | Built-in (not plugin-only) | Built-in |
697
+ | Deprecated Hiera 3 function detection | Not in the published core check list | Built-in (error) |
698
+ | Import statement detection | Not in the published core check list | Built-in (error) |
699
+ | Strict indent | 2-space / hard-tab rules in core; stricter indent historically a plugin | Built-in `strict_indent` |
700
+ | GitHub Actions | `--sarif`, [puppet-lint-action](https://github.com/marketplace/actions/puppet-lint-action), env-based annotations | Built-in `-f github` workflow commands |
701
+ | Code Climate | `--codeclimate-report-file` / `CODECLIMATE_REPORT_FILE` | Built-in `-f codeclimate` |
702
+ | CSV output | No native CSV formatter | Built-in (`-f csv`) |
703
+ | Custom log format | Yes (`%{path}`, `%{filename}`, `%{fullpath}`, …) | Yes (same core placeholders; no `%{filename}` / `%{fullpath}`) |
655
704
  | OpenVox awareness | No | Yes |
656
- | Plugin system | Yes | Yes (compatible) |
657
- | `--fix` support | Yes | Yes (real implementations for trailing_whitespace, hard_tabs, quoted_booleans, double_quoted_strings, single_quote_string_with_variables + line-based) |
705
+ | Plugin system | `--load FILE`, `--load-from-puppet`, gem auto-discovery via `PuppetLint::Plugins.load_from_gems` | `OpenvoxLint.new_check` DSL; **require-your-file only** — no `--load`, no gem auto-discovery |
706
+ | `--fix` support | Yes (token-rewriting; many core checks) | Yes, line-based, for five checks: `trailing_whitespace`, `hard_tabs`, `quoted_booleans`, `double_quoted_strings`, `single_quote_string_with_variables` |
658
707
  | vim-openvox integration | No | Native |
659
708
 
660
709
  ---