Build Status

Mask ActiveRecord 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 Active Record 4+ and modern Rubies.

Getting started

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?

Using custom maskers

By default, data is maksed with AttrMasker::Maskers::SIMPLE masker which always returns "(redacted)" string. But anything what responds to #call can be used instead: a lambda, Method instance, and more. You can specify it by setting the :masker option.

For instance, you may want to use ffaker or Well Read Faker to generate random replacement values:

require "ffaker"

attr_masker :first_name, :masker => ->(_hash) { FFaker::Name.first_name }

A hash is passed as an argument, which includes some information about the record being masked and the attribute value. It can be used to further customize masker’s behaviour.

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 :masker option is unspecified.

Example:

attr_masker :first_name
attr_masker :last_name, :masker => AttrMasker::Maskers::SIMPLE

Would set both first_name and last_name attributes 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_only

false

When true, only alphanumeric charaters are replaced.

Example:

rm = AttrMasker::Maskers::Replacing.new(character: "X", alphanum_only: true)
attr_masker :phone, :masker => rm

Would mask "123-456-7890" as "XXX-XXX-XXXX".

Roadmap & TODOs

  • documentation

  • spec tests

  • Make the Rails.env (in which db:mask could be run) configurable

    • maybe by passing ENV vars

  • 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