
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
matchi
Advanced tools
Matchi is a lightweight, framework-agnostic Ruby library that provides a comprehensive set of expectation matchers for elegant and secure testing. Its design focuses on simplicity, security, and extensibility.

While most Matchi matchers are designed to resist type spoofing, predicate matchers (Matchi::Predicate) rely on Ruby's dynamic method dispatch system and can be vulnerable to method overriding:
# Example of predicate matcher vulnerability:
matcher = Matchi::Predicate.new(:be_empty)
array = []
# Method overriding can defeat the matcher
def array.empty?
false
end
matcher.match? { array } # => false (Even though array is empty!)
This limitation is inherent to Ruby's dynamic nature when working with predicate methods. If your tests require strict security guarantees, consider using direct state verification matchers instead of predicate matchers.
A Matchi matcher is a simple Ruby object that follows a specific contract:
Core Interface: Every matcher must implement a match? method that:
Optional Description: Matchers can implement a to_s method that returns a human-readable description of the match criteria
Here's the simplest possible matcher:
module Matchi
class SimpleEqual
def initialize(expected)
@expected = expected
end
def match?
raise ArgumentError, "a block must be provided" unless block_given?
@expected == yield
end
def to_s
"equal #{@expected.inspect}"
end
end
end
# Usage:
matcher = Matchi::SimpleEqual.new(42)
matcher.match? { 42 } # => true
matcher.match? { "42" } # => false
matcher.to_s # => "equal 42"
This design provides several benefits:
Add to your Gemfile:
gem "matchi"
Or install directly:
gem install matchi
require "matchi"
# Basic equality matching
Matchi::Eq.new("hello").match? { "hello" } # => true
# Type checking
Matchi::BeAKindOf.new(Numeric).match? { 42 } # => true
Matchi::BeAKindOf.new(String).match? { 42 } # => false
# State change verification
array = []
Matchi::Change.new(array, :length).by(2).match? { array.push(1, 2) } # => true
# Exact equality (eql?)
Matchi::Eq.new("test").match? { "test" } # => true
Matchi::Eq.new([1, 2, 3]).match? { [1, 2, 3] } # => true
# Object identity (equal?)
symbol = :test
Matchi::Be.new(symbol).match? { symbol } # => true
string = "test"
Matchi::Be.new(string).match? { string.dup } # => false
# Inheritance-aware type checking
Matchi::BeAKindOf.new(Numeric).match? { 42.0 } # => true
Matchi::BeAKindOf.new(Integer).match? { 42.0 } # => false
# Exact type matching
Matchi::BeAnInstanceOf.new(Float).match? { 42.0 } # => true
Matchi::BeAnInstanceOf.new(Numeric).match? { 42.0 } # => false
# Using class names as strings
Matchi::BeAKindOf.new("Numeric").match? { 42.0 } # => true
Matchi::BeAnInstanceOf.new("Float").match? { 42.0 } # => true
# Verify exact changes
counter = 0
Matchi::Change.new(counter, :to_i).by(5).match? { counter += 5 } # => true
# Verify minimum changes
Matchi::Change.new(counter, :to_i).by_at_least(2).match? { counter += 3 } # => true
# Verify maximum changes
Matchi::Change.new(counter, :to_i).by_at_most(5).match? { counter += 3 } # => true
# Track value transitions
string = "hello"
Matchi::Change.new(string, :to_s).from("hello").to("HELLO").match? { string.upcase! } # => true
# Simple change detection
array = []
Matchi::Change.new(array, :length).match? { array << 1 } # => true
# Check final state only
counter = 0
Matchi::Change.new(counter, :to_i).to(5).match? { counter = 5 } # => true
# Regular expressions
Matchi::Match.new(/^test/).match? { "test_string" } # => true
Matchi::Match.new(/^\d{3}-\d{2}$/).match? { "123-45" } # => true
# Custom predicates with Satisfy
Matchi::Satisfy.new { |x| x.positive? && x < 10 }.match? { 5 } # => true
Matchi::Satisfy.new { |arr| arr.all?(&:even?) }.match? { [2, 4, 6] } # => true
# Built-in predicates
Matchi::Predicate.new(:be_empty).match? { [] } # => true
Matchi::Predicate.new(:have_key, :name).match? { { name: "Alice" } } # => true
# Verify raised exceptions
Matchi::RaiseException.new(ArgumentError).match? { raise ArgumentError } # => true
# Works with inheritance
Matchi::RaiseException.new(StandardError).match? { raise ArgumentError } # => true
# Using exception class names
Matchi::RaiseException.new("ArgumentError").match? { raise ArgumentError } # => true
# Delta comparisons
Matchi::BeWithin.new(0.5).of(3.0).match? { 3.2 } # => true
Matchi::BeWithin.new(2).of(10).match? { 9 } # => true
Creating custom matchers is straightforward:
module Matchi
class BePositive
def match?
yield.positive?
end
def to_s
"be positive"
end
end
end
matcher = Matchi::BePositive.new
matcher.match? { 42 } # => true
matcher.match? { -1 } # => false
One of the most critical aspects when implementing matchers is the order of comparison between expected and actual values. Always compare values in this order:
# GOOD: Expected value controls the comparison
expected_value.eql?(actual_value)
# BAD: Actual value controls the comparison
actual_value.eql?(expected_value)
The order is crucial because the object receiving the comparison method controls how the comparison is performed. When testing, the actual value might come from untrusted or malicious code that could override comparison methods:
# Example of how comparison can be compromised
class MaliciousString
def eql?(other)
true # Always returns true regardless of actual equality
end
def ==(other)
true # Always returns true regardless of actual equality
end
end
actual = MaliciousString.new
expected = "expected string"
actual.eql?(expected) # => true (incorrect result!)
expected.eql?(actual) # => false (correct result)
This is why Matchi's built-in matchers are implemented with this security consideration in mind. For example, the Eq matcher:
# Implementation in Matchi::Eq
def match?
@expected.eql?(yield) # Expected value controls the comparison
end
The matchi-fix gem extends Matchi with support for testing against Fix specifications. It provides a seamless integration between Matchi's matcher interface and Fix's powerful specification system.
# Add to your Gemfile
gem "matchi-fix"
This extension adds a Fix matcher that allows you to verify implementation conformance to Fix test specifications across different testing frameworks like Minitest and RSpec.
Matchi follows Semantic Versioning 2.0.
The gem is available as open source under the terms of the MIT License.
This project is sponsored by Sashité
FAQs
Unknown package
We found that matchi demonstrated a healthy version release cadence and project activity because the last version was released less than 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
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.