aikido-zen 1.0.1.beta.2-x86_64-linux → 1.0.1.beta.4-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca6248278bdeadfe41309e32cc275d6d160f5a5016d6ac601150e9a352ea527f
4
- data.tar.gz: 3becdb310c7afdbbc5e4fdc9cc4bbb025a3c86226ff528dfce1d45790516f830
3
+ metadata.gz: f37e26f454db353f40a384e2e315a8b43a079cf9d2cf168890539d0eb83e7e14
4
+ data.tar.gz: 6143a0fbca3e33965425308aa4b4f50460ba62024af8a7e79c9d8216c6a797dc
5
5
  SHA512:
6
- metadata.gz: f27904ccf00767000b205c18ad6ba8547a895827569fd8f623d861f0f4837121a287f1cba8f102eaf5966b5a10816f430542a07ec29a8ff52300a310e6928d07
7
- data.tar.gz: 013b02a57ed0e5d9e4546e03d857eebf36aee66a53e436f2f679b16fc7cbe84544f8d22ee80cf8586e30190c1bde3b6d4d298d3e45078ad4b1138d3bb7aed4b5
6
+ metadata.gz: e4a14957b72a8491244dbbe6b4cf53e912b504ceb92a5966479c99427fd1be89308735289bf8d05dff4063b55d31cfea82cf916c956bd9de42ff1a5c3417a202
7
+ data.tar.gz: 84d78fa05f982d240df8b4d0fefc63dc6bf413945cbeeb07a10d3914d9a955f092eee01e0a2f7e8de3ce51b550ed33b8d81cb2e5912abea0f0d43b5eb7cb81d7
data/README.md CHANGED
@@ -61,7 +61,7 @@ See list above for supported database drivers.
61
61
  * ✅ [`curb`](https://github.com/taf2/curb) 0.x (0.2.3+), 1.x
62
62
  * ✅ [`patron`](https://github.com/toland/patron) 0.x (0.6.4+)
63
63
  * ✅ [`typhoeus`](https://github.com/typhoeus/typhoeus) 0.x (0.5.0+), 1.x
64
- * ✅ [`async-http`](https://github.com/igrigorik/em-http-request) 0.x (0.70.0+)
64
+ * ✅ [`async-http`](https://github.com/socketry/async-http) 0.x (0.70.0+)
65
65
  * ✅ [`em-http-request`](https://github.com/igrigorik/em-http-request) 1.x
66
66
 
67
67
  ## Installation
@@ -111,7 +111,7 @@ module Aikido::Zen
111
111
  # @raise [Aikido::Zen::NetworkError] if an error occurs trying to make the
112
112
  # request.
113
113
  private def request(request, base_url: @config.api_endpoint)
114
- Net::HTTP.start(base_url.host, base_url.port, http_settings) do |http|
114
+ Net::HTTP.start(base_url.host, base_url.port, http_settings(base_url)) do |http|
115
115
  response = http.request(request)
116
116
 
117
117
  case response
@@ -127,8 +127,11 @@ module Aikido::Zen
127
127
  raise NetworkError.new(request, err)
128
128
  end
129
129
 
130
- private def http_settings
131
- @http_settings ||= {use_ssl: true, max_retries: 2}.merge(@config.api_timeouts)
130
+ private def http_settings(base_url)
131
+ @http_settings ||= {
132
+ use_ssl: base_url.scheme == "https",
133
+ max_retries: 2
134
+ }.merge(@config.api_timeouts)
132
135
  end
133
136
 
134
137
  private def default_headers
@@ -12,7 +12,9 @@ module Aikido::Zen
12
12
 
13
13
  # @!visibility private
14
14
  Context::RAILS_REQUEST_BUILDER = ->(env) do
15
- delegate = ActionDispatch::Request.new(env)
15
+ # Duplicate the Rack environment to prevent unexpected modifications from
16
+ # breaking Rails routing.
17
+ delegate = ActionDispatch::Request.new(env.dup)
16
18
  request = Aikido::Zen::Request.new(
17
19
  delegate, framework: "rails", router: Rails.router
18
20
  )
@@ -7,12 +7,6 @@ module Aikido::Zen
7
7
  module Internals
8
8
  extend FFI::Library
9
9
 
10
- class << self
11
- # @return [String] the name of the extension we're loading, which we can
12
- # use in error messages to identify the architecture.
13
- attr_accessor :libzen_name
14
- end
15
-
16
10
  def self.libzen_names
17
11
  lib_name = "libzen-v#{LIBZEN_VERSION}"
18
12
  lib_ext = FFI::Platform::LIBSUFFIX
@@ -40,17 +34,24 @@ module Aikido::Zen
40
34
  names
41
35
  end
42
36
 
37
+ # @return [String] the name of the extension we're loading, which we can
38
+ # use in error messages.
39
+ def self.libzen_name
40
+ # The most generic platform library name.
41
+ libzen_names.last
42
+ end
43
+
43
44
  # Load the most specific library
44
45
  def self.load_libzen
45
- libzen_names.each do |libzen_name|
46
- libzen_path = File.expand_path(libzen_name, __dir__)
46
+ libzen_names.each do |name|
47
+ path = File.expand_path(name, __dir__)
47
48
  begin
48
- return ffi_lib(libzen_path)
49
+ return ffi_lib(path)
49
50
  rescue LoadError
50
51
  # empty
51
52
  end
52
53
  end
53
- raise LoadError, "Could not load libzen"
54
+ raise LoadError, "Zen could not load its native extension #{libzen_name}"
54
55
  end
55
56
 
56
57
  begin
@@ -68,11 +69,11 @@ module Aikido::Zen
68
69
  # :nocov:
69
70
 
70
71
  # Emit an $stderr warning at startup.
71
- warn "Zen could not load its binary extension #{libzen_name}: #{err}"
72
+ warn "Zen could not load its native extension #{libzen_name}: #{err}"
72
73
 
73
74
  def self.detect_sql_injection(query, *)
74
75
  attempt = format("%p for SQL injection", query)
75
- raise InternalsError.new(attempt, "loading", Internals.libzen_name)
76
+ raise InternalsError.new(attempt, "loading", libzen_name)
76
77
  end
77
78
 
78
79
  # :nocov:
@@ -10,8 +10,6 @@ module Aikido::Zen
10
10
  end
11
11
 
12
12
  initializer "aikido.add_middleware" do |app|
13
- next unless config.zen.protect?
14
-
15
13
  app.middleware.use Aikido::Zen::Middleware::SetContext
16
14
  app.middleware.use Aikido::Zen::Middleware::CheckAllowedAddresses
17
15
  # Request Tracker stats do not consider failed request or 40x, so the middleware
@@ -34,8 +32,8 @@ module Aikido::Zen
34
32
  # Allow the logger to be configured before checking if disabled? so we can
35
33
  # let the user know that the agent is disabled.
36
34
  logger = ::Rails.logger
37
- logger = ActiveSupport::TaggedLogging.new(logger) unless logger.respond_to?(:tagged)
38
- app.config.zen.logger = logger.tagged("aikido")
35
+ logger = logger.tagged("aikido") if logger.respond_to?(:tagged)
36
+ app.config.zen.logger = logger
39
37
 
40
38
  app.config.zen.request_builder = Aikido::Zen::Context::RAILS_REQUEST_BUILDER
41
39
 
@@ -51,20 +49,8 @@ module Aikido::Zen
51
49
  end
52
50
 
53
51
  config.after_initialize do
54
- next unless config.zen.protect?
55
-
56
- # Make sure this is run at the end of the initialization process, so
57
- # that any gems required after aikido-zen are detected and patched
58
- # accordingly.
59
- Aikido::Zen.load_sinks!
60
-
61
- # It's important we start after loading sinks, so we can report the installed packages
52
+ # Start the Aikido Agent only once the application starts.
62
53
  Aikido::Zen.start!
63
-
64
- # Agent's bootstrap process has finished —Controllers are patched to block
65
- # unwanted requests, sinks are loaded, scanners are running—, so we mark
66
- # the agent as installed.
67
- Aikido::Zen.middleware_installed!
68
54
  end
69
55
  end
70
56
  end
@@ -29,6 +29,11 @@ module Aikido::Zen
29
29
  end
30
30
 
31
31
  private def recognize_in_route_set(request, route_set, prefix: nil)
32
+ # ActionDispatch::Journey::Router#recognize modifies the Rack environment.
33
+ # This is correct for Rails routing, but it is not expected to be used in
34
+ # Rack middleware, and using it here can break Rails routing.
35
+ #
36
+ # To avoid this, the Rack environment is duplicated when building request.
32
37
  route_set.router.recognize(request) do |route, _|
33
38
  app = route.app
34
39
  next unless app.matches?(request)
@@ -8,7 +8,7 @@ module Aikido::Zen
8
8
  module Async
9
9
  module HTTP
10
10
  def self.load_sinks!
11
- if Gem.loaded_specs["async-http"]
11
+ if Aikido::Zen.satisfy "async-http", ">= 0.70.0"
12
12
  require "async/http"
13
13
 
14
14
  ::Async::HTTP::Client.prepend(Async::HTTP::ClientExtensions)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module Curl
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["curb"]
10
+ if Aikido::Zen.satisfy "curb", ">= 0.2.3"
11
11
  require "curb"
12
12
 
13
13
  ::Curl::Easy.prepend(Curl::EasyExtensions)
@@ -8,7 +8,7 @@ module Aikido::Zen
8
8
  module EventMachine
9
9
  module HttpRequest
10
10
  def self.load_sinks!
11
- if Gem.loaded_specs["em-http-request"]
11
+ if Aikido::Zen.satisfy "em-http-request", ">= 1.0"
12
12
  require "em-http-request"
13
13
 
14
14
  ::EventMachine::HttpRequest.use(EventMachine::HttpRequest::Middleware)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module Excon
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["excon"]
10
+ if Aikido::Zen.satisfy "excon", ">= 0.50.0"
11
11
  require "excon"
12
12
 
13
13
  ::Excon::Connection.prepend(ConnectionExtensions)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module HTTP
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["http"]
10
+ if Aikido::Zen.satisfy "http", ">= 1.0"
11
11
  require "http"
12
12
 
13
13
  ::HTTP::Client.prepend(ClientExtensions)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module HTTPClient
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["httpclient"]
10
+ if Aikido::Zen.satisfy "httpclient", ">= 2.0"
11
11
  require "httpclient"
12
12
 
13
13
  ::HTTPClient.prepend(HTTPClient::HTTPClientExtensions)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module HTTPX
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["httpx"]
10
+ if Aikido::Zen.satisfy "httpx", ">= 1.1.3"
11
11
  require "httpx"
12
12
 
13
13
  ::HTTPX::Session.prepend(HTTPX::SessionExtensions)
@@ -4,7 +4,7 @@ module Aikido::Zen
4
4
  module Sinks
5
5
  module Mysql2
6
6
  def self.load_sinks!
7
- if Gem.loaded_specs["mysql2"]
7
+ if Aikido::Zen.satisfy "mysql2"
8
8
  require "mysql2"
9
9
 
10
10
  ::Mysql2::Client.prepend(ClientExtensions)
@@ -7,7 +7,7 @@ module Aikido::Zen
7
7
  module Sinks
8
8
  module Patron
9
9
  def self.load_sinks!
10
- if Gem.loaded_specs["patron"]
10
+ if Aikido::Zen.satisfy "patron", ">= 0.6.4"
11
11
  require "patron"
12
12
 
13
13
  ::Patron::Session.prepend(SessionExtensions)
@@ -4,7 +4,7 @@ module Aikido::Zen
4
4
  module Sinks
5
5
  module PG
6
6
  def self.load_sinks!
7
- if Gem.loaded_specs["pg"]
7
+ if Aikido::Zen.satisfy "pg", ">= 1.0"
8
8
  require "pg"
9
9
 
10
10
  ::PG::Connection.prepend(PG::ConnectionExtensions)
@@ -4,7 +4,7 @@ module Aikido::Zen
4
4
  module Sinks
5
5
  module SQLite3
6
6
  def self.load_sinks!
7
- if Gem.loaded_specs["sqlite3"]
7
+ if Aikido::Zen.satisfy "sqlite3", ">= 1.0"
8
8
  require "sqlite3"
9
9
 
10
10
  ::SQLite3::Database.prepend(DatabaseExtensions)
@@ -4,7 +4,7 @@ module Aikido::Zen
4
4
  module Sinks
5
5
  module Trilogy
6
6
  def self.load_sinks!
7
- if Gem.loaded_specs["trilogy"]
7
+ if Aikido::Zen.satisfy "trilogy", ">= 2.0"
8
8
  require "trilogy"
9
9
 
10
10
  ::Trilogy.prepend(TrilogyExtensions)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Aikido
4
4
  module Zen
5
- VERSION = "1.0.1.beta.2"
5
+ VERSION = "1.0.1.beta.4"
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
@@ -1,8 +1,5 @@
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
-
6
3
  require_relative "zen/version"
7
4
  require_relative "zen/errors"
8
5
  require_relative "zen/actor"
@@ -29,6 +26,9 @@ module Aikido
29
26
  # Enable protection. Until this method is called no sinks are loaded
30
27
  # and the Aikido Agent does not start.
31
28
  #
29
+ # This method should be called only once, in the application after the
30
+ # initialization process is complete.
31
+ #
32
32
  # @return [void]
33
33
  def self.protect!
34
34
  if config.disabled?
@@ -36,9 +36,31 @@ module Aikido
36
36
  return
37
37
  end
38
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)
39
+ return unless config.protect?
40
+
41
+ unless load_sources! && load_sinks!
42
+ config.logger.warn "Zen could not find any supported libraries or frameworks. Visit https://github.com/AikidoSec/firewall-ruby for more information."
43
+ return
44
+ end
45
+
46
+ middleware_installed!
47
+ end
48
+
49
+ # @!visibility private
50
+ # Returns whether the loaded gem specification satisfies the listed requirements.
51
+ #
52
+ # Returns false if the gem specification is not loaded.
53
+ #
54
+ # @param name [String] the gem name
55
+ # @param requirements [Array<String>] a variable number of gem requirement strings
56
+ #
57
+ # @return [Boolean] true if the gem specification is loaded and all gem requirements are satisfied
58
+ def self.satisfy(name, *requirements)
59
+ spec = Gem.loaded_specs[name]
60
+
61
+ return false if spec.nil?
62
+
63
+ Gem::Requirement.new(*requirements).satisfied_by?(spec.version)
42
64
  end
43
65
 
44
66
  # @return [Aikido::Zen::Config] the agent configuration.
@@ -149,15 +171,28 @@ module Aikido
149
171
  collector.middleware_installed!
150
172
  end
151
173
 
152
- # Load all sinks matching libraries loaded into memory. This method should
153
- # be called after all other dependencies have been loaded into memory (i.e.
154
- # at the end of the initialization process).
174
+ # @!visibility private
175
+ # Load all sources.
155
176
  #
156
- # If a new gem is required, this method can be called again safely.
177
+ # @return [Boolean] true if any sources were loaded
178
+ def self.load_sources!
179
+ if Aikido::Zen.satisfy("rails", ">= 7.0")
180
+ require_relative "zen/rails_engine"
181
+
182
+ return true
183
+ end
184
+
185
+ false
186
+ end
187
+
188
+ # @!visibility private
189
+ # Load all sinks.
157
190
  #
158
- # @return [void]
191
+ # @return [Boolean] true if any sinks were loaded
159
192
  def self.load_sinks!
160
193
  require_relative "zen/sinks"
194
+
195
+ !Aikido::Zen::Sinks.registry.empty?
161
196
  end
162
197
 
163
198
  # @!visibility private
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.2
4
+ version: 1.0.1.beta.4
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-07-30 00:00:00.000000000 Z
11
+ date: 2025-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby