aikido-zen 1.0.1.beta.5-x86_64-darwin → 1.0.2.beta.1-x86_64-darwin

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1393fa45d0bfc2d1b2e9297c8f723a722a3a2c7bc23ba9154d7970d438a7641
4
- data.tar.gz: 603014b3cac01c79a4ab4f50fbee852bfda042b860292bfb7aefb1c8002d12a4
3
+ metadata.gz: c55246b2bdb40b316fb80cf0aa1ddbedb6205c050a26b5b2f75e930d6a6cf989
4
+ data.tar.gz: 78156c513ccbadf7a7b3a8c24689d8629007bca189406fc1ea441c5c16763625
5
5
  SHA512:
6
- metadata.gz: 14bc6ccd5afb21b194fff8992999f07da8cb8689bf9f5af89b19a5a10a5db2d005294e792e6a3aab67cd5af167480fa6a702e70ed4d3c38f05cc41b157a3dc08
7
- data.tar.gz: b703d4a16f581d24e4ca981b2cdb3b9f36144f045b7ec49b4711ee3ccc501ffa4210d2e47f7960a8203f4e1ad7d2317741dc0c070cdd0365fdaa37c1cf8c9b62
6
+ metadata.gz: 216f8686d16699dabfb416fb207f31e302b2239aa9393999f499af14237156818b5c5e45bb6fa7cbf3b214336e6059b96867a303932b9669b87460b20d0514f6
7
+ data.tar.gz: 470b07194b238bb4a44c283fce7ad7679ac8fa4df119feca684bb65bb7c75729157c9e77b38fbce8bcc9629780848455aa790af9159c12a349c1e71faa41ee02
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
- ``` ruby
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
- ``` yaml
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
- ``` ruby
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
  ```
@@ -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
- attr_reader :detached_agent_socket_path
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 detached_agent_socket_path=(path)
226
- @detached_agent_socket_path = 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.detached_agent_socket_path)
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
- @detached_agent_front = FrontObject.new
7
- @drb_server = DRb.start_service(config.detached_agent_socket_path, @detached_agent_front)
15
+ @started_at = nil
8
16
 
9
- # We don't want to see drb logs unless in debug mode
10
- @drb_server.verbose = config.logger.debug?
11
- end
17
+ @config = config
12
18
 
13
- def alive?
14
- @drb_server.alive?
19
+ @socket_path = config.detached_agent_socket_path
20
+ @socket_uri = config.detached_agent_socket_uri
15
21
  end
16
22
 
17
- def stop!
18
- @drb_server.stop_service
19
- DRb.stop_service
23
+ def started?
24
+ !!@started_at
20
25
  end
21
26
 
22
- class << self
23
- def start!
24
- Aikido::Zen.config.logger.debug("Starting DRb Server...")
25
- max_attempts = 10
26
- @server = new
27
-
28
- attempts = 0
29
- until @server.alive?
30
- Aikido::Zen.config.logger.info("DRb Server still not alive. #{max_attempts - attempts} attempts remaining")
31
- sleep 0.1
32
- attempts += 1
33
- raise Aikido::Zen::DetachedAgentError.new("Impossible to start the dRB server (socket=#{Aikido::Zen.config.detached_agent_socket_path})") \
34
- if attempts == max_attempts
35
- end
36
-
37
- @server
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
@@ -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
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Aikido
4
4
  module Zen
5
- VERSION = "1.0.1.beta.5"
5
+ VERSION = "1.0.2.beta.1"
6
6
 
7
7
  # The version of libzen_internals that we build against.
8
8
  LIBZEN_VERSION = "0.1.39"
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.1.beta.5
4
+ version: 1.0.2.beta.1
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Aikido Security
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-19 00:00:00.000000000 Z
11
+ date: 2025-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby