cased-ruby 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rubocop.yml +21 -0
  3. data/.github/workflows/ruby.yml +46 -0
  4. data/.gitignore +10 -0
  5. data/.rubocop.yml +88 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +7 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +8 -0
  10. data/Gemfile.lock +107 -0
  11. data/LICENSE +21 -0
  12. data/README.md +661 -0
  13. data/Rakefile +12 -0
  14. data/bin/console +15 -0
  15. data/bin/rubocop +29 -0
  16. data/cased-ruby.gemspec +48 -0
  17. data/lib/cased-ruby.rb +3 -0
  18. data/lib/cased.rb +260 -0
  19. data/lib/cased/clients.rb +21 -0
  20. data/lib/cased/collection_response.rb +117 -0
  21. data/lib/cased/config.rb +172 -0
  22. data/lib/cased/context.rb +50 -0
  23. data/lib/cased/context/expander.rb +33 -0
  24. data/lib/cased/error.rb +8 -0
  25. data/lib/cased/http/client.rb +83 -0
  26. data/lib/cased/http/error.rb +99 -0
  27. data/lib/cased/instrumentation/controller.rb +34 -0
  28. data/lib/cased/instrumentation/log_subscriber.rb +31 -0
  29. data/lib/cased/integrations/sidekiq.rb +17 -0
  30. data/lib/cased/integrations/sidekiq/client_middleware.rb +14 -0
  31. data/lib/cased/integrations/sidekiq/server_middleware.rb +20 -0
  32. data/lib/cased/model.rb +98 -0
  33. data/lib/cased/policy.rb +24 -0
  34. data/lib/cased/publishers.rb +6 -0
  35. data/lib/cased/publishers/active_support_publisher.rb +16 -0
  36. data/lib/cased/publishers/base.rb +17 -0
  37. data/lib/cased/publishers/error.rb +11 -0
  38. data/lib/cased/publishers/http_publisher.rb +15 -0
  39. data/lib/cased/publishers/null_publisher.rb +11 -0
  40. data/lib/cased/publishers/test_publisher.rb +19 -0
  41. data/lib/cased/query.rb +87 -0
  42. data/lib/cased/rack_middleware.rb +15 -0
  43. data/lib/cased/response.rb +37 -0
  44. data/lib/cased/sensitive.rb +4 -0
  45. data/lib/cased/sensitive/handler.rb +54 -0
  46. data/lib/cased/sensitive/processor.rb +78 -0
  47. data/lib/cased/sensitive/range.rb +54 -0
  48. data/lib/cased/sensitive/result.rb +8 -0
  49. data/lib/cased/sensitive/string.rb +43 -0
  50. data/lib/cased/test_helper.rb +188 -0
  51. data/lib/cased/version.rb +5 -0
  52. data/vendor/cache/activesupport-6.0.3.4.gem +0 -0
  53. data/vendor/cache/addressable-2.7.0.gem +0 -0
  54. data/vendor/cache/ast-2.4.0.gem +0 -0
  55. data/vendor/cache/byebug-11.0.1.gem +0 -0
  56. data/vendor/cache/concurrent-ruby-1.1.7.gem +0 -0
  57. data/vendor/cache/connection_pool-2.2.2.gem +0 -0
  58. data/vendor/cache/crack-0.4.3.gem +0 -0
  59. data/vendor/cache/docile-1.3.2.gem +0 -0
  60. data/vendor/cache/dotpath-0.1.0.gem +0 -0
  61. data/vendor/cache/faraday-1.1.0.gem +0 -0
  62. data/vendor/cache/faraday_middleware-1.0.0.gem +0 -0
  63. data/vendor/cache/hashdiff-1.0.1.gem +0 -0
  64. data/vendor/cache/i18n-1.8.5.gem +0 -0
  65. data/vendor/cache/jaro_winkler-1.5.4.gem +0 -0
  66. data/vendor/cache/json-2.3.1.gem +0 -0
  67. data/vendor/cache/minitest-5.13.0.gem +0 -0
  68. data/vendor/cache/mocha-1.11.2.gem +0 -0
  69. data/vendor/cache/multipart-post-2.1.1.gem +0 -0
  70. data/vendor/cache/net-http-persistent-3.1.0.gem +0 -0
  71. data/vendor/cache/parallel-1.19.1.gem +0 -0
  72. data/vendor/cache/parser-2.7.1.3.gem +0 -0
  73. data/vendor/cache/public_suffix-4.0.5.gem +0 -0
  74. data/vendor/cache/rack-2.2.2.gem +0 -0
  75. data/vendor/cache/rack-protection-2.0.8.1.gem +0 -0
  76. data/vendor/cache/rainbow-3.0.0.gem +0 -0
  77. data/vendor/cache/rake-10.5.0.gem +0 -0
  78. data/vendor/cache/redis-4.1.4.gem +0 -0
  79. data/vendor/cache/rubocop-0.78.0.gem +0 -0
  80. data/vendor/cache/rubocop-performance-1.5.2.gem +0 -0
  81. data/vendor/cache/ruby-progressbar-1.10.1.gem +0 -0
  82. data/vendor/cache/ruby2_keywords-0.0.2.gem +0 -0
  83. data/vendor/cache/safe_yaml-1.0.5.gem +0 -0
  84. data/vendor/cache/sidekiq-6.0.7.gem +0 -0
  85. data/vendor/cache/simplecov-0.18.5.gem +0 -0
  86. data/vendor/cache/simplecov-html-0.12.2.gem +0 -0
  87. data/vendor/cache/thread_safe-0.3.6.gem +0 -0
  88. data/vendor/cache/tzinfo-1.2.7.gem +0 -0
  89. data/vendor/cache/unicode-display_width-1.6.1.gem +0 -0
  90. data/vendor/cache/webmock-3.8.3.gem +0 -0
  91. data/vendor/cache/yard-0.9.24.gem +0 -0
  92. data/vendor/cache/zeitwerk-2.4.0.gem +0 -0
  93. metadata +375 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 45c422e1920ea510d16c5c8a5b91016ac2a4eedb9a2b880ff29018dc18580a13
