spyglasses 1.0.0 → 1.1.0
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/CHANGELOG.md +47 -28
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/spyglasses/middleware.rb +16 -4
- data/lib/spyglasses/types.rb +3 -3
- data/lib/spyglasses/version.rb +1 -1
- data/spyglasses.gemspec +43 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0a3d6de667a48f878769b774eccd367018ed52f1c6628cd730e1ff8c9fdaabe
|
4
|
+
data.tar.gz: 737c8e8de705a5dc0eadf303afe1b1fa7a5d2292a700642aa5d82416565661ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4493abc121849ba91d73c18ceaf060f0008b409bbe8c3402f74fa224c8906e6b4ea07e43e3c0f477bd028b37899db73c144ec49daabff0cce54f4878475d54a5
|
7
|
+
data.tar.gz: 22e71db5b421dcb9a78ef599261036d5b32dde80b92abb995933d57261a6b68b9a5505482fe9392c3420e363f8ff42b798c2659d2e012930e4df0d4cd97c5a41
|
data/CHANGELOG.md
CHANGED
@@ -5,37 +5,56 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
-
## [
|
8
|
+
## [1.1.0] - 2024-12-29
|
9
9
|
|
10
|
-
|
10
|
+
### Fixed
|
11
|
+
- **BREAKING**: Fixed API payload format to match TypeScript collector endpoint
|
12
|
+
- Changed `platform_type` to `platformType` in JSON payload (camelCase)
|
13
|
+
- Ensured `ip_address` and `request_query` are never nil (required strings in API schema)
|
14
|
+
- Enhanced IP extraction from forwarded headers with comma-separated values
|
15
|
+
- Fixed 400 Bad Request errors when logging to collector endpoint
|
16
|
+
- Improved error handling and data validation for API compatibility
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
- **BREAKING**: JSON payload field names now use camelCase to match API expectations
|
20
|
+
- Enhanced middleware IP extraction with better fallback handling
|
21
|
+
- Improved request query string handling to ensure non-nil values
|
22
|
+
|
23
|
+
## [1.0.1] - 2024-12-28
|
24
|
+
|
25
|
+
### Added
|
26
|
+
- Comprehensive Ruby documentation in main docs site
|
27
|
+
- Rails-specific configuration examples
|
28
|
+
- Deployment platform guidance (Heroku, Railway, etc.)
|
29
|
+
- Troubleshooting section for common issues
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
- Documentation formatting and code examples
|
33
|
+
- Installation instructions for various Ruby frameworks
|
34
|
+
|
35
|
+
## [1.0.0] - 2024-12-28
|
11
36
|
|
12
37
|
### Added
|
13
38
|
- Initial release of Spyglasses Ruby gem
|
14
|
-
-
|
15
|
-
-
|
16
|
-
-
|
17
|
-
-
|
18
|
-
- Rack middleware for
|
19
|
-
-
|
20
|
-
- Non-blocking request logging to Spyglasses collector API
|
21
|
-
- Thread-safe pattern caching and background processing
|
22
|
-
- Comprehensive test suite with >95% code coverage
|
23
|
-
- Environment variable configuration support
|
39
|
+
- AI bot detection with pattern matching
|
40
|
+
- AI referrer detection for traffic from AI platforms
|
41
|
+
- Flexible blocking rules via Spyglasses platform
|
42
|
+
- Non-blocking request logging to collector API
|
43
|
+
- Rack middleware for universal Ruby framework support
|
44
|
+
- Thread-safe operations for concurrent applications
|
24
45
|
- Default patterns for common AI agents and crawlers
|
25
|
-
-
|
26
|
-
- Debug logging
|
27
|
-
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
|
34
|
-
|
35
|
-
-
|
36
|
-
|
37
|
-
-
|
38
|
-
-
|
39
|
-
|
40
|
-
[Unreleased]: https://github.com/spyglasses/spyglasses-ruby/compare/v1.0.0...HEAD
|
46
|
+
- Configuration via environment variables
|
47
|
+
- Debug logging support
|
48
|
+
- Pattern synchronization with API
|
49
|
+
- Support for Rails, Sinatra, and other Rack-based frameworks
|
50
|
+
|
51
|
+
### Features
|
52
|
+
- **Bot Detection**: GPTBot, ClaudeBot, ChatGPT-User, Claude-User, and more
|
53
|
+
- **AI Referrer Detection**: ChatGPT, Claude, Perplexity, Gemini, Copilot
|
54
|
+
- **Blocking Rules**: Configurable via platform dashboard
|
55
|
+
- **Performance**: Pattern caching, background logging, minimal overhead
|
56
|
+
- **Framework Support**: Universal Rack middleware design
|
57
|
+
|
58
|
+
[Unreleased]: https://github.com/spyglasses/spyglasses-ruby/compare/v1.0.1...HEAD
|
59
|
+
[1.0.1]: https://github.com/spyglasses/spyglasses-ruby/compare/v1.0.0...v1.0.1
|
41
60
|
[1.0.0]: https://github.com/spyglasses/spyglasses-ruby/releases/tag/v1.0.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -331,5 +331,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
331
331
|
## Support
|
332
332
|
|
333
333
|
- 📧 Email: support@spyglasses.io
|
334
|
-
- 📖 Documentation: https://
|
334
|
+
- 📖 Documentation: https://www.spyglasses.io/docs/platforms/ruby
|
335
335
|
- 🐛 Issues: https://github.com/spyglasses/spyglasses-ruby/issues
|
@@ -137,13 +137,17 @@ module Spyglasses
|
|
137
137
|
def log_request_async(detection_result, request, status, response_time)
|
138
138
|
return unless @configuration.api_key_present?
|
139
139
|
|
140
|
+
# Ensure ip_address is never nil
|
141
|
+
client_ip = extract_client_ip(request) || '127.0.0.1'
|
142
|
+
|
140
143
|
request_info = {
|
141
144
|
url: request.url,
|
142
145
|
user_agent: request.user_agent || '',
|
143
|
-
ip_address:
|
146
|
+
ip_address: client_ip,
|
144
147
|
request_method: request.request_method,
|
145
148
|
request_path: request.path,
|
146
|
-
request_query
|
149
|
+
# Ensure request_query is never nil - use empty string if no query
|
150
|
+
request_query: request.query_string || '',
|
147
151
|
referrer: request.referrer,
|
148
152
|
response_status: status,
|
149
153
|
response_time_ms: (response_time * 1000).round,
|
@@ -157,13 +161,21 @@ module Spyglasses
|
|
157
161
|
|
158
162
|
def extract_client_ip(request)
|
159
163
|
# Try various headers to get the real client IP
|
160
|
-
[
|
164
|
+
ip = [
|
161
165
|
request.env['HTTP_X_FORWARDED_FOR'],
|
162
166
|
request.env['HTTP_X_REAL_IP'],
|
163
167
|
request.env['HTTP_CF_CONNECTING_IP'], # Cloudflare
|
164
168
|
request.env['HTTP_X_CLIENT_IP'],
|
165
169
|
request.env['REMOTE_ADDR']
|
166
|
-
].find { |ip| ip && !ip.empty? && ip != '127.0.0.1' }
|
170
|
+
].find { |ip| ip && !ip.empty? && ip != '127.0.0.1' }
|
171
|
+
|
172
|
+
# If we found an IP in headers, handle comma-separated lists (X-Forwarded-For)
|
173
|
+
if ip && ip.include?(',')
|
174
|
+
ip = ip.split(',').first.strip
|
175
|
+
end
|
176
|
+
|
177
|
+
# Return the found IP or fallback to request.ip
|
178
|
+
ip || request.ip
|
167
179
|
end
|
168
180
|
|
169
181
|
def extract_headers(request)
|
data/lib/spyglasses/types.rb
CHANGED
@@ -187,17 +187,17 @@ module Spyglasses
|
|
187
187
|
{
|
188
188
|
url: @url,
|
189
189
|
user_agent: @user_agent,
|
190
|
-
ip_address: @ip_address,
|
190
|
+
ip_address: @ip_address || '',
|
191
191
|
request_method: @request_method,
|
192
192
|
request_path: @request_path,
|
193
|
-
request_query: @request_query,
|
193
|
+
request_query: @request_query || '',
|
194
194
|
request_body: @request_body,
|
195
195
|
referrer: @referrer,
|
196
196
|
response_status: @response_status,
|
197
197
|
response_time_ms: @response_time_ms,
|
198
198
|
headers: @headers,
|
199
199
|
timestamp: @timestamp,
|
200
|
-
|
200
|
+
platformType: @platform_type,
|
201
201
|
metadata: @metadata
|
202
202
|
}
|
203
203
|
end
|
data/lib/spyglasses/version.rb
CHANGED
data/spyglasses.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'lib/spyglasses/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'spyglasses'
|
5
|
+
spec.version = Spyglasses::VERSION
|
6
|
+
spec.authors = ['Orchestra AI, Inc.']
|
7
|
+
spec.email = ['support@spyglasses.io']
|
8
|
+
|
9
|
+
spec.summary = 'AI Agent Detection and Management for Ruby web applications'
|
10
|
+
spec.description = 'Spyglasses provides comprehensive AI agent detection and management capabilities for Ruby web applications, including Rails, Sinatra, and other Rack-based frameworks.'
|
11
|
+
spec.homepage = 'https://www.spyglasses.io'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.required_ruby_version = '>= 2.7.0'
|
14
|
+
|
15
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
16
|
+
spec.metadata['source_code_uri'] = 'https://github.com/spyglasses/spyglasses-ruby'
|
17
|
+
spec.metadata['documentation_uri'] = 'https://www.spyglasses.io/docs/platforms/ruby'
|
18
|
+
spec.metadata['changelog_uri'] = 'https://github.com/spyglasses/spyglasses-ruby/blob/main/CHANGELOG.md'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
23
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
# Runtime dependencies
|
31
|
+
spec.add_dependency 'rack', '>= 2.0'
|
32
|
+
spec.add_dependency 'json', '>= 2.0'
|
33
|
+
|
34
|
+
# Development dependencies
|
35
|
+
spec.add_development_dependency 'bundler', '>= 2.0'
|
36
|
+
spec.add_development_dependency 'rake', '>= 13.0'
|
37
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
38
|
+
spec.add_development_dependency 'webmock', '~> 3.0'
|
39
|
+
spec.add_development_dependency 'rack-test', '~> 2.0'
|
40
|
+
spec.add_development_dependency 'rubocop', '~> 1.0'
|
41
|
+
spec.add_development_dependency 'simplecov', '~> 0.21'
|
42
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
43
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spyglasses
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Orchestra AI, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -173,13 +173,14 @@ files:
|
|
173
173
|
- lib/spyglasses/middleware.rb
|
174
174
|
- lib/spyglasses/types.rb
|
175
175
|
- lib/spyglasses/version.rb
|
176
|
+
- spyglasses.gemspec
|
176
177
|
homepage: https://www.spyglasses.io
|
177
178
|
licenses:
|
178
179
|
- MIT
|
179
180
|
metadata:
|
180
181
|
homepage_uri: https://www.spyglasses.io
|
181
182
|
source_code_uri: https://github.com/spyglasses/spyglasses-ruby
|
182
|
-
documentation_uri: https://
|
183
|
+
documentation_uri: https://www.spyglasses.io/docs/platforms/ruby
|
183
184
|
changelog_uri: https://github.com/spyglasses/spyglasses-ruby/blob/main/CHANGELOG.md
|
184
185
|
post_install_message:
|
185
186
|
rdoc_options: []
|