cased-ruby 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +20 -15
- data/README.md +14 -41
- data/bin/cli +14 -0
- data/cased-ruby.gemspec +2 -0
- data/lib/cased.rb +1 -0
- data/lib/cased/cli.rb +13 -0
- data/lib/cased/cli/asciinema/file.rb +108 -0
- data/lib/cased/cli/asciinema/writer.rb +67 -0
- data/lib/cased/cli/authentication.rb +31 -0
- data/lib/cased/cli/identity.rb +38 -0
- data/lib/cased/cli/interactive_session.rb +84 -0
- data/lib/cased/cli/log.rb +25 -0
- data/lib/cased/cli/recorder.rb +57 -0
- data/lib/cased/cli/session.rb +278 -0
- data/lib/cased/clients.rb +7 -3
- data/lib/cased/config.rb +40 -0
- data/lib/cased/http/client.rb +13 -6
- data/lib/cased/http/error.rb +5 -2
- data/lib/cased/query.rb +6 -3
- data/lib/cased/version.rb +1 -1
- data/vendor/cache/activesupport-6.1.3.gem +0 -0
- data/vendor/cache/concurrent-ruby-1.1.8.gem +0 -0
- data/vendor/cache/faraday-1.3.0.gem +0 -0
- data/vendor/cache/faraday-net_http-1.0.1.gem +0 -0
- data/vendor/cache/i18n-1.8.9.gem +0 -0
- data/vendor/cache/json-2.5.1.gem +0 -0
- data/vendor/cache/jwt-2.2.2.gem +0 -0
- data/vendor/cache/ruby2_keywords-0.0.4.gem +0 -0
- data/vendor/cache/subprocess-1.5.4.gem +0 -0
- data/vendor/cache/tzinfo-2.0.4.gem +0 -0
- data/vendor/cache/zeitwerk-2.4.2.gem +0 -0
- metadata +51 -11
- data/vendor/cache/activesupport-6.0.3.4.gem +0 -0
- data/vendor/cache/concurrent-ruby-1.1.7.gem +0 -0
- data/vendor/cache/faraday-1.1.0.gem +0 -0
- data/vendor/cache/i18n-1.8.5.gem +0 -0
- data/vendor/cache/json-2.3.1.gem +0 -0
- data/vendor/cache/ruby2_keywords-0.0.2.gem +0 -0
- data/vendor/cache/thread_safe-0.3.6.gem +0 -0
- data/vendor/cache/tzinfo-1.2.7.gem +0 -0
- data/vendor/cache/zeitwerk-2.4.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e22f14bbfac74d8d6ed2565ab7d4dd2607b03178a8534e15681ebad08aadd047
|
4
|
+
data.tar.gz: aeec32fc2d39829a6e4c24b4b8024b416dad08d84528d13eaa2d310c4a3c2c59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba38566776a824c05f9750a72ca0e0b878279a07e5134fac83d54e9f10d462a8a940bf01f5d0968c1654adfb9a196f3d7ad6398614c987e41168bdf81d40cd93
|
7
|
+
data.tar.gz: f5bde94bab92b5cfc4dce4a146ca5a1d02d7946f14e5003386b3b82c920c656b92665b801b5ae5ef116316b0d33e7c3d727a730bda46426e30d08380b7bac798
|
data/Gemfile.lock
CHANGED
@@ -1,43 +1,48 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cased-ruby (0.
|
4
|
+
cased-ruby (0.4.0)
|
5
5
|
activesupport (~> 6)
|
6
6
|
dotpath (= 0.1.0)
|
7
7
|
faraday (~> 1.0)
|
8
8
|
faraday_middleware (~> 1.0)
|
9
9
|
json (~> 2)
|
10
|
+
jwt (~> 2)
|
10
11
|
net-http-persistent (~> 3.0)
|
12
|
+
subprocess (~> 1.5.0)
|
11
13
|
|
12
14
|
GEM
|
13
15
|
remote: https://rubygems.org/
|
14
16
|
specs:
|
15
|
-
activesupport (6.
|
17
|
+
activesupport (6.1.3)
|
16
18
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
-
i18n (>=
|
18
|
-
minitest (
|
19
|
-
tzinfo (~>
|
20
|
-
zeitwerk (~> 2.
|
19
|
+
i18n (>= 1.6, < 2)
|
20
|
+
minitest (>= 5.1)
|
21
|
+
tzinfo (~> 2.0)
|
22
|
+
zeitwerk (~> 2.3)
|
21
23
|
addressable (2.7.0)
|
22
24
|
public_suffix (>= 2.0.2, < 5.0)
|
23
25
|
ast (2.4.0)
|
24
26
|
byebug (11.0.1)
|
25
|
-
concurrent-ruby (1.1.
|
27
|
+
concurrent-ruby (1.1.8)
|
26
28
|
connection_pool (2.2.2)
|
27
29
|
crack (0.4.3)
|
28
30
|
safe_yaml (~> 1.0.0)
|
29
31
|
docile (1.3.2)
|
30
32
|
dotpath (0.1.0)
|
31
|
-
faraday (1.
|
33
|
+
faraday (1.3.0)
|
34
|
+
faraday-net_http (~> 1.0)
|
32
35
|
multipart-post (>= 1.2, < 3)
|
33
36
|
ruby2_keywords
|
37
|
+
faraday-net_http (1.0.1)
|
34
38
|
faraday_middleware (1.0.0)
|
35
39
|
faraday (~> 1.0)
|
36
40
|
hashdiff (1.0.1)
|
37
|
-
i18n (1.8.
|
41
|
+
i18n (1.8.9)
|
38
42
|
concurrent-ruby (~> 1.0)
|
39
43
|
jaro_winkler (1.5.4)
|
40
|
-
json (2.
|
44
|
+
json (2.5.1)
|
45
|
+
jwt (2.2.2)
|
41
46
|
minitest (5.13.0)
|
42
47
|
mocha (1.11.2)
|
43
48
|
multipart-post (2.1.1)
|
@@ -63,7 +68,7 @@ GEM
|
|
63
68
|
rubocop-performance (1.5.2)
|
64
69
|
rubocop (>= 0.71.0)
|
65
70
|
ruby-progressbar (1.10.1)
|
66
|
-
ruby2_keywords (0.0.
|
71
|
+
ruby2_keywords (0.0.4)
|
67
72
|
safe_yaml (1.0.5)
|
68
73
|
sidekiq (6.0.7)
|
69
74
|
connection_pool (>= 2.2.2)
|
@@ -74,16 +79,16 @@ GEM
|
|
74
79
|
docile (~> 1.1)
|
75
80
|
simplecov-html (~> 0.11)
|
76
81
|
simplecov-html (0.12.2)
|
77
|
-
|
78
|
-
tzinfo (
|
79
|
-
|
82
|
+
subprocess (1.5.4)
|
83
|
+
tzinfo (2.0.4)
|
84
|
+
concurrent-ruby (~> 1.0)
|
80
85
|
unicode-display_width (1.6.1)
|
81
86
|
webmock (3.8.3)
|
82
87
|
addressable (>= 2.3.6)
|
83
88
|
crack (>= 0.3.2)
|
84
89
|
hashdiff (>= 0.4.0, < 2.0.0)
|
85
90
|
yard (0.9.24)
|
86
|
-
zeitwerk (2.4.
|
91
|
+
zeitwerk (2.4.2)
|
87
92
|
|
88
93
|
PLATFORMS
|
89
94
|
ruby
|
data/README.md
CHANGED
@@ -8,15 +8,15 @@ A Cased client for Ruby applications in your organization to control and monitor
|
|
8
8
|
- [Configuration](#configuration)
|
9
9
|
- [Usage](#usage)
|
10
10
|
- [Publishing events to Cased](#publishing-events-to-cased)
|
11
|
-
- [Retrieving events from a Cased
|
12
|
-
- [Retrieving events from
|
13
|
-
- [Retrieving events from multiple Cased Policies](#retrieving-events-from-multiple-cased-policies)
|
11
|
+
- [Retrieving events from a Cased audit trail](#retrieving-events-from-a-cased-audit-trail)
|
12
|
+
- [Retrieving events from multiple Cased audit trails](#retrieving-events-from-multiple-cased-audit-trails)
|
14
13
|
- [Exporting events](#exporting-events)
|
15
|
-
- [Masking & filtering sensitive information](#masking
|
14
|
+
- [Masking & filtering sensitive information](#masking--filtering-sensitive-information)
|
16
15
|
- [Disable publishing events](#disable-publishing-events)
|
17
16
|
- [Context](#context)
|
18
17
|
- [Testing](#testing)
|
19
18
|
- [Customizing cased-ruby](#customizing-cased-ruby)
|
19
|
+
- [Contributing](#contributing)
|
20
20
|
|
21
21
|
## Installation
|
22
22
|
|
@@ -100,7 +100,7 @@ Cased.publish(
|
|
100
100
|
|
101
101
|
**Cased::Model**
|
102
102
|
|
103
|
-
cased-ruby provides a class mixin that gives you a framework to publish events.
|
103
|
+
`cased-ruby` provides a class mixin that gives you a framework to publish events.
|
104
104
|
|
105
105
|
```ruby
|
106
106
|
require 'cased-ruby'
|
@@ -170,9 +170,9 @@ Both examples above are equivelent in that they publish the following `credit_ca
|
|
170
170
|
}
|
171
171
|
```
|
172
172
|
|
173
|
-
### Retrieving events from a Cased
|
173
|
+
### Retrieving events from a Cased audit trail
|
174
174
|
|
175
|
-
If you plan on retrieving events from your audit
|
175
|
+
If you plan on retrieving audit events from your Cased audit trail you must use a Cased API key.
|
176
176
|
|
177
177
|
```ruby
|
178
178
|
require 'cased-ruby'
|
@@ -193,31 +193,9 @@ query.success? # => true
|
|
193
193
|
query.error? # => false
|
194
194
|
```
|
195
195
|
|
196
|
-
### Retrieving events from
|
196
|
+
### Retrieving events from multiple Cased audit trails
|
197
197
|
|
198
|
-
|
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.
|
198
|
+
To retrieve audit events from one or more Cased audit trails you can configure multiple Cased Policy API keys and retrieve events for each one.
|
221
199
|
|
222
200
|
```ruby
|
223
201
|
require 'cased-ruby'
|
@@ -229,14 +207,14 @@ Cased.configure do |config|
|
|
229
207
|
}
|
230
208
|
end
|
231
209
|
|
232
|
-
query = Cased.
|
210
|
+
query = Cased.policies[:users].events.limit(25).page(1)
|
233
211
|
results = query.results
|
234
212
|
results.each do |event|
|
235
213
|
puts event['action'] # => user.login
|
236
214
|
puts event['timestamp'] # => 2020-06-23T02:02:39.932759Z
|
237
215
|
end
|
238
216
|
|
239
|
-
query = Cased.
|
217
|
+
query = Cased.policies[:organizations].events.limit(25).page(1)
|
240
218
|
results = query.results
|
241
219
|
results.each do |event|
|
242
220
|
puts event['action'] # => organization.create
|
@@ -246,7 +224,7 @@ end
|
|
246
224
|
|
247
225
|
### Exporting events
|
248
226
|
|
249
|
-
Exporting events from
|
227
|
+
Exporting events from Cased allows you to provide users with exports of their own data or to respond to data requests.
|
250
228
|
|
251
229
|
```ruby
|
252
230
|
require 'cased-ruby'
|
@@ -281,14 +259,9 @@ Cased.publish(
|
|
281
259
|
|
282
260
|
### Console Usage
|
283
261
|
|
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.
|
262
|
+
Most Cased events will be created by users from actions on the website from custom defined events or lifecycle callbacks. The exception is any console session where models may generate Cased events as you start to modify records.
|
287
263
|
|
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.
|
264
|
+
By default any console session will include the hostname of where the console session takes place. Since every event must have an actor, you must set the actor at the beginning of your console session. If you don't know the user, it's recommended you create a system/robot user.
|
292
265
|
|
293
266
|
```ruby
|
294
267
|
# OTHER CONSOLE INITIALIZATION HERE
|
data/bin/cli
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'cased-ruby'
|
6
|
+
|
7
|
+
Cased.configure do |config|
|
8
|
+
config.guard_application_key = 'guard_application_1oFqltbMqSEtJQKRCAYQNrQoXsS'
|
9
|
+
config.guard_deny_if_unreachable = true
|
10
|
+
end
|
11
|
+
|
12
|
+
Cased::CLI::InteractiveSession.start
|
13
|
+
|
14
|
+
puts 'Something destructive'
|
data/cased-ruby.gemspec
CHANGED
@@ -33,7 +33,9 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_dependency 'faraday', '~> 1.0'
|
34
34
|
spec.add_dependency 'faraday_middleware', '~> 1.0'
|
35
35
|
spec.add_dependency 'json', '~> 2'
|
36
|
+
spec.add_dependency 'jwt', '~> 2'
|
36
37
|
spec.add_dependency 'net-http-persistent', '~> 3.0'
|
38
|
+
spec.add_dependency 'subprocess', '~> 1.5.0'
|
37
39
|
spec.add_development_dependency 'bundler', '2.1.4'
|
38
40
|
spec.add_development_dependency 'byebug', '11.0.1'
|
39
41
|
spec.add_development_dependency 'minitest', '5.13.0'
|
data/lib/cased.rb
CHANGED
data/lib/cased/cli.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cased
|
4
|
+
module CLI
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'cased/cli/asciinema/writer'
|
9
|
+
require 'cased/cli/asciinema/file'
|
10
|
+
require 'cased/cli/recorder'
|
11
|
+
require 'cased/cli/log'
|
12
|
+
require 'cased/cli/session'
|
13
|
+
require 'cased/cli/interactive_session'
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Cased
|
6
|
+
module CLI
|
7
|
+
# Spec: https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md
|
8
|
+
module Asciinema
|
9
|
+
class File
|
10
|
+
OUT = 'o'
|
11
|
+
IN = 'i'
|
12
|
+
|
13
|
+
def self.from_writer(writer)
|
14
|
+
new(writer.header, writer.stream)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_cast(cast)
|
18
|
+
stream = cast.split("\n").collect do |data|
|
19
|
+
JSON.parse(data)
|
20
|
+
end
|
21
|
+
header = stream.shift
|
22
|
+
|
23
|
+
new(header, stream)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Required
|
27
|
+
attr_reader :header
|
28
|
+
attr_reader :version
|
29
|
+
attr_reader :width
|
30
|
+
attr_reader :height
|
31
|
+
attr_reader :stream
|
32
|
+
|
33
|
+
# Optional
|
34
|
+
attr_reader :timestamp
|
35
|
+
attr_reader :duration
|
36
|
+
attr_reader :idle_time_limit
|
37
|
+
attr_reader :command
|
38
|
+
attr_reader :title
|
39
|
+
attr_reader :env
|
40
|
+
attr_reader :theme
|
41
|
+
|
42
|
+
def initialize(header, stream)
|
43
|
+
@header = header
|
44
|
+
@version = header.fetch('version')
|
45
|
+
@width = header.fetch('width')
|
46
|
+
@height = header.fetch('height')
|
47
|
+
self.timestamp = header['timestamp']
|
48
|
+
self.duration = header['duration']
|
49
|
+
self.idle_time_limit = header['idle_time_limit']
|
50
|
+
@command = header['command']
|
51
|
+
@title = header['title']
|
52
|
+
@env = header.fetch('env', {})
|
53
|
+
@theme = header['theme']
|
54
|
+
@stream = stream
|
55
|
+
end
|
56
|
+
|
57
|
+
def timestamp=(new_timestamp)
|
58
|
+
@timestamp = case new_timestamp
|
59
|
+
when Integer
|
60
|
+
Time.at(new_timestamp)
|
61
|
+
when Time, NilClass
|
62
|
+
new_timestamp
|
63
|
+
else
|
64
|
+
raise ArgumentError, "unexpected timestamp format #{new_timestamp.class}, expected Integer, Time, or nil"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def duration=(new_duration)
|
69
|
+
@duration = case new_duration
|
70
|
+
when Float, NilClass
|
71
|
+
new_duration
|
72
|
+
else
|
73
|
+
raise ArgumentError, "unexpected duration format #{new_duration.class}, expected Float or nil"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def idle_time_limit=(new_idle_time_limit)
|
78
|
+
@idle_time_limit = case new_idle_time_limit
|
79
|
+
when Numeric, NilClass
|
80
|
+
new_idle_time_limit
|
81
|
+
else
|
82
|
+
raise ArgumentError, "unexpected idle_time_limit format #{new_idle_time_limit.class}, expected Integer, Float, or nil"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_cast
|
87
|
+
builder = []
|
88
|
+
builder << JSON.dump(header)
|
89
|
+
stream.each do |duration, type, data|
|
90
|
+
builder << JSON.dump([duration, type, data])
|
91
|
+
end
|
92
|
+
builder.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
str = []
|
97
|
+
stream.each do |_timestamp, type, data|
|
98
|
+
next unless type == OUT
|
99
|
+
|
100
|
+
str << data
|
101
|
+
end
|
102
|
+
|
103
|
+
str.join
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Cased
|
6
|
+
module CLI
|
7
|
+
# Spec: https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md
|
8
|
+
module Asciinema
|
9
|
+
class Writer
|
10
|
+
VERSION = 2
|
11
|
+
|
12
|
+
attr_accessor :width
|
13
|
+
attr_accessor :height
|
14
|
+
attr_reader :stream
|
15
|
+
attr_reader :started_at
|
16
|
+
attr_reader :finished_at
|
17
|
+
|
18
|
+
def initialize(command: [], width: 80, height: 24)
|
19
|
+
@command = command
|
20
|
+
@width = width
|
21
|
+
@height = height
|
22
|
+
@stream = []
|
23
|
+
@started_at = Time.now
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<(output)
|
27
|
+
stream << [Time.now - started_at, 'o', output]
|
28
|
+
end
|
29
|
+
|
30
|
+
def time
|
31
|
+
@started_at = Time.now
|
32
|
+
ret = yield
|
33
|
+
@finished_at = Time.now
|
34
|
+
ret
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_cast
|
38
|
+
# In the event we didn't run the writer in a #time block, we should
|
39
|
+
# set the finished time if it isn't set.
|
40
|
+
@finished_at ||= Time.now
|
41
|
+
|
42
|
+
File.new(header, stream).to_cast
|
43
|
+
end
|
44
|
+
|
45
|
+
def header
|
46
|
+
{
|
47
|
+
'version' => VERSION,
|
48
|
+
'env' => {
|
49
|
+
'SHELL' => ENV['SHELL'],
|
50
|
+
'TERM' => ENV['TERM'],
|
51
|
+
},
|
52
|
+
'width' => width,
|
53
|
+
'height' => height,
|
54
|
+
}.tap do |h|
|
55
|
+
if started_at
|
56
|
+
h['timestamp'] = started_at.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
if started_at && finished_at
|
60
|
+
h['duration'] = finished_at - started_at
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Cased
|
6
|
+
module CLI
|
7
|
+
class Authentication
|
8
|
+
attr_reader :directory
|
9
|
+
attr_reader :credentials_path
|
10
|
+
attr_writer :token
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@token = Cased.config.guard_user_token
|
14
|
+
@directory = Pathname.new(File.expand_path('~/.cguard'))
|
15
|
+
@credentials_path = @directory.join('credentials')
|
16
|
+
end
|
17
|
+
|
18
|
+
def exists?
|
19
|
+
!token.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def token
|
23
|
+
@token ||= begin
|
24
|
+
credentials_path.read
|
25
|
+
rescue Errno::ENOENT
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|