4
+ data.tar.gz: 83e14abb44637e8d61a3fff592d8b434cbf8373cd8a4c8afede513cf89852f8a
5
+ SHA512:
6
+ metadata.gz: 5beffb4be2a539b74e6145c4d4b7b96ae6aea94c2bb5cdf9a79dfb90bfaeac615c80b537db0249702d807acb7f69727ff7b81cfc62896d03ad6e2c44124c1360
7
+ data.tar.gz: 8ae4ac844f566981de31a5d51ecfe28d4e665f9cebd5c6f5327a596b052e43e92ab0d7db9bb07029211f0786db5baf00035db8022a376b5ea3ba30ac512dbbda
@@ -0,0 +1,21 @@
1
+ name: Rubocop
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ timeout-minutes: 10
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+
13
+ - uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6
16
+
17
+ - name: Install dependencies
18
+ run: |
19
+ gem install bundler
20
+ bundle install --local
21
+ - run: bin/rubocop
@@ -0,0 +1,46 @@
1
+ name: Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ timeout-minutes: 10
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ ruby:
12
+ - "2.5"
13
+ - "2.6"
14
+ - "2.7"
15
+ name: Ruby ${{ matrix.ruby }} test
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+
19
+ - uses: actions/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+
23
+ - name: Install dependencies
24
+ run: |
25
+ gem install bundler
26
+ bundle install --local
27
+
28
+ - name: Run Tests
29
+ run: |
30
+ bundle exec rake test
31
+
32
+ - name: Generate yard documentation
33
+ run: |
34
+ bundle exec yard
35
+
36
+ - name: Upload test coverage report
37
+ uses: actions/upload-artifact@v2
38
+ with:
39
+ name: coverage
40
+ path: coverage/**/*
41
+
42
+ - name: Upload generated yard documentation
43
+ uses: actions/upload-artifact@v2
44
+ with:
45
+ name: yard
46
+ path: doc/**/*
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .DS_Store
10
+ .byebug_history
@@ -0,0 +1,88 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "db/**/*"
4
+ - "config/**/*"
5
+ - "script/**/*"
6
+ - "bin/{rails,rake,bundle}"
7
+ - "node_modules/**/*"
8
+ - "app/views/**/*"
9
+
10
+ Style/Documentation:
11
+ Enabled: false
12
+
13
+ Style/StringLiterals:
14
+ Exclude:
15
+ - db/schema.rb
16
+
17
+ Style/DoubleNegation:
18
+ Enabled: false
19
+
20
+ Style/TrailingCommaInHashLiteral:
21
+ EnforcedStyleForMultiline: comma
22
+
23
+ Style/TrailingCommaInArrayLiteral:
24
+ EnforcedStyleForMultiline: comma
25
+
26
+ Style/TrailingCommaInArguments:
27
+ EnforcedStyleForMultiline: comma
28
+
29
+ Metrics/CyclomaticComplexity:
30
+ Enabled: false
31
+
32
+ Metrics/BlockLength:
33
+ Enabled: false
34
+
35
+ Metrics/ClassLength:
36
+ Enabled: false
37
+
38
+ Metrics/ModuleLength:
39
+ Enabled: false
40
+
41
+ Naming/FileName:
42
+ Exclude:
43
+ - lib/cased-ruby.rb
44
+
45
+ Naming/MethodParameterName:
46
+ Enabled: false
47
+
48
+ Metrics/AbcSize:
49
+ Enabled: false
50
+
51
+ Style/ConditionalAssignment:
52
+ Enabled: false
53
+
54
+ Style/IfUnlessModifier:
55
+ Enabled: false
56
+
57
+ Metrics/PerceivedComplexity:
58
+ Enabled: false
59
+
60
+ Metrics/MethodLength:
61
+ Enabled: false
62
+
63
+ Layout/LineLength:
64
+ Enabled: false
65
+
66
+ Layout/RescueEnsureAlignment:
67
+ Enabled: false
68
+
69
+ Layout/ArgumentAlignment:
70
+ Enabled: false
71
+
72
+ Layout/EndAlignment:
73
+ Enabled: false
74
+
75
+ Layout/ElseAlignment:
76
+ Enabled: false
77
+
78
+ Layout/IndentationWidth:
79
+ Enabled: false
80
+
81
+ Layout/FirstHashElementIndentation:
82
+ Enabled: false
83
+
84
+ Layout/MultilineMethodCallIndentation:
85
+ Enabled: false
86
+
87
+ Layout/CaseIndentation:
88
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.6.5
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at me@garrettbjerkhoel.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in cased-ruby.gemspec
6
+ gemspec
7
+
8
+ gem 'simplecov', '0.18.5', require: false
@@ -0,0 +1,107 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cased-ruby (0.3.3)
5
+ activesupport (~> 6)
6
+ dotpath (= 0.1.0)
7
+ faraday (~> 1.0)
8
+ faraday_middleware (~> 1.0)
9
+ json (~> 2)
10
+ net-http-persistent (~> 3.0)
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activesupport (6.0.3.4)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ zeitwerk (~> 2.2, >= 2.2.2)
21
+ addressable (2.7.0)
22
+ public_suffix (>= 2.0.2, < 5.0)
23
+ ast (2.4.0)
24
+ byebug (11.0.1)
25
+ concurrent-ruby (1.1.7)
26
+ connection_pool (2.2.2)
27
+ crack (0.4.3)
28
+ safe_yaml (~> 1.0.0)
29
+ docile (1.3.2)
30
+ dotpath (0.1.0)
31
+ faraday (1.1.0)
32
+ multipart-post (>= 1.2, < 3)
33
+ ruby2_keywords
34
+ faraday_middleware (1.0.0)
35
+ faraday (~> 1.0)
36
+ hashdiff (1.0.1)
37
+ i18n (1.8.5)
38
+ concurrent-ruby (~> 1.0)
39
+ jaro_winkler (1.5.4)
40
+ json (2.3.1)
41
+ minitest (5.13.0)
42
+ mocha (1.11.2)
43
+ multipart-post (2.1.1)
44
+ net-http-persistent (3.1.0)
45
+ connection_pool (~> 2.2)
46
+ parallel (1.19.1)
47
+ parser (2.7.1.3)
48
+ ast (~> 2.4.0)
49
+ public_suffix (4.0.5)
50
+ rack (2.2.2)
51
+ rack-protection (2.0.8.1)
52
+ rack
53
+ rainbow (3.0.0)
54
+ rake (10.5.0)
55
+ redis (4.1.4)
56
+ rubocop (0.78.0)
57
+ jaro_winkler (~> 1.5.1)
58
+ parallel (~> 1.10)
59
+ parser (>= 2.6)
60
+ rainbow (>= 2.2.2, < 4.0)
61
+ ruby-progressbar (~> 1.7)
62
+ unicode-display_width (>= 1.4.0, < 1.7)
63
+ rubocop-performance (1.5.2)
64
+ rubocop (>= 0.71.0)
65
+ ruby-progressbar (1.10.1)
66
+ ruby2_keywords (0.0.2)
67
+ safe_yaml (1.0.5)
68
+ sidekiq (6.0.7)
69
+ connection_pool (>= 2.2.2)
70
+ rack (~> 2.0)
71
+ rack-protection (>= 2.0.0)
72
+ redis (>= 4.1.0)
73
+ simplecov (0.18.5)
74
+ docile (~> 1.1)
75
+ simplecov-html (~> 0.11)
76
+ simplecov-html (0.12.2)
77
+ thread_safe (0.3.6)
78
+ tzinfo (1.2.7)
79
+ thread_safe (~> 0.1)
80
+ unicode-display_width (1.6.1)
81
+ webmock (3.8.3)
82
+ addressable (>= 2.3.6)
83
+ crack (>= 0.3.2)
84
+ hashdiff (>= 0.4.0, < 2.0.0)
85
+ yard (0.9.24)
86
+ zeitwerk (2.4.0)
87
+
88
+ PLATFORMS
89
+ ruby
90
+
91
+ DEPENDENCIES
92
+ bundler (= 2.1.4)
93
+ byebug (= 11.0.1)
94
+ cased-ruby!
95
+ minitest (= 5.13.0)
96
+ mocha (= 1.11.2)
97
+ rack (= 2.2.2)
98
+ rake (= 10.5.0)
99
+ rubocop (= 0.78.0)
100
+ rubocop-performance (= 1.5.2)
101
+ sidekiq (= 6.0.7)
102
+ simplecov (= 0.18.5)
103
+ webmock (= 3.8.3)
104
+ yard (= 0.9.24)
105
+
106
+ BUNDLED WITH
107
+ 2.1.4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Cased, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,661 @@
1
+ # cased-ruby
2
+
3
+ A Cased client for Ruby applications in your organization to control and monitor the access of information within your organization.
4
+
5
+ ## Overview
6
+
7
+ - [Installation](#installation)
8
+ - [Configuration](#configuration)
9
+ - [Usage](#usage)
10
+ - [Publishing events to Cased](#publishing-events-to-cased)
11
+ - [Retrieving events from a Cased Policy](#retrieving-events-from-a-cased-policy)
12
+ - [Retrieving events from a Cased Policy containing variables](#retrieving-events-from-a-cased-policy-containing-variables)
13
+ - [Retrieving events from multiple Cased Policies](#retrieving-events-from-multiple-cased-policies)
14
+ - [Exporting events](#exporting-events)
15
+ - [Masking & filtering sensitive information](#masking-and-filtering-sensitive-information)
16
+ - [Disable publishing events](#disable-publishing-events)
17
+ - [Context](#context)
18
+ - [Testing](#testing)
19
+ - [Customizing cased-ruby](#customizing-cased-ruby)
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'cased-ruby'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install cased-ruby
36
+
37
+ ## Configuration
38
+
39
+ All configuration options available in cased-ruby are available to be configured by an environment variable or manually.
40
+
41
+ ```ruby
42
+ Cased.configure do |config|
43
+ # CASED_POLICY_KEY=policy_live_1dQpY5JliYgHSkEntAbMVzuOROh
44
+ config.policy_key = 'policy_live_1dQpY5JliYgHSkEntAbMVzuOROh'
45
+
46
+ # CASED_USERS_POLICY_KEY=policy_live_1dQpY8bBgEwdpmdpVrrtDzMX4fH
47
+ # CASED_ORGANIZATIONS_POLICY_KEY=policy_live_1dSHQRurWX8JMYMbkRdfzVoo62d
48
+ config.policy_keys = {
49
+ users: 'policy_live_1dQpY8bBgEwdpmdpVrrtDzMX4fH',
50
+ organizations: 'policy_live_1dSHQRurWX8JMYMbkRdfzVoo62d',
51
+ }
52
+
53
+ # CASED_PUBLISH_KEY=publish_live_1dQpY1jKB48kBd3418PjAotmEwA
54
+ config.publish_key = 'publish_live_1dQpY1jKB48kBd3418PjAotmEwA'
55
+
56
+ # CASED_PUBLISH_URL=https://publish.cased.com
57
+ config.publish_url = 'https://publish.cased.com'
58
+
59
+ # CASED_API_URL=https://api.cased.com
60
+ config.api_url = 'https://api.cased.com'
61
+
62
+ # CASED_RAISE_ON_ERRORS=1
63
+ config.raise_on_errors = false
64
+
65
+ # CASED_SILENCE=1
66
+ config.silence = false
67
+
68
+ # CASED_HTTP_OPEN_TIMEOUT=5
69
+ config.http_open_timeout = 5
70
+
71
+ # CASED_HTTP_READ_TIMEOUT=10
72
+ config.http_read_timeout = 10
73
+ end
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ### Publishing events to Cased
79
+
80
+ There are two ways to publish your first Cased event.
81
+
82
+ **Manually**
83
+
84
+ ```ruby
85
+ require 'cased-ruby'
86
+
87
+ Cased.configure do |config|
88
+ config.publish_key = 'publish_live_1dQpY1jKB48kBd3418PjAotmEwA'
89
+ end
90
+
91
+ Cased.publish(
92
+ action: 'credit_card.charge',
93
+ amount: 2000,
94
+ currency: 'usd',
95
+ source: 'tok_amex',
96
+ description: 'My First Test Charge (created for API docs)',
97
+ credit_card_id: 'card_1dQpXqQwXxsQs9sohN9HrzRAV6y',
98
+ )
99
+ ```
100
+
101
+ **Cased::Model**
102
+
103
+ cased-ruby provides a class mixin that gives you a framework to publish events.
104
+
105
+ ```ruby
106
+ require 'cased-ruby'
107
+
108
+ Cased.configure do |config|
109
+ config.publish_key = 'publish_live_1dQpY1jKB48kBd3418PjAotmEwA'
110
+ end
111
+
112
+ class CreditCard
113
+ include Cased::Model
114
+
115
+ def initialize(amount:, currency:, source:, description:)
116
+ @amount = amount
117
+ @currency = currency
118
+ @source = source
119
+ @description = description
120
+ end
121
+
122
+ def charge
123
+ Stripe::Charge.create({
124
+ amount: @amount,
125
+ currency: @currency,
126
+ source: @source,
127
+ description: @description,
128
+ })
129
+
130
+ cased(:charge, payload: {
131
+ amount: @amount,
132
+ currency: @currency,
133
+ description: @description,
134
+ })
135
+ end
136
+
137
+ def cased_id
138
+ 'card_1dQpXqQwXxsQs9sohN9HrzRAV6y'
139
+ end
140
+
141
+ def cased_payload
142
+ {
143
+ credit_card: self,
144
+ }
145
+ end
146
+ end
147
+
148
+ credit_card = CreditCard.new(
149
+ amount: 2000,
150
+ currency: 'usd',
151
+ source: 'tok_amex',
152
+ description: 'My First Test Charge (created for API docs)',
153
+ )
154
+
155
+ credit_card.charge
156
+ ```
157
+
158
+ Both examples above are equivelent in that they publish the following `credit_card.charge` event to Cased:
159
+
160
+ ```json
161
+ {
162
+ "cased_id": "5f8559cd-4cd9-48c3-b1d0-6eedc4019ec1",
163
+ "action": "credit_card.charge",
164
+ "amount": 2000,
165
+ "currency": "usd",
166
+ "source": "tok_amex",
167
+ "description": "My First Test Charge (created for API docs)",
168
+ "credit_card_id": "card_1dQpXqQwXxsQs9sohN9HrzRAV6y",
169
+ "timestamp": "2020-06-23T02:02:39.932759Z"
170
+ }
171
+ ```
172
+
173
+ ### Retrieving events from a Cased Policy
174
+
175
+ If you plan on retrieving events from your audit trails you must use an Cased Policy token.
176
+
177
+ ```ruby
178
+ require 'cased-ruby'
179
+
180
+ Cased.configure do |config|
181
+ config.policy_key = 'policy_live_1dQpY5JliYgHSkEntAbMVzuOROh'
182
+ end
183
+
184
+ query = Cased.policy.events.limit(25).page(1)
185
+ results = query.results
186
+ results.each do |event|
187
+ puts event['action'] # => credit_card.charge
188
+ puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
189
+ end
190
+ query.total_count # => 2,366
191
+ query.total_pages # => 95
192
+ query.success? # => true
193
+ query.error? # => false
194
+ ```
195
+
196
+ ### Retrieving events from a Cased Policy containing variables
197
+
198
+ Cased policies allow you to filter events by providing variables to your Cased Policy events query. One example of a Cased Policy is to have a single Cased Policy that you can use to query events for any user in your database without having to create a Cased Policy for each user.
199
+
200
+ ```ruby
201
+ require 'cased-ruby'
202
+
203
+ Cased.configure do |config|
204
+ config.policy_key = 'policy_live_1dQpY5JliYgHSkEntAbMVzuOROh'
205
+ end
206
+
207
+ variables = {
208
+ user_id: 'user_1dSHQSNtAH90KA8zGTooMnmMdiD',
209
+ }
210
+ query = Cased.policy(variables: variables).events.limit(25).page(1)
211
+ results = query.results
212
+ results.each do |event|
213
+ puts event['action'] # => credit_card.charge
214
+ puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
215
+ end
216
+ ```
217
+
218
+ ### Retrieving events from multiple Cased Policies
219
+
220
+ To retrieve events from one or more Cased Policies you can configure multiple Cased Policy API keys and retrieve events for each one.
221
+
222
+ ```ruby
223
+ require 'cased-ruby'
224
+
225
+ Cased.configure do |config|
226
+ config.policy_keys = {
227
+ users: 'policy_live_1dQpY8bBgEwdpmdpVrrtDzMX4fH',
228
+ organizations: 'policy_live_1dSHQRurWX8JMYMbkRdfzVoo62d',
229
+ }
230
+ end
231
+
232
+ query = Cased.policy[:users].events.limit(25).page(1)
233
+ results = query.results
234
+ results.each do |event|
235
+ puts event['action'] # => user.login
236
+ puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
237
+ end
238
+
239
+ query = Cased.policy[:organizations].events.limit(25).page(1)
240
+ results = query.results
241
+ results.each do |event|
242
+ puts event['action'] # => organization.create
243
+ puts event['timestamp'] # => 2020-06-22T22:16:31.055655Z
244
+ end
245
+ ```
246
+
247
+ ### Exporting events
248
+
249
+ Exporting events from a Cased Policy allows you to provide users with exports of their own data or to respond to data requests.
250
+
251
+ ```ruby
252
+ require 'cased-ruby'
253
+
254
+ Cased.configure do |config|
255
+ config.policy_key = 'policy_live_1dQpY5JliYgHSkEntAbMVzuOROh'
256
+ end
257
+
258
+ export = Cased.policy.exports.create(
259
+ format: :json,
260
+ phrase: 'action:credit_card.charge',
261
+ )
262
+ export.download_url # => https://api.cased.com/exports/export_1dSHQSNtAH90KA8zGTooMnmMdiD/download?token=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoidXNlcl8xZFFwWThiQmdFd2RwbWRwVnJydER6TVg0ZkgiLCJ
263
+ ```
264
+
265
+ ### Masking & filtering sensitive information
266
+
267
+ If you are handling sensitive information on behalf of your users you should consider masking or filtering any sensitive information.
268
+
269
+ ```ruby
270
+ require 'cased-ruby'
271
+
272
+ Cased.configure do |config|
273
+ config.publish_key = 'publish_live_1dQpY1jKB48kBd3418PjAotmEwA'
274
+ end
275
+
276
+ Cased.publish(
277
+ action: 'credit_card.charge',
278
+ user: Cased::Sensitive::String.new('john@organization.com', label: :email)
279
+ )
280
+ ```
281
+
282
+ ### Console Usage
283
+
284
+ Most Cased events will be created by users from actions on the website from
285
+ custom defined events or lifecycle callbacks. The exception is any console
286
+ session where models may generate Cased events as you start to modify records.
287
+
288
+ By default any console session will include the hostname of where the console
289
+ session takes place. Since every event must have an actor, you must set the
290
+ actor at the beginning of your console session. If you don't know the user,
291
+ it's recommended you create a system/robot user.
292
+
293
+ ```ruby
294
+ # OTHER CONSOLE INITIALIZATION HERE
295
+ Cased.context.push(actor: @actor)
296
+ ```
297
+
298
+ ### Disable publishing events
299
+
300
+ Although rare, there may be times where you wish to disable publishing events to Cased. To do so wrap your transaction inside of a `Cased.disable` block:
301
+
302
+ ```ruby
303
+ Cased.disable do
304
+ user.cased(:login)
305
+ end
306
+ ```
307
+
308
+ Or you can configure the entire process to disable publishing events.
309
+
310
+ ```
311
+ CASED_DISABLE_PUBLISHING=1 bundle exec ruby crawl.rb
312
+ ```
313
+
314
+ ### Context
315
+
316
+ One of the most easiest ways to publish detailed events to Cased is to push contextual information on to the Cased context.
317
+
318
+ ```ruby
319
+ require 'cased-ruby'
320
+
321
+ Cased.configure do |config|
322
+ config.publish_key = 'publish_live_1dQpY1jKB48kBd3418PjAotmEwA'
323
+ end
324
+
325
+ Cased.context.merge(location: 'hostname.local')
326
+
327
+ Cased.publish(
328
+ action: 'console.start',
329
+ user: 'john',
330
+ )
331
+ ```
332
+
333
+ Any information stored in `Cased.context` will be included anytime an event is published.
334
+
335
+ ```json
336
+ {
337
+ "cased_id": "5f8559cd-4cd9-48c3-b1d0-6eedc4019ec1",
338
+ "action": "user.login",
339
+ "user": "john",
340
+ "location": "hostname.local",
341
+ "timestamp": "2020-06-22T21:43:06.157336"
342
+ }
343
+ ```
344
+
345
+ You can provide `Cased.context.merge` a block and the context will only be present for the duration of the block:
346
+
347
+ ```ruby
348
+ Cased.context.merge(location: 'hostname.local') do
349
+ # Will include { "location": "hostname.local" }
350
+ Cased.publish(
351
+ action: 'console.start',
352
+ user: 'john',
353
+ )
354
+ end
355
+
356
+ # Will not include { "location": "hostname.local" }
357
+ Cased.publish(
358
+ action: 'console.end',
359
+ user: 'john',
360
+ )
361
+ ```
362
+
363
+ To clear/reset the context:
364
+
365
+ ```ruby
366
+ Cased.context.clear
367
+ ```
368
+
369
+ ### Testing
370
+
371
+ cased-ruby provides a test helper class that you can use to test events are being published to Cased.
372
+
373
+ ```ruby
374
+ require 'test-helper'
375
+
376
+ class CreditCardTest < Test::Unit::TestCase
377
+ include Cased::TestHelper
378
+
379
+ def test_charging_credit_card_publishes_credit_card_create_event
380
+ credit_card = CreditCard.new(
381
+ amount: 2000,
382
+ currency: 'usd',
383
+ source: 'tok_amex',
384
+ description: 'My First Test Charge (created for API docs)',
385
+ )
386
+
387
+ credit_card.charge
388
+
389
+ assert_cased_events 1, action: 'credit_card.charge', amount: 2000
390
+ end
391
+
392
+ def test_charging_credit_card_publishes_credit_card_create_event_with_block
393
+ credit_card = CreditCard.new(
394
+ amount: 2000,
395
+ currency: 'usd',
396
+ source: 'tok_amex',
397
+ description: 'My First Test Charge (created for API docs)',
398
+ )
399
+
400
+ assert_cased_events 1, action: 'credit_card.charge', amount: 2000 do
401
+ credit_card.charge
402
+ end
403
+ end
404
+
405
+ def test_charging_credit_card_with_zero_amount_does_not_publish_credit_card_create_event
406
+ credit_card = CreditCard.new(
407
+ amount: 0,
408
+ currency: 'usd',
409
+ source: 'tok_amex',
410
+ description: 'My First Test Charge (created for API docs)',
411
+ )
412
+
413
+ assert_no_cased_events do
414
+ credit_card.charge
415
+ end
416
+ end
417
+ end
418
+ ```
419
+
420
+ ## Customizing cased-ruby
421
+
422
+ Out of the box cased-ruby takes care of serializing objects for you to the best of its ability, but you can customize cased-ruby should you like to fit your products needs.
423
+
424
+ Let's look at each of these methods independently as they all work together to
425
+ create the event.
426
+
427
+ `Cased::Model#cased`
428
+
429
+ This method is what publishes events for you to Cased. You include information specific to a particular event when calling `Cased::Model#cased`:
430
+
431
+ ```ruby
432
+ class CreditCard
433
+ include Cased::Model
434
+
435
+ # ...
436
+
437
+ def charge
438
+ Stripe::Charge.create({
439
+ amount: @amount,
440
+ currency: @currency,
441
+ source: @source,
442
+ description: @description,
443
+ })
444
+
445
+ cased(:charge, payload: {
446
+ amount: @amount,
447
+ currency: @currency,
448
+ description: @description,
449
+ })
450
+ end
451
+ end
452
+ ```
453
+
454
+ Or you can customize information that is included anytime `Cased::Model#cased` is called in your class:
455
+
456
+ ```ruby
457
+ class CreditCard
458
+ include Cased::Model
459
+
460
+ # ...
461
+
462
+ def charge
463
+ Stripe::Charge.create({
464
+ amount: @amount,
465
+ currency: @currency,
466
+ source: @source,
467
+ description: @description,
468
+ })
469
+
470
+ cased(:charge)
471
+ end
472
+
473
+ def cased_payload
474
+ {
475
+ credit_card: self,
476
+ amount: @amount,
477
+ currency: @currency,
478
+ description: @description,
479
+ }
480
+ end
481
+ end
482
+ ```
483
+
484
+ Both examples are equivelent.
485
+
486
+ `Cased::Model#cased_category`
487
+
488
+ By default `cased_category` will use the underscore class name to generate the
489
+ prefix for all events generated by this class. If you published a
490
+ `CreditCard#charge` event it would be delivered to Cased `credit_card.charge`. If you want to
491
+ customize what cased-ruby uses you can do so by re-opening the method:
492
+
493
+ ```ruby
494
+ class CreditCard
495
+ include Cased::Model
496
+
497
+ def cased_category
498
+ :card
499
+ end
500
+ end
501
+ ```
502
+
503
+ `Cased::Model#cased_id`
504
+
505
+ Per our guide on [Human and machine readable information](https://docs.cased.com/guides/design-audit-trail-events#human-and-machine-readable-information) for [Designing audit trail events](https://docs.cased.com/guides/design-audit-trail-events) we encourage you to publish a unique identifier that will never change to Cased along with your events. This way when you [retrieve events](#retrieving-events-from-a-cased-policy) from Cased you'll be able to locate the corresponding object in your system.
506
+
507
+ ```ruby
508
+ class User
509
+ include Cased::Model
510
+
511
+ def cased_id
512
+ database_id
513
+ end
514
+ end
515
+ ```
516
+
517
+ `Cased::Model#cased_context`
518
+
519
+ To assist you in publishing events to Cased that are consistent and predictable, cased-ruby attempts to build your `cased_context` as long as you implement either `to_s` or `cased_id` in your class:
520
+
521
+ ```ruby
522
+ class Plan
523
+ include Cased::Model
524
+
525
+ def initialize(name)
526
+ @name = name
527
+ end
528
+
529
+ def cased_id
530
+ database_id
531
+ end
532
+
533
+ def to_s
534
+ @name
535
+ end
536
+ end
537
+
538
+ plan = Plan.new('Free')
539
+ plan.to_s # => 'Free'
540
+ plan.cased_id # => 'plan_1dQpY1jKB48kBd3418PjAotmEwA'
541
+ plan.cased_context # => { plan: 'Free', plan_id: 'plan_1dQpY1jKB48kBd3418PjAotmEwA' }
542
+ ```
543
+
544
+ If your class does not implement `to_s` it will only include `cased_id`:
545
+
546
+ ```ruby
547
+ class Plan
548
+ include Cased::Model
549
+
550
+ def initialize(name)
551
+ @name = name
552
+ end
553
+
554
+ def cased_id
555
+ database_id
556
+ end
557
+ end
558
+
559
+ plan = Plan.new('Free')
560
+ plan.to_s # => '#<Plan:0x00007feadf63b7e0>'
561
+ plan.cased_context # => { plan_id: 'plan_1dQpY1jKB48kBd3418PjAotmEwA' }
562
+ ```
563
+
564
+ Or you can customize it if your `to_s` implementation is not suitable for Cased:
565
+
566
+ ```ruby
567
+ class Plan
568
+ include Cased::Model
569
+
570
+ def initialize(name)
571
+ @name = name
572
+ end
573
+
574
+ def cased_id
575
+ 'plan_1dQpY1jKB48kBd3418PjAotmEwA'
576
+ end
577
+
578
+ def to_s
579
+ @name
580
+ end
581
+
582
+ def cased_context(category: cased_category)
583
+ {
584
+ "#{category}_id".to_sym => cased_id,
585
+ category => @name.parameterize,
586
+ }
587
+ end
588
+ end
589
+
590
+ class CreditCard
591
+ include Cased::Model
592
+
593
+ def initialize(amount:, currency:, source:, description:)
594
+ @amount = amount
595
+ @currency = currency
596
+ @source = source
597
+ @description = description
598
+ end
599
+
600
+ def charge
601
+ Stripe::Charge.create({
602
+ amount: @amount,
603
+ currency: @currency,
604
+ source: @source,
605
+ description: @description,
606
+ })
607
+
608
+ cased(:charge, payload: {
609
+ amount: @amount,
610
+ currency: @currency,
611
+ description: @description,
612
+ })
613
+ end
614
+
615
+ def plan
616
+ Plan.new('Free')
617
+ end
618
+
619
+ def cased_id
620
+ 'card_1dQpXqQwXxsQs9sohN9HrzRAV6y'
621
+ end
622
+
623
+ def cased_payload
624
+ {
625
+ credit_card: self,
626
+ plan: plan,
627
+ }
628
+ end
629
+ end
630
+
631
+ credit_card = CreditCard.new(
632
+ amount: 2000,
633
+ currency: 'usd',
634
+ source: 'tok_amex',
635
+ description: 'My First Test Charge (created for API docs)',
636
+ )
637
+
638
+ credit_card.charge
639
+ ```
640
+
641
+ Results in:
642
+
643
+ ```json
644
+ {
645
+ "cased_id": "5f8559cd-4cd9-48c3-b1d0-6eedc4019ec1",
646
+ "action": "credit_card.charge",
647
+ "credit_card": "personal",
648
+ "credit_card_id": "card_1dQpXqQwXxsQs9sohN9HrzRAV6y",
649
+ "plan": "Free",
650
+ "plan_id": "plan_1dQpY1jKB48kBd3418PjAotmEwA",
651
+ "timestamp": "2020-06-22T20:24:04.815758"
652
+ }
653
+ ```
654
+
655
+ ## Contributing
656
+
657
+ 1. Fork it ( https://github.com/cased/cased-ruby/fork )
658
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
659
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
660
+ 4. Push to the branch (`git push origin my-new-feature`)
661
+ 5. Create a new Pull Request