Module: Metasploit::Framework::Spec::Constants::Each

Defined in:
lib/metasploit/framework/spec/constants/each.rb

Overview

Note:

This should only temporarily be used in ‘spec/spec_helper.rb` when `Metasploit::Framework::Spec::Constants::Suite.configure!` detects a leak. Permanently having `Metasploit::Framework::Spec::Constants::Each.configure!` can lead to false positives when modules are purposely loaded in a `before(:all)` and cleaned up in a `after(:all)`.

Fails example if it leaks module loading constants.

Constant Summary collapse

LOG_PATHNAME =

CONSTANTS

Pathname.new('log/metasploit/framework/spec/constants/each.log')

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.leaks_cleanedObject

Returns the value of attribute leaks_cleaned.

[View on GitHub]

19
20
21
# File 'lib/metasploit/framework/spec/constants/each.rb', line 19

def leaks_cleaned
  @leaks_cleaned
end

Class Method Details

.configure!void

This method returns an undefined value.

Configures after(:each) callback for RSpe to fail example if leaked constants.

[View source] [View on GitHub]

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/metasploit/framework/spec/constants/each.rb', line 33

def self.configure!
  unless @configured
    RSpec.configure do |config|
      config.before(:each) do |example|
        leaks_cleaned = Metasploit::Framework::Spec::Constants.clean

        if leaks_cleaned
          $stderr.puts "Cleaned leaked constants before #{example..full_description}"
        end

        # clean so that leaks from earlier example aren't attributed to this example
        Metasploit::Framework::Spec::Constants::Each.leaks_cleaned ||= leaks_cleaned
      end

      config.after(:each) do |example|
        child_names = Metasploit::Framework::Spec::Constants.to_enum(:each).to_a

        if child_names.length > 0
          lines = ['Leaked constants:']

          child_names.sort.each do |child_name|
            lines << "  #{child_name}"
          end

          lines << ''
          lines << "Add `include_context 'Metasploit::Framework::Spec::Constants cleaner'` to clean up constants from #{example..full_description}"

          message = lines.join("\n")

          # use caller metadata so that Jump to Source in the Rubymine RSpec running jumps to the example instead of
          # here
          fail RuntimeError, message, example.[:caller]
        end
      end

      config.after(:suite) do
        if Metasploit::Framework::Spec::Constants::Each.leaks_cleaned?
          if LOG_PATHNAME.exist?
            LOG_PATHNAME.delete
          end
        else
          LOG_PATHNAME.open('w') { |f|
            f.puts "No leaks were cleaned by `Metasploit::Framework::Spec::Constants::Each.configured!`.  Remove " \
                   "it from `spec/spec_helper.rb` so it does not interfere with contexts that persist loaded " \
                   "modules for entire context and clean up modules in `after(:all)`"
          }
        end
      end
    end

    @configured = true
  end
end

.configured?Boolean

Whether configure! was called

Returns:

  • (Boolean)
[View source] [View on GitHub]

90
91
92
# File 'lib/metasploit/framework/spec/constants/each.rb', line 90

def self.configured?
  !!@configured
end

.define_taskvoid

This method returns an undefined value.

Adds action to ‘spec` task so that `rake spec` fails if configured! is unnecessary in `spec/spec_helper.rb` and should be removed

[View source] [View on GitHub]

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/metasploit/framework/spec/constants/each.rb', line 98

def self.define_task
  Rake::Task.define_task('metasploit:framework:spec:constant:each:clean') do
    if LOG_PATHNAME.exist?
      LOG_PATHNAME.delete
    end
  end

  Rake::Task.define_task(spec: 'metasploit:framework:spec:constant:each:clean')

  Rake::Task.define_task(:spec) do
    if LOG_PATHNAME.exist?
      LOG_PATHNAME.open { |f|
        f.each_line do |line|
          $stderr.write line
        end
      }

      exit(1)
    end
  end
end

.leaks_cleaned?true, false

Is Metasploit::Framework::Spec::Constants::Each.configure! still necessary or should it be removed?

Returns:

  • (true)

    if configure!‘s `before(:each)` cleaned up leaked constants

  • (false)

    otherwise

[View source] [View on GitHub]

26
27
28
# File 'lib/metasploit/framework/spec/constants/each.rb', line 26

def self.leaks_cleaned?
  !!@leaks_cleaned
end