aikido-zen 1.0.1.beta.5-x86_64-linux → 1.0.2.beta.1-x86_64-linux
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 +4 -4
- data/docs/rails.md +49 -5
- data/lib/aikido/zen/config.rb +3 -4
- data/lib/aikido/zen/detached_agent/agent.rb +1 -1
- data/lib/aikido/zen/detached_agent/server.rb +63 -26
- data/lib/aikido/zen/sinks_dsl.rb +12 -0
- data/lib/aikido/zen/version.rb +1 -1
- data/lib/aikido/zen.rb +6 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9347e04120015f5c5837d1054439b4fbdb6266ecc815d83f99a2e7d6b1024046
|
4
|
+
data.tar.gz: e14058330d68a7a6ff88de76d7f34f414906694fa0e5eda01ec261b8169f322b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a783af96d065f0b2a17c0c9bb9a25b37032056e2a2dc18e0794c7ae2dc6d8f7cefe82c03234853546bb22af777d4ceb894b2fabedd0a256ca0fbce0bba717245
|
7
|
+
data.tar.gz: 570ddc5f69df1a48b04df314b77a42450dea051dd646709672f8a33805b87ccb49039ba7ad073f0c6901eb37509372ae464ce0551ad64f4519004f9e3e88ed8a
|
data/docs/rails.md
CHANGED
@@ -2,19 +2,63 @@
|
|
2
2
|
|
3
3
|
To install Zen, add the gem:
|
4
4
|
|
5
|
-
```
|
5
|
+
```sh
|
6
6
|
bundle add aikido-zen
|
7
7
|
```
|
8
8
|
|
9
|
+
And require it before `Bundler.require` in `config/application.rb`:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# config/application.rb
|
13
|
+
require_relative "boot"
|
14
|
+
|
15
|
+
require "rails/all"
|
16
|
+
|
17
|
+
require "aikido-zen"
|
18
|
+
Aikido::Zen.protect!
|
19
|
+
|
20
|
+
# Require the gems listed in Gemfile, including any gems
|
21
|
+
# you've limited to :test, :development, or :production.
|
22
|
+
Bundler.require(*Rails.groups)
|
23
|
+
|
24
|
+
...
|
25
|
+
```
|
26
|
+
|
9
27
|
That's it! Zen will start to run inside your app when it starts getting
|
10
28
|
requests.
|
11
29
|
|
30
|
+
## Rate limiting and user blocking
|
31
|
+
|
32
|
+
If you want to add the rate limiting feature to your app, modify your code like this:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
# app/controllers/application_controller.rb
|
36
|
+
class ApplicationController < ActionController::Base
|
37
|
+
private
|
38
|
+
|
39
|
+
def current_user
|
40
|
+
return unless session[:user_id]
|
41
|
+
User.find(session[:user_id])
|
42
|
+
end
|
43
|
+
|
44
|
+
def authenticate_user!
|
45
|
+
# Your authentication logic here
|
46
|
+
# ...
|
47
|
+
# Optional, if you want to use user based rate limiting or block specific users
|
48
|
+
Aikido::Zen.set_user(
|
49
|
+
id: current_user.id,
|
50
|
+
name: current_user.name
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
12
56
|
## Configuration
|
13
57
|
|
14
58
|
Zen exposes its configuration object to the Rails configuration, which you can
|
15
59
|
modify in an initializer if desired:
|
16
60
|
|
17
|
-
```
|
61
|
+
```ruby
|
18
62
|
# config/initializers/zen.rb
|
19
63
|
Rails.application.config.zen.api_timeouts = 20
|
20
64
|
```
|
@@ -30,7 +74,7 @@ If you're using Rails' [encrypted credentials][creds], and prefer not storing
|
|
30
74
|
sensitive values in your env vars, you can easily configure Zen for it. For
|
31
75
|
example, assuming the following credentials structure:
|
32
76
|
|
33
|
-
```
|
77
|
+
```yaml
|
34
78
|
# config/credentials.yml.enc
|
35
79
|
zen:
|
36
80
|
token: "AIKIDO_RUNTIME_..."
|
@@ -38,7 +82,7 @@ zen:
|
|
38
82
|
|
39
83
|
You can just tell Zen to use it like so:
|
40
84
|
|
41
|
-
```
|
85
|
+
```ruby
|
42
86
|
# config/initializers/zen.rb
|
43
87
|
Rails.application.config.zen.token = Rails.application.credentials.zen.token
|
44
88
|
```
|
@@ -61,7 +105,7 @@ way.
|
|
61
105
|
By default, Zen will use the Rails logger, prefixing messages with `[aikido]`.
|
62
106
|
You can redirect the log to a separate stream by overriding the logger:
|
63
107
|
|
64
|
-
```
|
108
|
+
```ruby
|
65
109
|
# config/initializers/zen.rb
|
66
110
|
Rails.application.config.zen.logger = Logger.new(...)
|
67
111
|
```
|
data/lib/aikido/zen/config.rb
CHANGED
@@ -64,7 +64,7 @@ module Aikido::Zen
|
|
64
64
|
# @return [string] Path of the socket where the detached agent will listen.
|
65
65
|
# By default, is stored under the root application path with file name
|
66
66
|
# `aikido-detached-agent.sock`
|
67
|
-
|
67
|
+
attr_accessor :detached_agent_socket_path
|
68
68
|
|
69
69
|
# @return [Boolean] is the agent in debugging mode?
|
70
70
|
attr_accessor :debugging
|
@@ -222,9 +222,8 @@ module Aikido::Zen
|
|
222
222
|
@api_timeouts.update(value)
|
223
223
|
end
|
224
224
|
|
225
|
-
def
|
226
|
-
@detached_agent_socket_path
|
227
|
-
@detached_agent_socket_path = "drbunix:" + @detached_agent_socket_path unless @detached_agent_socket_path.start_with?("drbunix:")
|
225
|
+
def detached_agent_socket_uri
|
226
|
+
"drbunix:" + @detached_agent_socket_path
|
228
227
|
end
|
229
228
|
|
230
229
|
private
|
@@ -32,7 +32,7 @@ module Aikido::Zen::DetachedAgent
|
|
32
32
|
@polling_interval = polling_interval
|
33
33
|
@worker = worker
|
34
34
|
@collector = collector
|
35
|
-
@detached_agent_front = DRbObject.new_with_uri(config.
|
35
|
+
@detached_agent_front = DRbObject.new_with_uri(config.detached_agent_socket_uri)
|
36
36
|
@has_forked = false
|
37
37
|
schedule_tasks
|
38
38
|
end
|
@@ -1,41 +1,78 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fileutils"
|
4
|
+
|
3
5
|
module Aikido::Zen::DetachedAgent
|
4
6
|
class Server
|
7
|
+
# Initialize and start a detached agent server instance.
|
8
|
+
#
|
9
|
+
# @return [Aikido::Zen::DetachedAgent::Server]
|
10
|
+
def self.start(**opts)
|
11
|
+
new(**opts).tap(&:start!)
|
12
|
+
end
|
13
|
+
|
5
14
|
def initialize(config: Aikido::Zen.config)
|
6
|
-
@
|
7
|
-
@drb_server = DRb.start_service(config.detached_agent_socket_path, @detached_agent_front)
|
15
|
+
@started_at = nil
|
8
16
|
|
9
|
-
|
10
|
-
@drb_server.verbose = config.logger.debug?
|
11
|
-
end
|
17
|
+
@config = config
|
12
18
|
|
13
|
-
|
14
|
-
@
|
19
|
+
@socket_path = config.detached_agent_socket_path
|
20
|
+
@socket_uri = config.detached_agent_socket_uri
|
15
21
|
end
|
16
22
|
|
17
|
-
def
|
18
|
-
|
19
|
-
DRb.stop_service
|
23
|
+
def started?
|
24
|
+
!!@started_at
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
27
|
+
def start!
|
28
|
+
@config.logger.info("Starting DRb Server...")
|
29
|
+
|
30
|
+
# Try to ensure that the DRb service can start if the DRb service did
|
31
|
+
# not stop cleanly.
|
32
|
+
begin
|
33
|
+
# Check whether the Unix domain socket is in use by another process.
|
34
|
+
UNIXSocket.new(@socket_path).close
|
35
|
+
rescue Errno::ECONNREFUSED
|
36
|
+
@config.logger.debug("Removing residual Unix domain socket...")
|
37
|
+
|
38
|
+
# Remove the residual Unix domain socket.
|
39
|
+
FileUtils.rm_f(@socket_path)
|
40
|
+
rescue
|
41
|
+
# empty
|
42
|
+
end
|
43
|
+
|
44
|
+
@front = FrontObject.new
|
45
|
+
|
46
|
+
# If the Unix domain socket is in use by another process and/or the
|
47
|
+
# residual Unix domain socket could not be removed DRb will raise an
|
48
|
+
# appropriate error.
|
49
|
+
@drb_server = DRb.start_service(@socket_uri, @front)
|
50
|
+
|
51
|
+
# Only show DRb output in debug mode.
|
52
|
+
@drb_server.verbose = @config.logger.debug?
|
53
|
+
|
54
|
+
# Ensure that the DRb server is alive.
|
55
|
+
max_attempts = 10
|
56
|
+
attempts = 0
|
57
|
+
until @drb_server.alive?
|
58
|
+
@config.logger.info("DRb Server still not alive. #{max_attempts - attempts} attempts remaining")
|
59
|
+
sleep 0.1
|
60
|
+
attempts += 1
|
61
|
+
raise Aikido::Zen::DetachedAgentError.new("Impossible to start the dRB server (socket=#{Aikido::Zen.config.detached_agent_socket_path})") \
|
62
|
+
if attempts == max_attempts
|
38
63
|
end
|
64
|
+
|
65
|
+
@started_at = Time.now.utc
|
66
|
+
|
67
|
+
at_exit { stop! if started? }
|
68
|
+
end
|
69
|
+
|
70
|
+
def stop!
|
71
|
+
@config.logger.info("Stopping DRb Server...")
|
72
|
+
@started_at = nil
|
73
|
+
|
74
|
+
@drb_server.stop_service if @drb_server.alive?
|
75
|
+
DRb.stop_service
|
39
76
|
end
|
40
77
|
end
|
41
78
|
end
|
data/lib/aikido/zen/sinks_dsl.rb
CHANGED
@@ -109,6 +109,8 @@ module Aikido::Zen
|
|
109
109
|
#
|
110
110
|
# @return [void]
|
111
111
|
def presafe_sink_before(method_name, &block)
|
112
|
+
raise ArgumentError, "block required" unless block
|
113
|
+
|
112
114
|
original = instance_method(method_name)
|
113
115
|
|
114
116
|
define_method(method_name) do |*args, **kwargs, &blk|
|
@@ -131,6 +133,8 @@ module Aikido::Zen
|
|
131
133
|
#
|
132
134
|
# @note the block is executed within `safe` to handle errors safely; the original method is executed outside of `safe` to preserve the original behavior
|
133
135
|
def sink_before(method_name, &block)
|
136
|
+
raise ArgumentError, "block required" unless block
|
137
|
+
|
134
138
|
presafe_sink_before(method_name) do |*args, **kwargs|
|
135
139
|
DSL.safe do
|
136
140
|
instance_exec(*args, **kwargs, &block)
|
@@ -149,6 +153,8 @@ module Aikido::Zen
|
|
149
153
|
#
|
150
154
|
# @return [void]
|
151
155
|
def presafe_sink_after(method_name, &block)
|
156
|
+
raise ArgumentError, "block required" unless block
|
157
|
+
|
152
158
|
original = instance_method(method_name)
|
153
159
|
|
154
160
|
define_method(method_name) do |*args, **kwargs, &blk|
|
@@ -173,6 +179,8 @@ module Aikido::Zen
|
|
173
179
|
#
|
174
180
|
# @note the block is executed within `safe` to handle errors safely; the original method is executed outside of `safe` to preserve the original behavior
|
175
181
|
def sink_after(method_name, &block)
|
182
|
+
raise ArgumentError, "block required" unless block
|
183
|
+
|
176
184
|
presafe_sink_after(method_name) do |result, *args, **kwargs|
|
177
185
|
DSL.safe do
|
178
186
|
instance_exec(result, *args, **kwargs, &block)
|
@@ -191,6 +199,8 @@ module Aikido::Zen
|
|
191
199
|
#
|
192
200
|
# @return [void]
|
193
201
|
def presafe_sink_around(method_name, &block)
|
202
|
+
raise ArgumentError, "block required" unless block
|
203
|
+
|
194
204
|
original = instance_method(method_name)
|
195
205
|
|
196
206
|
define_method(method_name) do |*args, **kwargs, &blk|
|
@@ -219,6 +229,8 @@ module Aikido::Zen
|
|
219
229
|
# @note the block is executed within `safe` to handle errors safely; the original method is executed within `presafe` to preserve the original behavior
|
220
230
|
# @note if the block does not call `original_call`, the original method is called automatically after the block is executed
|
221
231
|
def sink_around(method_name, &block)
|
232
|
+
raise ArgumentError, "block required" unless block
|
233
|
+
|
222
234
|
presafe_sink_around(method_name) do |presafe_original_call, *args, **kwargs|
|
223
235
|
original_called = false
|
224
236
|
original_call = proc do
|
data/lib/aikido/zen/version.rb
CHANGED
data/lib/aikido/zen.rb
CHANGED
@@ -165,6 +165,11 @@ module Aikido
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
+
# Align with other Zen implementations, while keeping internal consistency.
|
169
|
+
class << self
|
170
|
+
alias_method :set_user, :track_user
|
171
|
+
end
|
172
|
+
|
168
173
|
# Marks that the Zen middleware was installed properly
|
169
174
|
# @return void
|
170
175
|
def self.middleware_installed!
|
@@ -209,7 +214,7 @@ module Aikido
|
|
209
214
|
end
|
210
215
|
|
211
216
|
def self.detached_agent_server
|
212
|
-
@detached_agent_server ||= DetachedAgent::Server.start
|
217
|
+
@detached_agent_server ||= DetachedAgent::Server.start
|
213
218
|
end
|
214
219
|
|
215
220
|
class << self
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aikido-zen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2.beta.1
|
5
5
|
platform: x86_64-linux
|
6
6
|
authors:
|
7
7
|
- Aikido Security
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|