forget_that 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.byebug_history +37 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +117 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +97 -0
- data/README.md +137 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config/anonymization_config.yml +17 -0
- data/forget_that.gemspec +40 -0
- data/lib/forget_that.rb +19 -0
- data/lib/forget_that/record.rb +18 -0
- data/lib/forget_that/service.rb +83 -0
- data/lib/forget_that/version.rb +3 -0
- data/lib/generators/forget_that/install_generator.rb +31 -0
- data/lib/generators/forget_that/templates/migration.rb.tt +7 -0
- metadata +163 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: c4c089033e63cc13c348be8e0fc634dc9270d835b1427faffcfce82f744fce33
         | 
| 4 | 
            +
              data.tar.gz: ccf7e04335ecc2af7e89742d0e3046c1d2fa04f063f1a45d74de3dade8526d71
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 84525558e0101333d1c38b59a79b48230043dafac018c729f4340e34f1f4b7063b2936b72f82d738abcc1db3e054cfbfadae35312a2e0d733b9505768272ef14
         | 
| 7 | 
            +
              data.tar.gz: 0c5e4546c6f65dcbc70d02a9179258e4d1cb0f200e8f4b54cb0787d6b2cddfb3d1b4e0d8c7d499de903d2b6c968f056001fded5c8599882d5b590b5894b07cba
         | 
    
        data/.byebug_history
    ADDED
    
    | @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            exit
         | 
| 2 | 
            +
            self.default_scoped.object_id
         | 
| 3 | 
            +
            self.object_id
         | 
| 4 | 
            +
            self
         | 
| 5 | 
            +
            exit
         | 
| 6 | 
            +
            klass.for_anonymization.to_sql
         | 
| 7 | 
            +
            klass.where(created_at: (Time.now - 2000.years)..(Time.now), anonymized: 0)
         | 
| 8 | 
            +
            klass.for_anonymization.to_sql
         | 
| 9 | 
            +
            klass.where(created_at: (Time.now - 2000.years)..(Time.now), anonymized: 0)
         | 
| 10 | 
            +
            klass.where(created_at: (Time.now - 2000.years)..(Time.now), anonymized: 1)
         | 
| 11 | 
            +
            klass.where(created_at: (Time.now - 2000.years)..(Time.now), anonymized: true)
         | 
| 12 | 
            +
            klass.where(created_at: (Time.now - 2000.years)..(Time.now))
         | 
| 13 | 
            +
            klass.where(created_at: (Time.now - 2.years)..(Time.now - 90.days))
         | 
| 14 | 
            +
            klass.where(created_at: (Time.now - 2.years)..(Time.now))
         | 
| 15 | 
            +
            klass.where(anonymized: false, created_at: (Time.now - 2.years)..(Time.now))
         | 
| 16 | 
            +
            klass.where(anonymized: false, created_at: (Time.now - 2000.years)..(Time.now))
         | 
| 17 | 
            +
            klass.where(anonymized: false, created_at: (Time.now - 2000.years)..(retention_threshold.call))
         | 
| 18 | 
            +
                end)
         | 
| 19 | 
            +
                  where(anonymized: false, created_at: (Time.now - 2000.years)..(retention_threshold.call))
         | 
