A style-guide linter for OpenVox and Puppet manifests.
openvox-lint checks your .pp manifest files against the Puppet Style Guide and catches common errors, deprecated patterns, legacy facts, strict-mode violations, and Puppet 8+ / OpenVox 8.x language issues.
Fully compatible with:
- OpenVox 8.x (the community-maintained open-source fork of Puppet)
- Puppet 8.x
- Legacy Puppet 7.x manifests (with deprecation warnings)
- Prerequisites
- Installation
- Quick Start
- Usage
- Built-in Checks (38)
- Configuration
- Output Formats
- Integration
- Writing Custom Checks
- Development
- License
| Requirement | Version | Notes |
|---|---|---|
| Ruby | ≥ 3.1.0 | Required; check with ruby --version |
| RubyGems | ≥ 3.0 | Included with Ruby 3.1+ |
| Bundler | ≥ 2.0 | gem install bundler if not present |
| OpenVox or Puppet | 8.x | Optional; openvox-lint works standalone without an agent |
| Git | ≥ 2.0 | For installation from source |
| Tool | Purpose |
|---|---|
puppet or openvox binary |
For puppet parser validate syntax checking |
metadata-json-lint gem |
For linting module metadata.json files |
vim-openvox Vim plugin |
For IDE integration (async linting in Vim) |
rake gem |
For running tests during development |
rspec gem |
For running the test suite |
- macOS (Apple Silicon and Intel)
- Linux (x86_64, aarch64)
- Windows (via Ruby for Windows)
gem install openvox-lintgit clone https://github.com/cvquesty/openvox-lint.git
cd openvox-lint
gem build openvox-lint.gemspec
gem install openvox-lint-*.gemAdd to your Gemfile:
gem 'openvox-lint'Then run:
bundle install# Lint a single file
openvox-lint manifests/init.pp
# Lint all .pp files in a directory tree
openvox-lint manifests/
# Lint current directory
openvox-lint .
# List all available checks
openvox-lint --list-checks
# JSON output for CI
openvox-lint -f json manifests/Usage: openvox-lint [options] [file|directory ...]
Options:
--version Display version
-f, --format FORMAT Output format: text, json, csv, github, codeclimate
--log-format FORMAT Custom log format string
--fix Automatically fix problems where possible
--fail-on-warnings Exit with error code on warnings
--no-filename Suppress filename in output
--no-column Suppress column number in output
--relative Display relative file paths
--only-checks CHECKS Comma-separated list of checks to run
--ignore-paths PATHS Comma-separated list of glob patterns to ignore
--list-checks List all available checks
-c, --config FILE Path to configuration file
--no-<check_name>-check Disable a specific check
# Disable specific checks
openvox-lint --no-line_length-check --no-arrow_alignment-check .
# Run only specific checks
openvox-lint --only-checks legacy_facts,hiera3_function,top_scope_facts .
# Custom log format (compatible with puppet-lint)
openvox-lint --log-format '%{path}:%{line}:%{column}:%{KIND}:%{check}:%{message}' .
# GitHub Actions annotations
openvox-lint -f github manifests/
# Fail CI on warnings too
openvox-lint --fail-on-warnings manifests/openvox-lint ships with 38 built-in checks organized into categories:
| Check | Severity | Description |
|---|---|---|
trailing_whitespace |
warning | No trailing whitespace at end of lines |
hard_tabs |
warning | Use 2-space soft tabs, not literal tabs |
line_length |
warning | Lines should not exceed 140 characters |
space_before_arrow |
warning | Only the longest key in an aligned block should have one space before => |
strict_indent |
warning | Indentation must use 2-space increments |
| Check | Severity | Description |
|---|---|---|
arrow_alignment |
warning | => arrows should align within resource bodies |
| Check | Severity | Description |
|---|---|---|
double_quoted_strings |
warning | Use single quotes for strings without interpolation, escapes, or nested quotes |
only_variable_string |
warning | Don't quote strings containing only a variable |
single_quote_string_with_variables |
warning | Use double quotes for strings with variables |
variables_not_enclosed |
warning | Variables in strings must use ${var} braces |
quoted_booleans |
warning | Don't quote boolean values true/false |
| Check | Severity | Description |
|---|---|---|
variable_is_lowercase |
warning | All variables must be lowercase |
variable_contains_dash |
warning | Variables must not contain dashes |
| Check | Severity | Description |
|---|---|---|
ensure_first_param |
warning | ensure must be the first attribute |
ensure_not_symlink_target |
warning | Use ensure => link with target |
file_mode |
warning | File modes as 4-digit quoted octal or symbolic |
unquoted_file_mode |
warning | File modes must be quoted strings |
unquoted_resource_title |
warning | Resource titles must be quoted |
duplicate_params |
error | No duplicate parameters in resources |
trailing_comma |
warning | Trailing comma after last attribute |
| Check | Severity | Description |
|---|---|---|
documentation |
warning | Classes/defines must have preceding documentation |
nested_classes_or_defines |
warning | No nesting of classes or defines |
parameter_order |
warning | Params without defaults before params with defaults |
class_inherits_params |
warning | Avoid class inheritance; use composition |
inherits_across_namespaces |
warning | No inheritance across module namespaces |
| Check | Severity | Description |
|---|---|---|
case_without_default |
warning | Case statements must have a default case |
selector_inside_resource |
warning | Don't use selectors inside resource bodies |
| Check | Severity | Description |
|---|---|---|
leading_zero |
warning | No leading zeros in numbers (except file modes) |
resource_reference_without_title_capital |
warning | Capitalise resource reference types |
relative_classname_inclusion |
warning | Use fully qualified class names |
autoloader_layout |
warning | Class/define name must match file path |
| Check | Severity | Description |
|---|---|---|
star_comments |
warning | Use # comments, not /* */ |
| Check | Severity | Description |
|---|---|---|
puppet_url_without_modules |
warning | puppet:/// URLs must include /modules/ |
| Check | Severity | Description |
|---|---|---|
node_name_unquoted |
warning | Node names must be quoted strings |
| Check | Severity | Description |
|---|---|---|
legacy_facts |
warning | Legacy facts removed in Puppet 8; use $facts['...'] |
top_scope_facts |
warning | $::fact references; use $facts['fact'] |
hiera3_function |
error | hiera() / hiera_hash() removed; use lookup() |
import_statement |
error | import removed in Puppet 4+ |
Create .openvox-lint.rc in your project root or ~/.openvox-lint.rc:
# Disable specific checks
--no-line_length-check
--no-strict_indent-check
# Only run specific checks
# --only-checks legacy_facts,hiera3_function
# Fail on warnings in CI
--fail-on-warnings
# Ignore paths
--ignore-paths vendor/**/*.pp,pkg/**/*.pp
Suppress checks on specific lines:
# lint:ignore:line_length
$very_long_variable_name = 'a very long value that exceeds the line length limit because it is a very descriptive configuration string'
# lint:endignore
class foo { # lint:ignore:documentation
}manifests/init.pp:5:15: WARNING: unquoted_file_mode: unquoted file mode
manifests/init.pp:9:3: ERROR: hiera3_function: 'hiera()' is removed in Puppet 8
[
{
"path": "manifests/init.pp",
"line": 5,
"column": 15,
"kind": "warning",
"check": "unquoted_file_mode",
"message": "unquoted file mode"
}
]::warning file=manifests/init.pp,line=5,col=15::unquoted_file_mode: unquoted file mode
path,line,column,kind,check,message
manifests/init.pp,5,15,warning,unquoted_file_mode,"unquoted file mode"
Standard Code Climate JSON format for quality dashboards.
openvox-lint --log-format '%{path}:%{line}:%{column}:%{KIND}:%{check}:%{message}' .Available placeholders: %{path}, %{line}, %{column}, %{KIND}, %{kind}, %{check}, %{message}
openvox-lint is the default backend for the vim-openvox Vim plugin. Set in .vimrc:
let g:openvox_lint_command = 'openvox-lint'name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
- run: gem install openvox-lint
- run: openvox-lint --fail-on-warnings -f github manifests/require 'openvox-lint'
task :lint do
linter = OpenvoxLint::Linter.new
linter.run('manifests/')
OpenvoxLint::Report.new(OpenvoxLint.configuration).format(linter.problems)
exit linter.exit_code
end#!/bin/bash
# .git/hooks/pre-commit
files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.pp$')
[ -z "$files" ] && exit 0
openvox-lint --fail-on-warnings $filesCreate a Ruby file with a check plugin:
# lib/openvox-lint/plugins/checks/my_custom_check.rb
OpenvoxLint.new_check(:my_custom_check) do
def check
tokens.each do |tok|
if tok.type == :NAME && tok.value == 'something_bad'
notify :warning,
message: 'found something bad',
line: tok.line,
column: tok.column
end
end
end
endPlace in lib/openvox-lint/plugins/checks/ and it will be auto-loaded.
git clone https://github.com/cvquesty/openvox-lint.git
cd openvox-lint
bundle install
bundle exec rake specopenvox-lint/
├── bin/
│ └── openvox-lint # CLI executable
├── lib/
│ ├── openvox-lint.rb # Main entry point
│ └── openvox-lint/
│ ├── version.rb # Version constant
│ ├── configuration.rb # Configuration management
│ ├── token.rb # Token data structure
│ ├── lexer.rb # Puppet/OpenVox lexer/tokenizer
│ ├── check_plugin.rb # Base class for checks
│ ├── checks.rb # Check runner/orchestrator
│ ├── report.rb # Output formatters
│ ├── linter.rb # File-level orchestrator
│ ├── cli.rb # Command-line interface
│ └── plugins/
│ └── checks/ # 38 built-in check plugins
│ ├── trailing_whitespace.rb
│ ├── legacy_facts.rb
│ ├── hiera3_function.rb
│ └── ...
├── spec/ # RSpec test suite
├── openvox-lint.gemspec
├── Gemfile
├── Rakefile
├── LICENSE # Apache 2.0
├── README.md
├── CHANGELOG.md
└── DOCUMENTATION.md
| Feature | puppet-lint 5.x | openvox-lint 1.0 |
|---|---|---|
| Ruby requirement | ≥ 3.1 | ≥ 3.1 |
| Runtime dependencies | None | None |
| Built-in checks | ~25 | 38 |
| Legacy facts detection | Via plugin | Built-in |
| Top-scope facts detection | Via plugin | Built-in |
| Hiera 3 detection | No | Built-in (error) |
| Import statement detection | No | Built-in (error) |
| Strict indent check | Via plugin | Built-in |
| GitHub Actions output | No | Built-in (-f github) |
| Code Climate output | No | Built-in (-f codeclimate) |
| CSV output | No | Built-in (-f csv) |
| Custom log format | Yes | Yes (compatible) |
| OpenVox awareness | No | Yes |
| Plugin system | Yes | Yes (compatible) |
--fix support |
Yes | Yes |
| vim-openvox integration | No | Native |
Apache License, Version 2.0. See LICENSE for details.
Jerald Sheets (@cvquesty)