Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Impersonator is a Ruby library to record and replay object interactions.
When testing, you often find services that are expensive to invoke, and you need to use a double instead. Creating stubs and mocks for simple scenarios is easy, but, for complex interactions, things get messy fast. Stubbing elaborated canned response and orchestrating multiple expectations quickly degenerates in brittle tests that are hard to write and maintain.
Impersonator comes to the rescue. Given an object and a list of methods to impersonate:
Impersonator only focuses on validating invocation signature and reproducing output values, which is perfect for many services. It won't work for services that trigger additional logic that is relevant to the test (e.g., if the method sends an email, the impersonated method won't send it).
Familiar with VCR? Impersonator is like VCR but for ruby objects instead of HTTP.
Add this line to your application's Gemfile:
gem 'impersonator', group: :test
And then execute:
$ bundle
Use Impersonator.impersonate
passing in a list of methods to impersonate and a block that will instantiate the object at record time:
calculator = Impersonator.impersonate(:add, :divide) { Calculator.new }
Calculator
will be instantiated and their methods normally invoked, recording the returned values (and yielded values if any).Calculator
won't be instantiated. Instead, a double object will be generated on the fly that will replay the recorded values.class Calculator
def add(number_1, number_2)
number_1 + number_2
end
end
# The first time it records...
Impersonator.recording('calculator add') do
calculator = Impersonator.impersonate(:add) { Calculator.new }
puts calculator.add(2, 3) # 5
end
# The next time it replays
Object.send :remove_const, :Calculator # Calculator does not even have to exist now
Impersonator.recording('calculator add') do
calculator = Impersonator.impersonate(:add) { Calculator.new }
puts calculator.add(2, 3) # 5
end
Typically you will use impersonate
for testing, so this is how your test will look:
# The second time the test runs, impersonator will replay the
# recorded results
test 'sums the numbers' do
Impersonator.recording('calculator add') do
calculator = Impersonator.impersonate(:add){ Calculator.new }
assert_equal 5, calculator.add(2, 3)
end
end
Impersonated methods will record and replay:
Use Impersonator#impersonate_methods
to impersonate certain methods only. At replay time, the impersonated object will delegate to the actual object all the methods except the impersonated ones.
actual_calculator = Calculator.new
impersonator = Impersonator.impersonate(actual_calculator, :add)
In this case, in replay mode, Calculator
gets instantiated normally and any method other than #add
will be delegated to actual_calculator
.
Impersonator
works by recording method invocations in YAML
format. By default, recordings are saved in:
spec/recordings
if a spec
folder is present in the projecttest/recordings
otherwiseYou can configure this path with:
Impersonator.configure do |config|
config.recordings_path = 'my/own/recording/path'
end
By default, to determine if a method invocation was right, the list of arguments will be matched with ==
. You can configure how this work by providing a list of argument indexes to ignore.
impersonator = Impersonator.impersonate(:add){ Test::Calculator.new }
impersonator.configure_method_matching_for(:add) do |config|
config.ignore_arguments_at 0
end
# Now the first parameter of #add will be ignored.
#
# In record mode:
impersonator.add(1, 2) # 3
# In replay mode
impersonator.add(9999, 2) # will still return 3 and won't fail because the first argument is ignored
You can disable impersonator
by passing disable: true
to Impersonator.recording
:
Impersonator.recording('test recording', disabled: true) do
# ...
end
This will effectively force record mode at all times. This is handy while you are figuring out how interactions with the mocked service go. It will save the recordings, but it will never use them.
Impersonator
relies on Ruby standard YAML
library for serializing/deserializing data. It works with simple attributes, arrays, hashes and objects which attributes are serializable in a recurring way. This means that you don't have to care when interchanging value objects, which is a common scenario when impersonating RPC-like clients.
However, there are some types, like Proc
, anonymous classes, or IO
classes like File
, that will make the serialization process fail. You can customize which attributes are serialized by overriding init_with
and encode_with
in the class you want to serialize. You will typically exclude the problematic attributes by including only the compatible ones.
class MyClass
# ...
def init_with(coder)
self.name = coder['name']
end
def encode_with(coder)
coder['name'] = name
end
end
Impersonator
is test-framework agnostic. If you are using RSpec, you can configure an around
hook that will start a recording session automatically for each example that has an impersonator
tag:
RSpec.configure do |config|
config.around(:example, :impersonator) do |example|
Impersonator.recording(example.full_description) do
example.run
end
end
end
Now you can just tag your tests with impersonator
and an implicit recording named after the example will be available automatically, so you don't have to invoke Impersonator.recording
anymore.
describe Calculator, :impersonator do
it 'sums numbers' do
# there is an implicit recording stored in 'calculator-sums-numbers.yaml'
impersonator = Impersonator.impersonate(:add){ Calculator.new }
expect(impersonator.add(1, 2)).to eq(3)
end
end
Bug reports and pull requests are welcome on GitHub at https://github.com/jorgemanrubia/impersonator.
The gem is available as open source under the terms of the MIT License.`
FAQs
Unknown package
We found that impersonator demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.