aikido-zen 0.2.0-x86_64-darwin → 1.0.1.beta.2-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 +4 -4
- data/.aikido +6 -0
- data/.simplecov +6 -0
- data/README.md +67 -83
- data/benchmarks/README.md +8 -12
- data/docs/rails.md +1 -1
- data/lib/aikido/zen/agent.rb +10 -8
- data/lib/aikido/zen/api_client.rb +14 -4
- data/lib/aikido/zen/background_worker.rb +52 -0
- data/lib/aikido/zen/collector.rb +12 -1
- data/lib/aikido/zen/config.rb +20 -0
- data/lib/aikido/zen/context.rb +4 -0
- data/lib/aikido/zen/detached_agent/agent.rb +78 -0
- data/lib/aikido/zen/detached_agent/front_object.rb +37 -0
- data/lib/aikido/zen/detached_agent/server.rb +41 -0
- data/lib/aikido/zen/detached_agent.rb +2 -0
- data/lib/aikido/zen/errors.rb +8 -0
- data/lib/aikido/zen/internals.rb +41 -7
- data/lib/aikido/zen/libzen-v0.1.39-x86_64-darwin.dylib +0 -0
- data/lib/aikido/zen/middleware/rack_throttler.rb +9 -3
- data/lib/aikido/zen/middleware/request_tracker.rb +6 -4
- data/lib/aikido/zen/outbound_connection_monitor.rb +4 -0
- data/lib/aikido/zen/rails_engine.rb +8 -8
- data/lib/aikido/zen/rate_limiter/breaker.rb +3 -3
- data/lib/aikido/zen/rate_limiter.rb +6 -11
- data/lib/aikido/zen/request/heuristic_router.rb +6 -0
- data/lib/aikido/zen/request/rails_router.rb +6 -18
- data/lib/aikido/zen/request/schema/auth_schemas.rb +14 -0
- data/lib/aikido/zen/request/schema.rb +18 -0
- data/lib/aikido/zen/runtime_settings.rb +2 -2
- data/lib/aikido/zen/scanners/path_traversal_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/shell_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/sql_injection_scanner.rb +4 -2
- data/lib/aikido/zen/scanners/ssrf/private_ip_checker.rb +33 -21
- data/lib/aikido/zen/scanners/ssrf_scanner.rb +6 -1
- data/lib/aikido/zen/scanners/stored_ssrf_scanner.rb +6 -0
- data/lib/aikido/zen/sink.rb +11 -1
- data/lib/aikido/zen/sinks/action_controller.rb +9 -4
- data/lib/aikido/zen/sinks/async_http.rb +35 -16
- data/lib/aikido/zen/sinks/curb.rb +52 -26
- data/lib/aikido/zen/sinks/em_http.rb +39 -25
- data/lib/aikido/zen/sinks/excon.rb +63 -45
- data/lib/aikido/zen/sinks/file.rb +67 -71
- data/lib/aikido/zen/sinks/http.rb +38 -19
- data/lib/aikido/zen/sinks/httpclient.rb +51 -22
- data/lib/aikido/zen/sinks/httpx.rb +37 -18
- data/lib/aikido/zen/sinks/kernel.rb +18 -57
- data/lib/aikido/zen/sinks/mysql2.rb +19 -7
- data/lib/aikido/zen/sinks/net_http.rb +37 -19
- data/lib/aikido/zen/sinks/patron.rb +41 -24
- data/lib/aikido/zen/sinks/pg.rb +50 -27
- data/lib/aikido/zen/sinks/resolv.rb +37 -16
- data/lib/aikido/zen/sinks/socket.rb +46 -17
- data/lib/aikido/zen/sinks/sqlite3.rb +31 -12
- data/lib/aikido/zen/sinks/trilogy.rb +19 -7
- data/lib/aikido/zen/sinks.rb +29 -20
- data/lib/aikido/zen/sinks_dsl.rb +226 -0
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen/worker.rb +5 -0
- data/lib/aikido/zen.rb +59 -9
- data/placeholder/.gitignore +4 -0
- data/placeholder/README.md +11 -0
- data/placeholder/Rakefile +75 -0
- data/placeholder/lib/placeholder.rb.template +3 -0
- data/placeholder/placeholder.gemspec.template +20 -0
- data/tasklib/bench.rake +29 -6
- data/tasklib/libzen.rake +70 -66
- data/tasklib/wrk.rb +88 -0
- metadata +23 -13
- data/CHANGELOG.md +0 -25
- data/lib/aikido/zen/libzen-v0.1.37.x86_64.dylib +0 -0
- data/lib/aikido.rb +0 -3
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aikido::Zen
|
4
|
+
module Sinks
|
5
|
+
module DSL
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# In the context of `Aikido::Zen::Sinks::DSL`, the terms safe and presafe
|
9
|
+
# are defined as follows:
|
10
|
+
#
|
11
|
+
# safe: the desired state for a sink, particularly with respect to rescue.
|
12
|
+
#
|
13
|
+
# A sink is considered safe when unintended errors in the sink are handled,
|
14
|
+
# and-so are prevented from disrupting the operation of the original method
|
15
|
+
# (by raising unintended errors).
|
16
|
+
#
|
17
|
+
# presafe: the default state of a sink, particularly with respect to rescue.
|
18
|
+
#
|
19
|
+
# A sink is in the presafe state before and while unintended errors in the
|
20
|
+
# sink are not handled.
|
21
|
+
#
|
22
|
+
# Sink methods (like all methods) are in the presafe state when defined and
|
23
|
+
# become safe when unexpected errors cannot cause harm. The `safe` method
|
24
|
+
# is used to establish a safe state for the duration of the block executed.
|
25
|
+
# It is sometimes useful to be able to reestablish the presafe safe while
|
26
|
+
# inside a `safe` block; the `presafe` method allows this.
|
27
|
+
#
|
28
|
+
# Methods that contain the term presafe in their name should be used with
|
29
|
+
# appropriate care and understanding.
|
30
|
+
#
|
31
|
+
# IMPORTANT: All sinks should be safe!
|
32
|
+
#
|
33
|
+
# While this DSL proves useful for defining safe sink methods that follow
|
34
|
+
# common patterns, there are exceptions. It is always possible to define
|
35
|
+
# sink methods without using this DSL, but this should only be done when
|
36
|
+
# absolutely necessary. The sink methods defined using this DSL are safe,
|
37
|
+
# unless explicitly declared presafe.
|
38
|
+
#
|
39
|
+
# IMPORTANT: No sinks should be presafe in production!
|
40
|
+
#
|
41
|
+
# We are all responsible for ensuring that the sinks we implement are safe
|
42
|
+
# for production use. This DSL is only here to assist, by taking care of
|
43
|
+
# delicate edge cases and reducing the space for errors.
|
44
|
+
#
|
45
|
+
# When writing sink methods manually, some principles should be considered,
|
46
|
+
# to ensure safety for production:
|
47
|
+
#
|
48
|
+
# 1. Sink methods should ensure that the original method is always called,
|
49
|
+
# passing all parameters (positional, keyword, and block) exactly as they
|
50
|
+
# were passed to the original method, and return the result returned by
|
51
|
+
# the original method exactly as it was returned by the original method.
|
52
|
+
# (Unless intervention is required.)
|
53
|
+
#
|
54
|
+
# 2. Sink methods should not predict the signature of the original method,
|
55
|
+
# and-so restrict it from varying. The original method implementation is
|
56
|
+
# the sole and ultimate reference for its own behavior. We are observers
|
57
|
+
# (unless intervention is required).
|
58
|
+
#
|
59
|
+
# 3. Unexpected errors that are encountered in sink methods should not be
|
60
|
+
# capable of interfering with or preventing the normal operation of the
|
61
|
+
# original method. This includes but is not limited to exceptions that
|
62
|
+
# that may be raised when the sink method is called. Safe sink methods
|
63
|
+
# should return control to their caller (unless intervention is required).
|
64
|
+
#
|
65
|
+
# These are the guidelines adhered to by the `Aikido::Zen::Sinks::DSL`.
|
66
|
+
|
67
|
+
# The error with an original error as its cause to re-raise in `safe`.
|
68
|
+
class PresafeError < StandardError
|
69
|
+
end
|
70
|
+
|
71
|
+
# Safely execute the given block
|
72
|
+
#
|
73
|
+
# All standard errors are suppressed except `Aikido::Zen::UnderAttackError`s.
|
74
|
+
# This ensures that unexpected errors do not interrupt the execution of the
|
75
|
+
# original method, while all detected attacks are raised.
|
76
|
+
#
|
77
|
+
# When an error is wrapped in `PresafeError` the original error is reraised.
|
78
|
+
#
|
79
|
+
# @yield the block to execute
|
80
|
+
def safe
|
81
|
+
yield
|
82
|
+
rescue Aikido::Zen::UnderAttackError
|
83
|
+
raise
|
84
|
+
rescue PresafeError => err
|
85
|
+
raise err.cause
|
86
|
+
rescue => err
|
87
|
+
Aikido::Zen.config.logger.debug("[safe] #{err.class}: #{err.message}")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Presafely execute the given block
|
91
|
+
#
|
92
|
+
# Safely wrap standard errors in `PresafeError` so that the original error is
|
93
|
+
# reraised when rescued in `safe`.
|
94
|
+
#
|
95
|
+
# @yield the block to execute
|
96
|
+
def presafe
|
97
|
+
yield
|
98
|
+
rescue => err
|
99
|
+
raise PresafeError, cause: err
|
100
|
+
end
|
101
|
+
|
102
|
+
# Define a method `method_name` that presafely executes the given block before
|
103
|
+
# the original method.
|
104
|
+
#
|
105
|
+
# @param method_name [Symbol, String] the name of the method to define
|
106
|
+
# @yield the block to execute before the original method
|
107
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
108
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
109
|
+
#
|
110
|
+
# @return [void]
|
111
|
+
def presafe_sink_before(method_name, &block)
|
112
|
+
define_method(method_name) do |*args, **kwargs, &blk|
|
113
|
+
instance_exec(*args, **kwargs, &block)
|
114
|
+
super(*args, **kwargs, &blk)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Define a method `method_name` that safely executes the given block before
|
119
|
+
# the original method.
|
120
|
+
#
|
121
|
+
# @param method_name [Symbol, String] the name of the method to define
|
122
|
+
# @yield the block to execute before the original method
|
123
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
124
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
125
|
+
#
|
126
|
+
# @return [void]
|
127
|
+
#
|
128
|
+
# @note the block is executed within `safe` to handle errors safely; the original method is executed outside of `safe` to preserve the original behavior
|
129
|
+
def sink_before(method_name, &block)
|
130
|
+
presafe_sink_before(method_name) do |*args, **kwargs|
|
131
|
+
DSL.safe do
|
132
|
+
instance_exec(*args, **kwargs, &block)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Define a method `method_name` that presafely executes the given block after
|
138
|
+
# the original method.
|
139
|
+
#
|
140
|
+
# @param method_name [Symbol, String] the name of the method to define
|
141
|
+
# @yield the block to execute after the original method
|
142
|
+
# @yieldparam result [Object] the result returned by the original method
|
143
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
144
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
145
|
+
#
|
146
|
+
# @return [void]
|
147
|
+
def presafe_sink_after(method_name, &block)
|
148
|
+
define_method(method_name) do |*args, **kwargs, &blk|
|
149
|
+
result = super(*args, **kwargs, &blk)
|
150
|
+
instance_exec(result, *args, **kwargs, &block)
|
151
|
+
result
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Define a method `method_name` that safely executes the given block after
|
156
|
+
# the original method.
|
157
|
+
#
|
158
|
+
# @param method_name [Symbol, String] the name of the method to define
|
159
|
+
# @yield the block to execute after the original method
|
160
|
+
# @yieldparam result [Object] the result returned by the original method
|
161
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
162
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
163
|
+
#
|
164
|
+
# @return [void]
|
165
|
+
#
|
166
|
+
# @note the block is executed within `safe` to handle errors safely; the original method is executed outside of `safe` to preserve the original behavior
|
167
|
+
def sink_after(method_name, &block)
|
168
|
+
presafe_sink_after(method_name) do |result, *args, **kwargs|
|
169
|
+
DSL.safe do
|
170
|
+
instance_exec(result, *args, **kwargs, &block)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Define a method `method_name` that presafely executes the given block around
|
176
|
+
# the original method.
|
177
|
+
#
|
178
|
+
# @param method_name [Symbol, String] the name of the method to define
|
179
|
+
# @yield the block to execute around the original method
|
180
|
+
# @yieldparam super_call [Proc] the proc that calls the original method
|
181
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
182
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
183
|
+
#
|
184
|
+
# @return [void]
|
185
|
+
def presafe_sink_around(method_name, &block)
|
186
|
+
define_method(method_name) do |*args, **kwargs, &blk|
|
187
|
+
result = nil
|
188
|
+
super_call = proc do
|
189
|
+
result = super(*args, **kwargs, &blk)
|
190
|
+
end
|
191
|
+
instance_exec(super_call, *args, **kwargs, &block)
|
192
|
+
result
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Define a method `method_name` that safely executes the given block around
|
197
|
+
# the original method.
|
198
|
+
#
|
199
|
+
# @param method_name [Symbol, String] the name of the method to define
|
200
|
+
# @yield the block to execute around the original method
|
201
|
+
# @yieldparam super_call [Proc] the proc that calls the original method
|
202
|
+
# @yieldparam args [Array] the positional arguments passed to the original method
|
203
|
+
# @yieldparam kwargs [Hash] the keyword arguments passed to the original method
|
204
|
+
#
|
205
|
+
# @return [void]
|
206
|
+
#
|
207
|
+
# @note the block is executed within `safe` to handle errors safely; the original method is executed within `presafe` to preserve the original behavior
|
208
|
+
# @note if the block does not call `super_call`, the original method is called automatically after the block is executed
|
209
|
+
def sink_around(method_name, &block)
|
210
|
+
presafe_sink_around(method_name) do |presafe_super_call, *args, **kwargs|
|
211
|
+
super_called = false
|
212
|
+
super_call = proc do
|
213
|
+
super_called = true
|
214
|
+
DSL.presafe do
|
215
|
+
presafe_super_call.call
|
216
|
+
end
|
217
|
+
end
|
218
|
+
DSL.safe do
|
219
|
+
instance_exec(super_call, *args, **kwargs, &block)
|
220
|
+
end
|
221
|
+
presafe_super_call.call unless super_called
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/aikido/zen/version.rb
CHANGED
data/lib/aikido/zen/worker.rb
CHANGED
data/lib/aikido/zen.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# IMPORTANT: Any files that load sinks or start the Aikido Agent should
|
4
|
+
# be required in `Aikido::Zen.protect!`.
|
5
|
+
|
3
6
|
require_relative "zen/version"
|
4
7
|
require_relative "zen/errors"
|
5
8
|
require_relative "zen/actor"
|
@@ -10,6 +13,7 @@ require_relative "zen/worker"
|
|
10
13
|
require_relative "zen/agent"
|
11
14
|
require_relative "zen/api_client"
|
12
15
|
require_relative "zen/context"
|
16
|
+
require_relative "zen/detached_agent"
|
13
17
|
require_relative "zen/middleware/check_allowed_addresses"
|
14
18
|
require_relative "zen/middleware/middleware"
|
15
19
|
require_relative "zen/middleware/request_tracker"
|
@@ -19,10 +23,24 @@ require_relative "zen/outbound_connection_monitor"
|
|
19
23
|
require_relative "zen/runtime_settings"
|
20
24
|
require_relative "zen/rate_limiter"
|
21
25
|
require_relative "zen/scanners"
|
22
|
-
require_relative "zen/rails_engine" if defined?(::Rails)
|
23
26
|
|
24
27
|
module Aikido
|
25
28
|
module Zen
|
29
|
+
# Enable protection. Until this method is called no sinks are loaded
|
30
|
+
# and the Aikido Agent does not start.
|
31
|
+
#
|
32
|
+
# @return [void]
|
33
|
+
def self.protect!
|
34
|
+
if config.disabled?
|
35
|
+
config.logger.warn("Zen has been disabled and will not run.")
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
# IMPORTANT: Any files that load sinks or start the Aikido Agent
|
40
|
+
# should be required here only.
|
41
|
+
require_relative "zen/rails_engine" if defined?(::Rails)
|
42
|
+
end
|
43
|
+
|
26
44
|
# @return [Aikido::Zen::Config] the agent configuration.
|
27
45
|
def self.config
|
28
46
|
@config ||= Config.new
|
@@ -34,6 +52,10 @@ module Aikido
|
|
34
52
|
@runtime_settings ||= RuntimeSettings.new
|
35
53
|
end
|
36
54
|
|
55
|
+
def self.runtime_settings=(settings)
|
56
|
+
@runtime_settings = settings
|
57
|
+
end
|
58
|
+
|
37
59
|
# Gets information about the current system configuration, which is sent to
|
38
60
|
# the server along with any events.
|
39
61
|
def self.system_info
|
@@ -43,9 +65,15 @@ module Aikido
|
|
43
65
|
# Manages runtime metrics extracted from your app, which are uploaded to the
|
44
66
|
# Aikido servers if configured to do so.
|
45
67
|
def self.collector
|
68
|
+
check_and_handle_fork
|
46
69
|
@collector ||= Collector.new
|
47
70
|
end
|
48
71
|
|
72
|
+
def self.detached_agent
|
73
|
+
check_and_handle_fork
|
74
|
+
@detached_agent ||= DetachedAgent::Agent.new
|
75
|
+
end
|
76
|
+
|
49
77
|
# Gets the current context object that holds all information about the
|
50
78
|
# current request.
|
51
79
|
#
|
@@ -68,12 +96,10 @@ module Aikido
|
|
68
96
|
# @param request [Aikido::Zen::Request]
|
69
97
|
# @return [void]
|
70
98
|
def self.track_request(request)
|
71
|
-
|
72
|
-
collector.track_request(request)
|
99
|
+
collector.track_request
|
73
100
|
end
|
74
101
|
|
75
102
|
def self.track_discovered_route(request)
|
76
|
-
autostart
|
77
103
|
collector.track_route(request)
|
78
104
|
end
|
79
105
|
|
@@ -82,7 +108,6 @@ module Aikido
|
|
82
108
|
# @param connection [Aikido::Zen::OutboundConnection]
|
83
109
|
# @return [void]
|
84
110
|
def self.track_outbound(connection)
|
85
|
-
autostart
|
86
111
|
collector.track_outbound(connection)
|
87
112
|
end
|
88
113
|
|
@@ -94,7 +119,6 @@ module Aikido
|
|
94
119
|
# @raise [Aikido::Zen::UnderAttackError] if the scan detected an Attack
|
95
120
|
# and blocking_mode is enabled.
|
96
121
|
def self.track_scan(scan)
|
97
|
-
autostart
|
98
122
|
collector.track_scan(scan)
|
99
123
|
agent.handle_attack(scan.attack) if scan.attack?
|
100
124
|
end
|
@@ -107,7 +131,6 @@ module Aikido
|
|
107
131
|
return if config.disabled?
|
108
132
|
|
109
133
|
if (actor = Aikido::Zen::Actor(user))
|
110
|
-
autostart
|
111
134
|
collector.track_user(actor)
|
112
135
|
current_context.request.actor = actor if current_context
|
113
136
|
else
|
@@ -140,7 +163,8 @@ module Aikido
|
|
140
163
|
# @!visibility private
|
141
164
|
# Stop any background threads.
|
142
165
|
def self.stop!
|
143
|
-
agent&.stop!
|
166
|
+
@agent&.stop!
|
167
|
+
@detached_agent_server&.stop!
|
144
168
|
end
|
145
169
|
|
146
170
|
# @!visibility private
|
@@ -149,8 +173,34 @@ module Aikido
|
|
149
173
|
@agent ||= Agent.start
|
150
174
|
end
|
151
175
|
|
176
|
+
def self.detached_agent_server
|
177
|
+
@detached_agent_server ||= DetachedAgent::Server.start!
|
178
|
+
end
|
179
|
+
|
152
180
|
class << self
|
153
|
-
|
181
|
+
# `agent` and `detached_agent` are started on the first method call.
|
182
|
+
# A mutex controls thread execution to prevent multiple attempts.
|
183
|
+
LOCK = Mutex.new
|
184
|
+
|
185
|
+
def start!
|
186
|
+
@pid = Process.pid
|
187
|
+
LOCK.synchronize do
|
188
|
+
agent
|
189
|
+
detached_agent_server
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def check_and_handle_fork
|
194
|
+
if has_forked
|
195
|
+
@detached_agent&.handle_fork
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def has_forked
|
200
|
+
pid_changed = Process.pid != @pid
|
201
|
+
@pid = Process.pid
|
202
|
+
pid_changed
|
203
|
+
end
|
154
204
|
end
|
155
205
|
end
|
156
206
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Security Placeholder
|
2
|
+
|
3
|
+
This gem has been published by [Aikido Security](https://aikido.dev) to help prevent supply chain attacks and protect the integrity of the Ruby ecosystem.
|
4
|
+
|
5
|
+
It is **not intended for direct use** and contains no functional code.
|
6
|
+
|
7
|
+
If you are looking for the actual library, please use [`aikido-zen`](https://rubygems.org/gems/aikido-zen).
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
This package exists solely for security purposes. For more information, visit [aikido.dev](https://aikido.dev).
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rake"
|
4
|
+
require "rake/clean"
|
5
|
+
require "rubygems/package"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
GEM_NAMES = %w[aikido]
|
9
|
+
|
10
|
+
# Clean up created files
|
11
|
+
CLEAN.include("LICENSE")
|
12
|
+
CLEAN.include(*GEM_NAMES.map { |name| "#{name}.gemspec" })
|
13
|
+
CLEAN.include(*GEM_NAMES.map { |name| "lib/#{name}.rb" })
|
14
|
+
CLOBBER.include(*GEM_NAMES.map { |name| "#{name}-*.gem" })
|
15
|
+
|
16
|
+
namespace :build do
|
17
|
+
GEM_NAMES.each do |gem_name|
|
18
|
+
file "LICENSE" => ["../LICENSE"] do
|
19
|
+
FileUtils.cp("../LICENSE", "LICENSE")
|
20
|
+
puts "Copied LICENSE"
|
21
|
+
end
|
22
|
+
|
23
|
+
entry_point_path = "lib/#{gem_name}.rb"
|
24
|
+
|
25
|
+
# Generate the entry point file from template if needed
|
26
|
+
file entry_point_path => ["lib/placeholder.rb.template"] do
|
27
|
+
template = File.read("lib/placeholder.rb.template")
|
28
|
+
content = template.gsub("@GEM_NAME", gem_name)
|
29
|
+
File.write(entry_point_path, content)
|
30
|
+
puts "Generated #{entry_point_path}"
|
31
|
+
end
|
32
|
+
|
33
|
+
gemspec_path = "#{gem_name}.gemspec"
|
34
|
+
|
35
|
+
# Generate gemspec file from template if needed
|
36
|
+
file gemspec_path => ["placeholder.gemspec.template"] do
|
37
|
+
template = File.read("placeholder.gemspec.template")
|
38
|
+
content = template.gsub("@GEM_NAME", gem_name)
|
39
|
+
File.write(gemspec_path, content)
|
40
|
+
puts "Generated #{gemspec_path}"
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Build the #{gem_name} gem"
|
44
|
+
task gem_name => [entry_point_path, gemspec_path, "LICENSE"] do
|
45
|
+
gemspec = Gem::Specification.load(gemspec_path)
|
46
|
+
raise "Failed to load gemspec: #{gemspec_path}" unless gemspec
|
47
|
+
|
48
|
+
gem_path = Gem::Package.build(gemspec)
|
49
|
+
puts "Built #{gem_path}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Build all gems"
|
54
|
+
task all: GEM_NAMES.map { |gem_name| "build:#{gem_name}" }
|
55
|
+
end
|
56
|
+
|
57
|
+
namespace :release do
|
58
|
+
GEM_NAMES.each do |gem_name|
|
59
|
+
gemspec_path = "#{gem_name}.gemspec"
|
60
|
+
|
61
|
+
desc "Build and publish the #{gem_name} to RubyGems"
|
62
|
+
task gem_name => ["build:#{gem_name}"] do
|
63
|
+
gemspec = Gem::Specification.load(gemspec_path)
|
64
|
+
raise "Failed to load gemspec: #{gemspec_path}" unless gemspec
|
65
|
+
|
66
|
+
gem_path = "#{gemspec.name}-#{gemspec.version}.gem"
|
67
|
+
|
68
|
+
puts "Publishing #{gem_path} to RubyGem..."
|
69
|
+
sh "gem push #{gem_path}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "Build and publish all gems to RubyGems"
|
74
|
+
task all: GEM_NAMES.map { |gem_name| "release:#{gem_name}" }
|
75
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "@GEM_NAME"
|
5
|
+
spec.version = "0.0.2"
|
6
|
+
spec.authors = ["Aikido Security"]
|
7
|
+
spec.email = ["dev-admin@aikido.dev"]
|
8
|
+
spec.summary = "Security placeholder for 'aikido-zen'."
|
9
|
+
spec.description = "This gem has been published by Aikido Security to help prevent supply chain attacks. It is not intended for direct use. Please use 'aikido-zen' instead."
|
10
|
+
spec.homepage = "https://aikido.dev/zen"
|
11
|
+
spec.license = "AGPL-3.0-or-later"
|
12
|
+
|
13
|
+
spec.required_ruby_version = ">= 2.3"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/aikidosec/firewall-ruby"
|
17
|
+
|
18
|
+
spec.files = ["lib/@GEM_NAME.rb", "README.md", "LICENSE"]
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
end
|
data/tasklib/bench.rake
CHANGED
@@ -2,8 +2,11 @@
|
|
2
2
|
|
3
3
|
require "socket"
|
4
4
|
require "timeout"
|
5
|
+
require_relative "wrk"
|
5
6
|
|
6
7
|
SERVER_PIDS = {}
|
8
|
+
PORT_PROTECTED = 3001
|
9
|
+
PORT_UNPROTECTED = 3002
|
7
10
|
|
8
11
|
def stop_servers
|
9
12
|
SERVER_PIDS.each { |_, pid| Process.kill("TERM", pid) }
|
@@ -11,6 +14,8 @@ def stop_servers
|
|
11
14
|
end
|
12
15
|
|
13
16
|
def boot_server(dir, port:, env: {})
|
17
|
+
env["RAILS_MIN_THREADS"] = NUMBER_OF_THREADS
|
18
|
+
env["RAILS_MAX_THREADS"] = NUMBER_OF_THREADS
|
14
19
|
env["PORT"] = port.to_s
|
15
20
|
env["SECRET_KEY_BASE"] = rand(36**64).to_s(36)
|
16
21
|
|
@@ -49,8 +54,28 @@ end
|
|
49
54
|
Pathname.glob("sample_apps/*").select(&:directory?).each do |dir|
|
50
55
|
namespace :bench do
|
51
56
|
namespace dir.basename.to_s do
|
52
|
-
desc "Run benchmarks for the #{dir.basename} sample app"
|
53
|
-
task
|
57
|
+
desc "Run WRK benchmarks for the #{dir.basename} sample app"
|
58
|
+
task wrk_run: [:boot_protected_app, :boot_unprotected_app] do
|
59
|
+
throughput_decrease_limit_perc = 25
|
60
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0.0") && Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.1.0")
|
61
|
+
# add higher limit for ruby 3.0
|
62
|
+
throughput_decrease_limit_perc = 35
|
63
|
+
end
|
64
|
+
|
65
|
+
wait_for_servers
|
66
|
+
run_benchmark(
|
67
|
+
route_zen: "http://localhost:#{PORT_PROTECTED}/benchmark", # Application with Zen
|
68
|
+
route_no_zen: "http://localhost:#{PORT_UNPROTECTED}/benchmark", # Application without Zen
|
69
|
+
description: "An empty route (1ms simulated delay)",
|
70
|
+
throughput_decrease_limit_perc: throughput_decrease_limit_perc,
|
71
|
+
latency_increase_limit_ms: 200
|
72
|
+
)
|
73
|
+
ensure
|
74
|
+
stop_servers
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "Run K6 benchmarks for the #{dir.basename} sample app"
|
78
|
+
task k6_run: [:boot_protected_app, :boot_unprotected_app] do
|
54
79
|
wait_for_servers
|
55
80
|
Dir.chdir("benchmarks") { sh "k6 run #{dir.basename}.js" }
|
56
81
|
ensure
|
@@ -58,14 +83,12 @@ Pathname.glob("sample_apps/*").select(&:directory?).each do |dir|
|
|
58
83
|
end
|
59
84
|
|
60
85
|
task :boot_protected_app do
|
61
|
-
boot_server(dir, port:
|
86
|
+
boot_server(dir, port: PORT_PROTECTED)
|
62
87
|
end
|
63
88
|
|
64
89
|
task :boot_unprotected_app do
|
65
|
-
boot_server(dir, port:
|
90
|
+
boot_server(dir, port: PORT_UNPROTECTED, env: {"AIKIDO_DISABLED" => "true"})
|
66
91
|
end
|
67
92
|
end
|
68
|
-
|
69
|
-
task default: "#{dir.basename}:run"
|
70
93
|
end
|
71
94
|
end
|