Mask ActiveRecord/Mongoid data with ease!
Introduction
This gem is intended to mask sensitive data so that production database dumps can be used in staging or test environments. It works with Rails 4.2+ and modern Rubies. It supports Active Record and Mongoid models.
Usage instructions
Installation
Add attr_masker to your gemfile:
gem "attr_masker", github: "riboseinc/attr_masker"
Then install the gem:
bundle install
Basic usage
In your models, define attributes which should be masked:
class User
attr_masker :email, :first_name, :last_name
end
Then, when you want to mask the data, run the db:mask Rake task in some
Rails environment other than production, for example:
bundle exec rake db:mask RAILS_ENV=staging
|
Warning
|
Data are destructively overwritten. Run rake db:mask with care!
|
Masking records selectively
You can use :if and :unless options to prevent some records from being
altered.
# evaluates given proc for each record, and the record is passed as a proc's
# argument
attr_masker :email :unless => ->(record) { ! record.tester_user? }
# calls #tester_user? method on each record
attr_masker :first_name, :if => :tester_user?
The ActiveRecord’s ::default_scope method has no effect on masking. All
table records are updated, provided that :if and :unless filters allow that.
For example, if you’re using a Paranoia
gem to soft-delete your data, records marked as deleted will be masked as well.
Built-in maskers
Attr Masker comes with several built-in maskers.
AttrMasker::Maskers::Simple-
Simply replaces any value with the
"(redacted)". Only useful for columns containing textual data.This is a default masker. It is used when
:maskeroption is unspecified.Example:
attr_masker :first_name attr_masker :last_name, :masker => AttrMasker::Maskers::Simple.newWould set both
first_nameandlast_nameattributes to"(redacted)". AttrMasker::Maskers::Replacing-
Replaces characters with some masker string (single asterisk by default). Can be initialized with options.
Name Default Description replacement"*"Replacement string, can be empty.
alphanum_onlyfalseWhen true, only alphanumeric characters are replaced.
Example:
rm = AttrMasker::Maskers::Replacing.new(character: "X", alphanum_only: true) attr_masker :phone, :masker => rmWould mask "123-456-7890" as "XXX-XXX-XXXX".
Using custom maskers
Apart from built-in maskers, any object which responds to #call can be used,
e.g. some lambda or Method instance. For instance, you may want to produce
unique values basing on other attributes, to mask selectively, or to use
tool like Well Read Faker to
generate random replacement values:
require "well_read_faker"
attr_masker :email, masker: ->(model:, **) { "user#{model.id}@example.com" }
attr_masker :phone, masker: ->(value:, **) { "******" + value[-3..-1] }
attr_masker :bio, masker: ->(**) { WellReadFaker.paragraph }
Masker is called with following keyword arguments:
value-
Original value of the field which is about to be masked
model-
Model instance
attribute_name-
Name of the attribute which is about to be masked
masking_options-
Hash of options which were passed in
#attr_maskercall
This list is likely to be extended in future versions, and that will not be
considered a breaking change, therefore it is strongly recommended to always
use a splat (**) at end of argument list of masker’s #call method.
Configuration file
It is also possible to contain all the maskers configuration in one file.
Just place it in config/attr_masker.rb, and it will be loaded from a Rake
task after the application is fully loaded. That means you can re-open classes
and add masker definitions there, for example:
# config/attr_masker.rb
class User
attr_masker :first_name, :last_name
end
class Email
attr_masker :address, ->(model:, **) { "mail#{model.id}@example.com" }
end
Roadmap & TODOs
-
documentation
-
spec tests
-
Make the
Rails.env(in whichdb:maskcould be run) configurable-
maybe by passing
ENVvars
-
-
more masking options!
-
default scrambling algorithms?
-
structured text preserving algorithms
-
e.g., keeping an HTML snippet valid HTML, but with masked inner text
-
-
structured Object preserving algorithms
-
i.e. generalization of the above HTML scenario
-
-
-
I18n of the default
"(redacted)"phrase -
…
Acknowledgements
attr_encrypted for the initial code structure