| 20 | 
            +
            scope :for_anonymization, (lambda do
         | 
| 21 | 
            +
            klass.for_anonymization.to_sql
         | 
| 22 | 
            +
            klass.all
         | 
| 23 | 
            +
            klass.where(anonymizeed: true).to_sql
         | 
| 24 | 
            +
            klass.where(anonymized: 'true').to_sql
         | 
| 25 | 
            +
            klass.where(anonymized: true).to_sql
         | 
| 26 | 
            +
            klass.where(anonymized: 'true')
         | 
| 27 | 
            +
            klass.where(anonymized: true)
         | 
| 28 | 
            +
            klass.where(anonymized: true).to_sql
         | 
| 29 | 
            +
            klass.where(anonymized: false).to_sql
         | 
| 30 | 
            +
            klass.where(anonymized: false)
         | 
| 31 | 
            +
            klass.where(id: 1)
         | 
| 32 | 
            +
            klass.where()id: 1
         | 
| 33 | 
            +
            klass.where(anonymized: false)
         | 
| 34 | 
            +
            klass.for_anonymization
         | 
| 35 | 
            +
            klass.for:anonymization
         | 
| 36 | 
            +
            klass.all
         | 
| 37 | 
            +
            klass
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    
    
        data/.rubocop.yml
    ADDED
    
    | @@ -0,0 +1,117 @@ | |
| 1 | 
            +
            Style/Documentation:
         | 
| 2 | 
            +
              Enabled: false
         | 
| 3 | 
            +
            Style/MixinUsage:
         | 
| 4 | 
            +
              Exclude:
         | 
| 5 | 
            +
                - 'bin/setup'
         | 
| 6 | 
            +
                - 'bin/update'
         | 
| 7 | 
            +
            Metrics/LineLength:
         | 
| 8 | 
            +
              Max: 120
         | 
| 9 | 
            +
              IgnoredPatterns: ['(\A|\s)#']
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Metrics/MethodLength:
         | 
| 12 | 
            +
              Max: 68
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            Metrics/ClassLength:
         | 
| 15 | 
            +
              Max: 258
         | 
| 16 | 
            +
              Exclude:
         | 
| 17 | 
            +
                - 'app/components/consumer/factories/persist_leasing_request.rb'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Metrics/ModuleLength:
         | 
| 20 | 
            +
              Max: 212
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            Metrics/ParameterLists:
         | 
| 23 | 
            +
              Enabled: false
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            Style/MethodMissingSuper:
         | 
| 26 | 
            +
              Enabled: false
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            Style/MissingRespondToMissing:
         | 
| 29 | 
            +
              Enabled: false
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            Style/NumericLiteralPrefix:
         | 
| 32 | 
            +
              Enabled: false
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Naming/VariableNumber:
         | 
| 35 | 
            +
              Enabled: false
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            Naming/PredicateName:
         | 
| 38 | 
            +
              Enabled: false
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            Style/DoubleNegation:
         | 
| 41 | 
            +
              Enabled: false
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            Style/EmptyMethod:
         | 
| 44 | 
            +
              Enabled: false
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Style/StringLiteralsInInterpolation:
         | 
| 47 | 
            +
              Enabled: false
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            # Nodody really wants this. We are using Ruby! ` return ` as direct call should be used as less as possible
         | 
| 50 | 
            +
            Style/GuardClause:
         | 
| 51 | 
            +
              Enabled: false
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            Style/FormatStringToken:
         | 
| 54 | 
            +
              Exclude:
         | 
| 55 | 
            +
                - spec/**/*
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            Style/SafeNavigation:
         | 
| 58 | 
            +
              Enabled: false
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            Metrics/AbcSize:
         | 
| 61 | 
            +
              Max: 99
         | 
| 62 | 
            +
              Exclude:
         | 
| 63 | 
            +
                - spec/**/*
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            Metrics/CyclomaticComplexity:
         | 
| 66 | 
            +
              Max: 13
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            Metrics/PerceivedComplexity:
         | 
| 69 | 
            +
              Max: 14
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            Documentation:
         | 
| 72 | 
            +
              Enabled: false
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            Layout/MultilineHashBraceLayout:
         | 
| 75 | 
            +
              EnforcedStyle: symmetrical
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            Layout/AlignHash:
         | 
| 78 | 
            +
              Enabled: false
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            Layout/AlignParameters:
         | 
| 81 | 
            +
              Enabled: false
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Metrics/BlockLength:
         | 
| 84 | 
            +
              Enabled: false
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            # TODO: This is just a quickfix, we need to find out what this *really* does.
         | 
| 87 | 
            +
            Lint/SafeNavigationChain:
         | 
| 88 | 
            +
              Enabled: false
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            # Allows to create getter and setter methods with get_ and set_
         | 
| 91 | 
            +
            Naming/AccessorMethodName:
         | 
| 92 | 
            +
              Enabled: false
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            Naming/MemoizedInstanceVariableName:
         | 
| 95 | 
            +
              Enabled: false
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            Lint/AmbiguousBlockAssociation:
         | 
| 98 | 
            +
              Exclude:
         | 
| 99 | 
            +
                - "spec/**/*"
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            Lint/AmbiguousOperator:
         | 
| 102 | 
            +
              Enabled: true
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            AllCops:
         | 
| 105 | 
            +
              DisplayCopNames: true
         | 
| 106 | 
            +
              TargetRubyVersion: 2.5.0
         | 
| 107 | 
            +
              CacheRootDirectory: tmp/test-results
         | 
| 108 | 
            +
              Exclude:
         | 
| 109 | 
            +
                - db/**/*
         | 
| 110 | 
            +
                - bin/**
         | 
| 111 | 
            +
                - utils/**/*
         | 
| 112 | 
            +
                - Guardfile
         | 
| 113 | 
            +
                - config/**/*
         | 
| 114 | 
            +
                - node_modules/**/*
         | 
| 115 | 
            +
                - vendor/**/*
         | 
| 116 | 
            +
                - Gemfile
         | 
| 117 | 
            +
                - Gemfile.lock
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | @@ -0,0 +1,97 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: .
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                forget_that (0.1.0)
         | 
| 5 | 
            +
                  activerecord (>= 5)
         | 
| 6 | 
            +
                  activesupport
         | 
| 7 | 
            +
                  pg
         | 
| 8 | 
            +
                  railties (>= 5)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            GEM
         | 
| 11 | 
            +
              remote: https://rubygems.org/
         | 
| 12 | 
            +
              specs:
         | 
| 13 | 
            +
                actionpack (6.0.2.1)
         | 
| 14 | 
            +
                  actionview (= 6.0.2.1)
         | 
| 15 | 
            +
                  activesupport (= 6.0.2.1)
         | 
| 16 | 
            +
                  rack (~> 2.0, >= 2.0.8)
         | 
| 17 | 
            +
                  rack-test (>= 0.6.3)
         | 
| 18 | 
            +
                  rails-dom-testing (~> 2.0)
         | 
| 19 | 
            +
                  rails-html-sanitizer (~> 1.0, >= 1.2.0)
         | 
| 20 | 
            +
                actionview (6.0.2.1)
         | 
| 21 | 
            +
                  activesupport (= 6.0.2.1)
         | 
| 22 | 
            +
                  builder (~> 3.1)
         | 
| 23 | 
            +
                  erubi (~> 1.4)
         | 
| 24 | 
            +
                  rails-dom-testing (~> 2.0)
         | 
| 25 | 
            +
                  rails-html-sanitizer (~> 1.1, >= 1.2.0)
         | 
| 26 | 
            +
                activemodel (6.0.2.1)
         | 
| 27 | 
            +
                  activesupport (= 6.0.2.1)
         | 
| 28 | 
            +
                activerecord (6.0.2.1)
         | 
| 29 | 
            +
                  activemodel (= 6.0.2.1)
         | 
| 30 | 
            +
                  activesupport (= 6.0.2.1)
         | 
| 31 | 
            +
                activesupport (6.0.2.1)
         | 
| 32 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 33 | 
            +
                  i18n (>= 0.7, < 2)
         | 
| 34 | 
            +
                  minitest (~> 5.1)
         | 
| 35 | 
            +
                  tzinfo (~> 1.1)
         | 
| 36 | 
            +
                  zeitwerk (~> 2.2)
         | 
| 37 | 
            +
                builder (3.2.4)
         | 
| 38 | 
            +
                concurrent-ruby (1.1.5)
         | 
| 39 | 
            +
                crass (1.0.5)
         | 
| 40 | 
            +
                diff-lcs (1.3)
         | 
| 41 | 
            +
                erubi (1.9.0)
         | 
| 42 | 
            +
                i18n (1.7.0)
         | 
| 43 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 44 | 
            +
                loofah (2.4.0)
         | 
| 45 | 
            +
                  crass (~> 1.0.2)
         | 
| 46 | 
            +
                  nokogiri (>= 1.5.9)
         | 
| 47 | 
            +
                method_source (0.9.2)
         | 
| 48 | 
            +
                mini_portile2 (2.4.0)
         | 
| 49 | 
            +
                minitest (5.13.0)
         | 
| 50 | 
            +
                nokogiri (1.10.7)
         | 
| 51 | 
            +
                  mini_portile2 (~> 2.4.0)
         | 
| 52 | 
            +
                pg (1.2.1)
         | 
| 53 | 
            +
                rack (2.0.8)
         | 
| 54 | 
            +
                rack-test (1.1.0)
         | 
| 55 | 
            +
                  rack (>= 1.0, < 3)
         | 
| 56 | 
            +
                rails-dom-testing (2.0.3)
         | 
| 57 | 
            +
                  activesupport (>= 4.2.0)
         | 
| 58 | 
            +
                  nokogiri (>= 1.6)
         | 
| 59 | 
            +
                rails-html-sanitizer (1.3.0)
         | 
| 60 | 
            +
                  loofah (~> 2.3)
         | 
| 61 | 
            +
                railties (6.0.2.1)
         | 
| 62 | 
            +
                  actionpack (= 6.0.2.1)
         | 
| 63 | 
            +
                  activesupport (= 6.0.2.1)
         | 
| 64 | 
            +
                  method_source
         | 
| 65 | 
            +
                  rake (>= 0.8.7)
         | 
| 66 | 
            +
                  thor (>= 0.20.3, < 2.0)
         | 
| 67 | 
            +
                rake (10.5.0)
         | 
| 68 | 
            +
                rspec (3.9.0)
         | 
| 69 | 
            +
                  rspec-core (~> 3.9.0)
         | 
| 70 | 
            +
                  rspec-expectations (~> 3.9.0)
         | 
| 71 | 
            +
                  rspec-mocks (~> 3.9.0)
         | 
| 72 | 
            +
                rspec-core (3.9.1)
         | 
| 73 | 
            +
                  rspec-support (~> 3.9.1)
         | 
| 74 | 
            +
                rspec-expectations (3.9.0)
         | 
| 75 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 76 | 
            +
                  rspec-support (~> 3.9.0)
         | 
| 77 | 
            +
                rspec-mocks (3.9.1)
         | 
| 78 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 79 | 
            +
                  rspec-support (~> 3.9.0)
         | 
| 80 | 
            +
                rspec-support (3.9.2)
         | 
| 81 | 
            +
                thor (1.0.1)
         | 
| 82 | 
            +
                thread_safe (0.3.6)
         | 
| 83 | 
            +
                tzinfo (1.2.6)
         | 
| 84 | 
            +
                  thread_safe (~> 0.1)
         | 
| 85 | 
            +
                zeitwerk (2.2.2)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            PLATFORMS
         | 
| 88 | 
            +
              ruby
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            DEPENDENCIES
         | 
| 91 | 
            +
              bundler (~> 2.0)
         | 
| 92 | 
            +
              forget_that!
         | 
| 93 | 
            +
              rake (~> 10.0)
         | 
| 94 | 
            +
              rspec (~> 3.0)
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            BUNDLED WITH
         | 
| 97 | 
            +
               2.0.2
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,137 @@ | |
| 1 | 
            +
            # ForgetThat
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ForgetThat is a tool to take care of critical data in your database. It replaces the critical pieces of data with anonymized data, according to pre-set per-application policy.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Important notice
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            When misconfigured and/or misused this gem can effectively wipe important data from the database. Be responsible and test before running on production data.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## Installation
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Add this line to your application's Gemfile:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ```ruby
         | 
| 14 | 
            +
            gem 'forget_that'
         | 
| 15 | 
            +
            ```
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            And then execute:
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                $ bundle
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ## Configuration
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Before gem could be used, a config in `config/anonymization_config.yml` in must be created:
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ```YAML
         | 
| 26 | 
            +
            config:
         | 
| 27 | 
            +
              retention_time:
         | 
| 28 | 
            +
                value: 90
         | 
| 29 | 
            +
                unit: 'days'
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            schema:
         | 
| 32 | 
            +
              table1:
         | 
| 33 | 
            +
                name: 'Peter'
         | 
| 34 | 
            +
              table2:
         | 
| 35 | 
            +
                phone: '%{random_phone}'
         | 
| 36 | 
            +
            ```
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            Pay attention that default placeholders are `random_date`, `hex_string`, `random_phone`, `fake_personal_id_number`, `random_amount`. You can add your own placeholders by supplying them to initializer ([see below](#custom_placeholders))
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ## Database migration
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            After you created a config you can generate migration that adds anonymization metadata to corresponding tables:
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                $ rails g forget_that:install
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Do not forget to run the migration:
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                $ rails db:migrate
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            ## Usage
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            In order to run the service, you can create an instance and use the `call` method:
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            ```ruby
         | 
| 55 | 
            +
            ForgetThat::Service.new.call
         | 
| 56 | 
            +
            ```
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Calling that will find records older then `retention_time` in your configured tables and replace the configured fields with configured values.
         | 
| 59 | 
            +
            If some of the placeholders are not supplied, or some tables do not contain `anonymization` flag the error will be raised.
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            ### Sidekiq
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            The case gem is used originally is data anonymization with accordance to data protection regulations in EU. Reducing the amount of sensitive information, after transactions are complete is the safest bet when it comes to data security.
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            This can be achieved through setting up a `sidekiq` worker:
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            ```ruby
         | 
| 68 | 
            +
            class AnonymizeCustomerData
         | 
| 69 | 
            +
              include Sidekiq::Worker
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              sidekiq_options retry: 10
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def perform
         | 
| 74 | 
            +
                Rails.logger.info('[AnonymizeCustomerData.perform] start')
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                ForgetThat::Service.new.call
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                Rails.logger.info('[AnonymizeCustomerData.perform] done')
         | 
| 79 | 
            +
              end
         | 
| 80 | 
            +
            end
         | 
| 81 | 
            +
            ```
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Then you can use tool like `sidekiq-cron` in order to schedule it.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ### Rake-task for using production data locally
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            Another use might be when a developer dumps a production database in order to play with it locally.
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            To be on the safe side and to not compromise sensitive data, the gem might be configured in the following way:
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            ```YAML
         | 
| 92 | 
            +
            config:
         | 
| 93 | 
            +
              retention_time:
         | 
| 94 | 
            +
                value: 0
         | 
| 95 | 
            +
                unit: 'seconds'
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            schema:
         | 
| 98 | 
            +
              # your anonymization schema
         | 
| 99 | 
            +
            ```
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            Then gem can be invoked from the rake-task. It is your responsibility to ensure that it never runs on production.
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            ### Custom placeholders
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            The default placeholders are `random_date`, `hex_string`, `random_phone`, `fake_personal_id_number`, `random_amount`. In some cases this might not be enough or behaviour might not be desireable. In that case you can supply `anonymizers` hash.
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            ```ruby
         | 
| 108 | 
            +
            ForgetThat::Service.new(
         | 
| 109 | 
            +
              anonymizers: {
         | 
| 110 | 
            +
                foobar: -> { 'Foo' + 'Bar' }
         | 
| 111 | 
            +
              }
         | 
| 112 | 
            +
            ).call
         | 
| 113 | 
            +
            ```
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            Each member of this hash must be a zero-arity lambda that returns a string value.
         | 
| 116 | 
            +
             | 
| 117 | 
            +
            If the key in the hash matches one of the pre-defined placeholders, the pre-defined placeholder will be overridden by the new one.
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            After anonymizer was supplied with the lambda, it can be used in the config.
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            ```YAML
         | 
| 122 | 
            +
            # ...
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            schema:
         | 
| 125 | 
            +
              users:
         | 
| 126 | 
            +
                name: 'Peter %{foobar}' #results in the "name" column of table "users" filled with "Peter FooBar"
         | 
| 127 | 
            +
            ```
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            ## Development
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            ## Contributing
         | 
| 136 | 
            +
             | 
| 137 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/vehiculum-berlin/forget_that.
         | 
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/console
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "bundler/setup"
         | 
| 4 | 
            +
            require "forget_that"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # You can add fixtures and/or initialization code here to make experimenting
         | 
| 7 | 
            +
            # with your gem easier. You can also use a different console, if you like.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # (If you use this, don't forget to add pry to your Gemfile!)
         | 
| 10 | 
            +
            # require "pry"
         | 
| 11 | 
            +
            # Pry.start
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "irb"
         | 
| 14 | 
            +
            IRB.start(__FILE__)
         | 
    
        data/bin/setup
    ADDED
    
    
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            config:
         | 
| 2 | 
            +
              retention_time:
         | 
| 3 | 
            +
                value: 90
         | 
| 4 | 
            +
                unit: 'days'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            schema:
         | 
| 7 | 
            +
              addresses:
         | 
| 8 | 
            +
                city: 'Kyteż'
         | 
| 9 | 
            +
                zip_code: '99999'
         | 
| 10 | 
            +
                street: 'Sesame Street'
         | 
| 11 | 
            +
                street_number: '123'
         | 
| 12 | 
            +
                lived_since: '%{random_date}'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              bank_accounts:
         | 
| 15 | 
            +
                bic: '123456789'
         | 
| 16 | 
            +
                iban: '123456789'
         | 
| 17 | 
            +
                bank_name: 'ACME INC.'
         | 
    
        data/forget_that.gemspec
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            lib = File.expand_path('lib', __dir__)
         | 
| 4 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 5 | 
            +
            require 'forget_that/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Gem::Specification.new do |spec|
         | 
| 8 | 
            +
              spec.name          = 'forget_that'
         | 
| 9 | 
            +
              spec.version       = ForgetThat::VERSION
         | 
| 10 | 
            +
              spec.authors       = ['Stan Pankov']
         | 
| 11 | 
            +
              spec.email         = ['s.pankov@vehiculum.de']
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              spec.summary       = "Strip your customers' data from db"
         | 
| 14 | 
            +
              spec.description   = 'Easily setup and run anonymization policies'
         | 
| 15 | 
            +
              spec.homepage      = 'https://github.com/vehiculum-berlin'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.metadata['allowed_push_host'] = 'https://rubygems.org'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              spec.metadata['homepage_uri'] = spec.homepage
         | 
| 20 | 
            +
              spec.metadata['source_code_uri'] = 'https://github.com/vehiculum-berlin/forget_that'
         | 
| 21 | 
            +
              spec.metadata["changelog_uri"] = 'https://github.com/vehiculum-berlin/forget_that'
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              # Specify which files should be added to the gem when it is released.
         | 
| 24 | 
            +
              # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
         | 
| 25 | 
            +
              spec.files = Dir.chdir(File.expand_path(__dir__)) do
         | 
| 26 | 
            +
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              spec.bindir        = 'exe'
         | 
| 29 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 30 | 
            +
              spec.require_paths = ['lib']
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              spec.add_development_dependency 'bundler', '~> 2.0'
         | 
| 33 | 
            +
              spec.add_development_dependency 'rake', '~> 10.0'
         | 
| 34 | 
            +
              spec.add_development_dependency 'rspec', '~> 3.0'
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              spec.add_runtime_dependency 'activerecord', '>= 5'
         | 
| 37 | 
            +
              spec.add_runtime_dependency 'activesupport'
         | 
| 38 | 
            +
              spec.add_runtime_dependency 'pg'
         | 
| 39 | 
            +
              spec.add_runtime_dependency 'railties', '>= 5'
         | 
| 40 | 
            +
            end
         | 
    
        data/lib/forget_that.rb
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'forget_that/version'
         | 
| 4 | 
            +
            require 'forget_that/service'
         | 
| 5 | 
            +
            require 'forget_that/record'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module ForgetThat
         | 
| 8 | 
            +
              class InvalidConfigError < StandardError; end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              class << self
         | 
| 11 | 
            +
                attr_writer :logger
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def logger
         | 
| 14 | 
            +
                  @logger ||= Logger.new($stdout).tap do |log|
         | 
| 15 | 
            +
                    log.progname = self.name
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'active_record'
         | 
| 4 | 
            +
            module ForgetThat
         | 
| 5 | 
            +
              class Record < ActiveRecord::Base
         | 
| 6 | 
            +
                retention_threshold = (
         | 
| 7 | 
            +
                  ->                    { YAML.load_file('config/anonymization_config.yml') } >>
         | 
| 8 | 
            +
                  ->(config)            { config.dig('config', 'retention_time') } >>
         | 
| 9 | 
            +
                  ->(retention_params)  { retention_params['value'].send(retention_params['unit']) } >>
         | 
| 10 | 
            +
                  ->(retention_time)    { Time.current - retention_time }
         | 
| 11 | 
            +
                )
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                scope :for_anonymization, (lambda do
         | 
| 14 | 
            +
                  where(anonymized: false)
         | 
| 15 | 
            +
                    .where('created_at < ?', retention_threshold.call)
         | 
| 16 | 
            +
                end)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,83 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ForgetThat
         | 
| 4 | 
            +
              class Service
         | 
| 5 | 
            +
                def initialize(options = {})
         | 
| 6 | 
            +
                  @custom_anonymizers = options[:anonymizers] || {}
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def call
         | 
| 10 | 
            +
                  raise InvalidConfigError unless valid_config?
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  config.each do |table, columns|
         | 
| 13 | 
            +
                    klass = Class.new(ForgetThat::Record) { self.table_name = table }
         | 
| 14 | 
            +
                    records_hash = klass
         | 
| 15 | 
            +
                                   .for_anonymization
         | 
| 16 | 
            +
                                   .pluck(:id)
         | 
| 17 | 
            +
                                   .map { |id| [id, populate_records_hash(columns)] }
         | 
| 18 | 
            +
                                   .to_h
         | 
| 19 | 
            +
                    klass.update(records_hash.keys, records_hash.values)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def anonymizers
         | 
| 24 | 
            +
                  {
         | 
| 25 | 
            +
                    random_date: -> { Time.now - [*1..10**4].sample.days },
         | 
| 26 | 
            +
                    hex_string: -> { SecureRandom.hex(5) },
         | 
| 27 | 
            +
                    random_phone: -> { "+49#{[*0..10].map { SecureRandom.random_number(10) } .join}" },
         | 
| 28 | 
            +
                    fake_personal_id_number: -> { "DE#{[*0..10].map { SecureRandom.random_number(10) }.join}" },
         | 
| 29 | 
            +
                    random_amount: -> { [*1..80].sample * [*900..1100].sample }
         | 
| 30 | 
            +
                  }.merge(@custom_anonymizers)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def valid_config?
         | 
| 34 | 
            +
                  return false unless valid_anonymizer_set?
         | 
| 35 | 
            +
                  return false unless valid_database_schema?
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  true
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def valid_anonymizer_set?
         | 
| 41 | 
            +
                  available = anonymizers.stringify_keys.keys
         | 
| 42 | 
            +
                  required = config
         | 
| 43 | 
            +
                             .map { |_key, value| value.map { |_key, val| val } }
         | 
| 44 | 
            +
                             .flatten
         | 
| 45 | 
            +
                             .map { |value| value.to_s.scan(/%{(\w*)\.?.*}/) }
         | 
| 46 | 
            +
                             .flatten
         | 
| 47 | 
            +
                             .uniq
         | 
| 48 | 
            +
                  return true if (required - available).empty?
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  ForgetThat.logger.error("Anonymizers #{(required - available).join(', ')} are not defined")
         | 
| 51 | 
            +
                  false
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def valid_database_schema?
         | 
| 55 | 
            +
                  if config
         | 
| 56 | 
            +
                     .keys
         | 
| 57 | 
            +
                     .map { |table| ActiveRecord::Base.connection.columns(table).map(&:name).include? 'anonymized' }
         | 
| 58 | 
            +
                     .reduce { |a, b| a && b }
         | 
| 59 | 
            +
                    true
         | 
| 60 | 
            +
                  else
         | 
| 61 | 
            +
                    ForgetThat.logger.error('Some of the tables in your database do not contain `anonymized` flag')
         | 
| 62 | 
            +
                    false
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                private
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def populate_records_hash(columns)
         | 
| 69 | 
            +
                  columns
         | 
| 70 | 
            +
                    .map { |key, value| [key, value.to_s % generate_anonymized_values] }
         | 
| 71 | 
            +
                    .to_h
         | 
| 72 | 
            +
                    .merge('anonymized' => true)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def generate_anonymized_values
         | 
| 76 | 
            +
                  anonymizers.map { |key, value| [key, value.call] }.to_h
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def config
         | 
| 80 | 
            +
                  YAML.load_file('config/anonymization_config.yml').dig('schema')
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rails/generators/active_record'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ForgetThat
         | 
| 6 | 
            +
              module Generators
         | 
| 7 | 
            +
                class InstallGenerator < Rails::Generators::Base
         | 
| 8 | 
            +
                  include ActiveRecord::Generators::Migration
         | 
| 9 | 
            +
                  source_root File.join(__dir__, 'templates')
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def copy_migration
         | 
| 12 | 
            +
                    migration_template 'migration.rb', 'db/migrate/install_forget_that.rb', migration_version: migration_version
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def migration_version
         | 
| 16 | 
            +
                    "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def used_tables
         | 
| 20 | 
            +
                    YAML
         | 
| 21 | 
            +
                      .load_file('config/anonymization_config.yml')
         | 
| 22 | 
            +
                      .dig('schema')
         | 
| 23 | 
            +
                      .keys
         | 
| 24 | 
            +
                      .map { |table| [table, ActiveRecord::Base.connection.columns(table).map(&:name).include?('anonymized')] }
         | 
| 25 | 
            +
                      .to_h
         | 
| 26 | 
            +
                      .reject { |_key, value| value }
         | 
| 27 | 
            +
                      .keys
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,163 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: forget_that
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Stan Pankov
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2020-01-08 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: bundler
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '2.0'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '2.0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: rake
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '10.0'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '10.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rspec
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '3.0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '3.0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: activerecord
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '5'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '5'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: activesupport
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - ">="
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :runtime
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - ">="
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: pg
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - ">="
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - ">="
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: railties
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - ">="
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '5'
         | 
| 104 | 
            +
              type: :runtime
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - ">="
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: '5'
         | 
| 111 | 
            +
            description: Easily setup and run anonymization policies
         | 
| 112 | 
            +
            email:
         | 
| 113 | 
            +
            - s.pankov@vehiculum.de
         | 
| 114 | 
            +
            executables: []
         | 
| 115 | 
            +
            extensions: []
         | 
| 116 | 
            +
            extra_rdoc_files: []
         | 
| 117 | 
            +
            files:
         | 
| 118 | 
            +
            - ".byebug_history"
         | 
| 119 | 
            +
            - ".gitignore"
         | 
| 120 | 
            +
            - ".rspec"
         | 
| 121 | 
            +
            - ".rubocop.yml"
         | 
| 122 | 
            +
            - ".travis.yml"
         | 
| 123 | 
            +
            - Gemfile
         | 
| 124 | 
            +
            - Gemfile.lock
         | 
| 125 | 
            +
            - README.md
         | 
| 126 | 
            +
            - Rakefile
         | 
| 127 | 
            +
            - bin/console
         | 
| 128 | 
            +
            - bin/setup
         | 
| 129 | 
            +
            - config/anonymization_config.yml
         | 
| 130 | 
            +
            - forget_that.gemspec
         | 
| 131 | 
            +
            - lib/forget_that.rb
         | 
| 132 | 
            +
            - lib/forget_that/record.rb
         | 
| 133 | 
            +
            - lib/forget_that/service.rb
         | 
| 134 | 
            +
            - lib/forget_that/version.rb
         | 
| 135 | 
            +
            - lib/generators/forget_that/install_generator.rb
         | 
| 136 | 
            +
            - lib/generators/forget_that/templates/migration.rb.tt
         | 
| 137 | 
            +
            homepage: https://github.com/vehiculum-berlin
         | 
| 138 | 
            +
            licenses: []
         | 
| 139 | 
            +
            metadata:
         | 
| 140 | 
            +
              allowed_push_host: https://rubygems.org
         | 
| 141 | 
            +
              homepage_uri: https://github.com/vehiculum-berlin
         | 
| 142 | 
            +
              source_code_uri: https://github.com/vehiculum-berlin/forget_that
         | 
| 143 | 
            +
              changelog_uri: https://github.com/vehiculum-berlin/forget_that
         | 
| 144 | 
            +
            post_install_message: 
         | 
| 145 | 
            +
            rdoc_options: []
         | 
| 146 | 
            +
            require_paths:
         | 
| 147 | 
            +
            - lib
         | 
| 148 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 149 | 
            +
              requirements:
         | 
| 150 | 
            +
              - - ">="
         | 
| 151 | 
            +
                - !ruby/object:Gem::Version
         | 
| 152 | 
            +
                  version: '0'
         | 
| 153 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 154 | 
            +
              requirements:
         | 
| 155 | 
            +
              - - ">="
         | 
| 156 | 
            +
                - !ruby/object:Gem::Version
         | 
| 157 | 
            +
                  version: '0'
         | 
| 158 | 
            +
            requirements: []
         | 
| 159 | 
            +
            rubygems_version: 3.0.6
         | 
| 160 | 
            +
            signing_key: 
         | 
| 161 | 
            +
            specification_version: 4
         | 
| 162 | 
            +
            summary: Strip your customers' data from db
         | 
| 163 | 
            +
            test_files: []
         |