Skip to content

Modern linter for Puppet code updated with recent developments in the Puppet language

License

Notifications You must be signed in to change notification settings

cvquesty/openvox-lint

Repository files navigation

openvox-lint

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)

Table of Contents


Prerequisites

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

Optional Prerequisites

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

Supported Platforms

  • macOS (Apple Silicon and Intel)
  • Linux (x86_64, aarch64)
  • Windows (via Ruby for Windows)

Installation

From RubyGems (recommended)

gem install openvox-lint

From Source

git clone https://github.com/cvquesty/openvox-lint.git
cd openvox-lint
gem build openvox-lint.gemspec
gem install openvox-lint-*.gem

Via Bundler

Add to your Gemfile:

gem 'openvox-lint'

Then run:

bundle install

Quick Start

# 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

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

Examples

# 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/

Built-in Checks

openvox-lint ships with 38 built-in checks organized into categories:

Whitespace & Formatting (5 checks)

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

Arrow Alignment (1 check)

Check Severity Description
arrow_alignment warning => arrows should align within resource bodies

Quoting & Strings (5 checks)

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

Variables (2 checks)

Check Severity Description
variable_is_lowercase warning All variables must be lowercase
variable_contains_dash warning Variables must not contain dashes

Resources (7 checks)

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

Classes & Defines (5 checks)

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

Conditionals (2 checks)

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

References & Syntax (4 checks)

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

Comments (1 check)

Check Severity Description
star_comments warning Use # comments, not /* */

URLs (1 check)

Check Severity Description
puppet_url_without_modules warning puppet:/// URLs must include /modules/

Nodes (1 check)

Check Severity Description
node_name_unquoted warning Node names must be quoted strings

Puppet 8 / OpenVox 8 Compatibility (4 checks) ⭐ NEW

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+

Configuration

RC File

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

Inline Ignore Comments

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
}

Output Formats

Text (default)

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

JSON (-f json)

[
  {
    "path": "manifests/init.pp",
    "line": 5,
    "column": 15,
    "kind": "warning",
    "check": "unquoted_file_mode",
    "message": "unquoted file mode"
  }
]

GitHub Actions (-f github)

::warning file=manifests/init.pp,line=5,col=15::unquoted_file_mode: unquoted file mode

CSV (-f csv)

path,line,column,kind,check,message
manifests/init.pp,5,15,warning,unquoted_file_mode,"unquoted file mode"

Code Climate (-f codeclimate)

Standard Code Climate JSON format for quality dashboards.

Custom (--log-format)

openvox-lint --log-format '%{path}:%{line}:%{column}:%{KIND}:%{check}:%{message}' .

Available placeholders: %{path}, %{line}, %{column}, %{KIND}, %{kind}, %{check}, %{message}


Integration

vim-openvox

openvox-lint is the default backend for the vim-openvox Vim plugin. Set in .vimrc:

let g:openvox_lint_command = 'openvox-lint'

GitHub Actions

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/

Rake Integration

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

Pre-commit Hook

#!/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 $files

Writing Custom Checks

Create 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
end

Place in lib/openvox-lint/plugins/checks/ and it will be auto-loaded.


Development

git clone https://github.com/cvquesty/openvox-lint.git
cd openvox-lint
bundle install
bundle exec rake spec

Project Structure

openvox-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

Comparison with puppet-lint

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

License

Apache License, Version 2.0. See LICENSE for details.


Author

Jerald Sheets (@cvquesty)

About

Modern linter for Puppet code updated with recent developments in the Puppet language

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages