Adds Rubocop rule to detect leading/trailing whitespace in module metadata
This commit is contained in:
@@ -23,6 +23,7 @@ require:
|
||||
- ./lib/rubocop/cop/lint/deprecated_gem_version.rb
|
||||
- ./lib/rubocop/cop/lint/module_enforce_notes.rb
|
||||
- ./lib/rubocop/cop/lint/detect_invalid_pack_directives.rb
|
||||
- ./lib/rubocop/cop/lint/detect_metadata_trailing_leading_whitespace.rb
|
||||
|
||||
Layout/SpaceBeforeBrackets:
|
||||
Enabled: true
|
||||
@@ -672,3 +673,6 @@ Style/UnpackFirst:
|
||||
Disabling to make it easier to copy/paste `unpack('h*')` expressions from code
|
||||
into a debugging REPL.
|
||||
Enabled: false
|
||||
|
||||
Lint/DetectMetadataTrailingLeadingWhitespace:
|
||||
Enabled: true
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# frozen_string_literal: trueAdd commentMore actions
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module Lint
|
||||
# Checks for leading or trailing whitespace in Metasploit module metadata keys/values
|
||||
# inside the initialize method. Recursively checks all hash and array values, except for
|
||||
# keys listed in EXEMPT_KEYS.
|
||||
#
|
||||
# EXEMPT_KEYS can be extended to skip additional metadata fields as needed.
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# 'Name' => ' value '
|
||||
# 'Author' => [' hd']
|
||||
#
|
||||
# # good
|
||||
# 'Name' => 'value'
|
||||
# 'Author' => ['hd']
|
||||
class DetectMetadataTrailingLeadingWhitespace < Base
|
||||
extend AutoCorrector
|
||||
MSG = 'Metadata key or value has leading or trailing whitespace.'
|
||||
EXEMPT_KEYS = %w[Description Payload].freeze
|
||||
|
||||
# Called for every method definition node
|
||||
# Only processes the initialize method
|
||||
# @param node [RuboCop::AST::DefNode]
|
||||
def on_def(node)
|
||||
return unless node.method_name == :initialize
|
||||
|
||||
node.each_descendant(:hash) do |hash_node|
|
||||
hash_node.pairs.each do |pair|
|
||||
key = extract_string(pair.key)
|
||||
next if key && EXEMPT_KEYS.any? { |exempt| key.casecmp?(exempt) }
|
||||
check_value(pair.value)
|
||||
if key && (key != key.strip)
|
||||
add_offense(pair.key, message: MSG) do |corrector|
|
||||
corrector.replace(pair.key.loc.expression, key.strip.inspect)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Recursively checks a value node for whitespace issues
|
||||
# @param node [RuboCop::AST::Node]
|
||||
def check_value(node)
|
||||
case node.type
|
||||
when :str, :dstr
|
||||
value = extract_string(node)
|
||||
if value && value != value.strip
|
||||
add_offense(node, message: MSG) do |corrector|
|
||||
replacement = node.sym_type? ? ":#{value.strip}" : value.strip.inspect
|
||||
corrector.replace(node.loc.expression, replacement)
|
||||
end
|
||||
end
|
||||
when :array
|
||||
node.children.each { |child| check_value(child) }
|
||||
when :hash
|
||||
node.pairs.each do |pair|
|
||||
key = extract_string(pair.key)
|
||||
next if key && EXEMPT_KEYS.any? { |exempt| key.casecmp?(exempt) }
|
||||
if key && key != key.strip
|
||||
add_offense(pair.key, message: MSG) do |corrector|
|
||||
corrector.replace(pair.key.loc.expression, key.strip.inspect)
|
||||
end
|
||||
end
|
||||
check_value(pair.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Extracts the string value from a node (handles str, sym, dstr)
|
||||
# @param node [RuboCop::AST::Node]
|
||||
# @return [String, nil]
|
||||
def extract_string(node)
|
||||
return unless node
|
||||
if node.str_type? || node.sym_type?
|
||||
node.value.to_s
|
||||
elsif node.dstr_type?
|
||||
# For dynamic strings, join all child string values
|
||||
node.children.map { |c| c.is_a?(Parser::AST::Node) ? extract_string(c) : c.to_s }.join
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,131 @@
|
||||
# frozen_string_literal: trueAdd commentMore actions
|
||||
|
||||
require 'rubocop/cop/lint/detect_metadata_trailing_leading_whitespace'
|
||||
require 'rubocop/rspec/support'
|
||||
|
||||
RSpec.describe RuboCop::Cop::Lint::DetectMetadataTrailingLeadingWhitespace, :config do
|
||||
subject(:cop) { described_class.new(config) }
|
||||
|
||||
let(:config) { RuboCop::Config.new }
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in Name' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => ' value ',
|
||||
^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in Author (array)' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Author' => [
|
||||
' author ',
|
||||
^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
],
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in License' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'License' => ' MSF_LICENSE ',
|
||||
^^^^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in Privileged' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Privileged' => ' true ',
|
||||
^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in DefaultOptions (hash)' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'DefaultOptions' => {
|
||||
'WfsDelay' => ' 10 ',
|
||||
^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
},
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in References (array of arrays)' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'References' => [
|
||||
[ ' CVE ', ' 1999-0504 ' ],
|
||||
^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
^^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
],
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in Platform' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Platform' => ' win ',
|
||||
^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in Targets (array of arrays)' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Targets' => [
|
||||
[ ' Automatic ', { 'Arch' => [ ' ARCH_X86 ', ' ARCH_X64 ' ] } ],
|
||||
^^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
],
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in DefaultTarget' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'DefaultTarget' => ' 0 ',
|
||||
^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'registers an offense for leading/trailing whitespace in DisclosureDate' do
|
||||
expect_offense(<<~RUBY)
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'DisclosureDate' => ' 1999-01-01 ',
|
||||
^^^^^^^^^^^^^^ Lint/DetectMetadataTrailingLeadingWhitespace: Metadata key or value has leading or trailing whitespace.
|
||||
))
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user