spyglasses 1.0.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.
data/README.md ADDED
@@ -0,0 +1,335 @@
1
+ # Spyglasses Ruby Gem
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/spyglasses.svg)](https://badge.fury.io/rb/spyglasses)
4
+ [![Ruby](https://github.com/spyglasses/spyglasses-ruby/actions/workflows/ruby.yml/badge.svg)](https://github.com/spyglasses/spyglasses-ruby/actions/workflows/ruby.yml)
5
+
6
+ AI Agent Detection and Management for Ruby web applications. Spyglasses provides comprehensive AI agent detection and management capabilities for Ruby web applications, including Rails, Sinatra, and other Rack-based frameworks.
7
+
8
+ ## Features
9
+
10
+ - 🤖 **AI Bot Detection**: Automatically detect AI agents like GPTBot, ClaudeBot, ChatGPT-User, and more
11
+ - 🧠 **AI Referrer Detection**: Track traffic from AI platforms like ChatGPT, Claude, Perplexity
12
+ - 🚫 **Flexible Blocking**: Configure blocking rules via the Spyglasses platform
13
+ - 📊 **Request Logging**: Non-blocking request logging to Spyglasses collector
14
+ - ⚡ **High Performance**: Minimal overhead with pattern caching and background processing
15
+ - 🔧 **Easy Integration**: Drop-in Rack middleware for any Ruby web framework
16
+ - 🛡️ **Thread Safe**: Built for concurrent Ruby applications
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'spyglasses'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ ```bash
29
+ $ bundle install
30
+ ```
31
+
32
+ Or install it yourself as:
33
+
34
+ ```bash
35
+ $ gem install spyglasses
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ### 1. Get Your API Key
41
+
42
+ Sign up at [spyglasses.io](https://spyglasses.io) to get your API key.
43
+
44
+ ### 2. Set Environment Variable
45
+
46
+ ```bash
47
+ export SPYGLASSES_API_KEY=your_api_key_here
48
+ ```
49
+
50
+ ### 3. Add Middleware
51
+
52
+ #### Rails
53
+
54
+ Add to your `config/application.rb`:
55
+
56
+ ```ruby
57
+ # config/application.rb
58
+ class Application < Rails::Application
59
+ config.middleware.use Spyglasses::Middleware
60
+ end
61
+ ```
62
+
63
+ Or with options:
64
+
65
+ ```ruby
66
+ # config/application.rb
67
+ class Application < Rails::Application
68
+ config.middleware.use Spyglasses::Middleware, {
69
+ api_key: ENV['SPYGLASSES_API_KEY'],
70
+ debug: Rails.env.development?,
71
+ exclude_paths: ['/admin', '/internal']
72
+ }
73
+ end
74
+ ```
75
+
76
+ #### Sinatra
77
+
78
+ ```ruby
79
+ require 'sinatra'
80
+ require 'spyglasses'
81
+
82
+ use Spyglasses::Middleware, api_key: ENV['SPYGLASSES_API_KEY']
83
+
84
+ get '/' do
85
+ 'Hello World!'
86
+ end
87
+ ```
88
+
89
+ #### Rack Application
90
+
91
+ ```ruby
92
+ # config.ru
93
+ require 'spyglasses'
94
+
95
+ use Spyglasses::Middleware, api_key: ENV['SPYGLASSES_API_KEY']
96
+
97
+ app = lambda do |env|
98
+ [200, {'Content-Type' => 'text/plain'}, ['Hello World!']]
99
+ end
100
+
101
+ run app
102
+ ```
103
+
104
+ ## Configuration
105
+
106
+ ### Environment Variables
107
+
108
+ | Variable | Description | Default |
109
+ |----------|-------------|---------|
110
+ | `SPYGLASSES_API_KEY` | Your Spyglasses API key | Required |
111
+ | `SPYGLASSES_DEBUG` | Enable debug logging | `false` |
112
+ | `SPYGLASSES_AUTO_SYNC` | Auto-sync patterns on startup | `true` |
113
+ | `SPYGLASSES_CACHE_TTL` | Pattern cache TTL in seconds | `86400` (24 hours) |
114
+ | `SPYGLASSES_COLLECT_ENDPOINT` | Custom collector endpoint | `https://www.spyglasses.io/api/collect` |
115
+ | `SPYGLASSES_PATTERNS_ENDPOINT` | Custom patterns endpoint | `https://www.spyglasses.io/api/patterns` |
116
+
117
+ ### Middleware Options
118
+
119
+ ```ruby
120
+ use Spyglasses::Middleware, {
121
+ api_key: 'your-api-key', # API key (overrides env var)
122
+ debug: true, # Enable debug logging
123
+ auto_sync: true, # Auto-sync patterns
124
+ platform_type: 'rails', # Platform identifier
125
+ exclude_paths: [ # Paths to exclude from monitoring
126
+ '/admin',
127
+ '/api/internal',
128
+ /\.json$/ # Regex patterns supported
129
+ ],
130
+ collect_endpoint: 'https://...', # Custom collector endpoint
131
+ patterns_endpoint: 'https://...' # Custom patterns endpoint
132
+ }
133
+ ```
134
+
135
+ ### Global Configuration
136
+
137
+ ```ruby
138
+ # config/initializers/spyglasses.rb (Rails)
139
+ Spyglasses.configure do |config|
140
+ config.api_key = ENV['SPYGLASSES_API_KEY']
141
+ config.debug = Rails.env.development?
142
+ config.platform_type = 'rails'
143
+ config.exclude_paths = ['/admin', '/internal']
144
+ end
145
+ ```
146
+
147
+ ## Usage Examples
148
+
149
+ ### Manual Detection
150
+
151
+ ```ruby
152
+ require 'spyglasses'
153
+
154
+ # Configure the client
155
+ client = Spyglasses::Client.new(
156
+ Spyglasses::Configuration.new.tap do |config|
157
+ config.api_key = 'your-api-key'
158
+ end
159
+ )
160
+
161
+ # Detect bots
162
+ result = client.detect_bot('GPTBot/1.0')
163
+ puts "Bot detected: #{result.is_bot}" # => true
164
+ puts "Should block: #{result.should_block}" # => depends on your settings
165
+
166
+ # Detect AI referrers
167
+ result = client.detect_ai_referrer('https://chat.openai.com/')
168
+ puts "AI referrer: #{result.source_type}" # => 'ai_referrer'
169
+
170
+ # Combined detection
171
+ result = client.detect('Mozilla/5.0', 'https://chat.openai.com/')
172
+ puts "Source type: #{result.source_type}" # => 'ai_referrer'
173
+ ```
174
+
175
+ ### Custom Rack Middleware
176
+
177
+ ```ruby
178
+ class MyCustomMiddleware
179
+ def initialize(app)
180
+ @app = app
181
+ @spyglasses = Spyglasses::Client.new
182
+ end
183
+
184
+ def call(env)
185
+ request = Rack::Request.new(env)
186
+
187
+ # Detect using Spyglasses
188
+ result = @spyglasses.detect(request.user_agent, request.referrer)
189
+
190
+ if result.is_bot && result.should_block
191
+ return [403, {}, ['Forbidden']]
192
+ end
193
+
194
+ # Log the request if something was detected
195
+ if result.source_type != 'none'
196
+ @spyglasses.log_request(result, {
197
+ url: request.url,
198
+ user_agent: request.user_agent,
199
+ # ... other request info
200
+ })
201
+ end
202
+
203
+ @app.call(env)
204
+ end
205
+ end
206
+ ```
207
+
208
+ ## Blocking Configuration
209
+
210
+ Blocking rules are configured through the [Spyglasses platform](https://spyglasses.io) dashboard, not in code:
211
+
212
+ 1. **Global AI Model Trainer Blocking**: Block all AI training bots (GPTBot, ClaudeBot, etc.)
213
+ 2. **Custom Block Rules**: Block specific categories, subcategories, or individual patterns
214
+ 3. **Custom Allow Rules**: Create exceptions for specific bots
215
+
216
+ The middleware automatically loads and applies these settings.
217
+
218
+ ## Default Patterns
219
+
220
+ The gem includes default patterns for common AI agents:
221
+
222
+ ### AI Assistants (Usually Allowed)
223
+ - ChatGPT-User/* - OpenAI ChatGPT user requests
224
+ - Claude-User/* - Anthropic Claude user requests
225
+ - Perplexity-User/* - Perplexity AI user requests
226
+ - Gemini-User/* - Google Gemini user requests
227
+
228
+ ### AI Model Training Crawlers (Can be Blocked)
229
+ - GPTBot/* - OpenAI training crawler
230
+ - ClaudeBot/* - Anthropic training crawler
231
+ - CCBot/* - Common Crawl bot
232
+ - meta-externalagent/* - Meta training crawler
233
+ - Applebot-Extended/* - Apple training crawler
234
+
235
+ ### AI Referrers
236
+ - chat.openai.com, chatgpt.com - ChatGPT
237
+ - claude.ai - Claude
238
+ - perplexity.ai - Perplexity
239
+ - gemini.google.com - Gemini
240
+ - copilot.microsoft.com - Microsoft Copilot
241
+
242
+ ## Framework Integration
243
+
244
+ ### Rails Integration
245
+
246
+ For Rails applications, you can also create an initializer:
247
+
248
+ ```ruby
249
+ # config/initializers/spyglasses.rb
250
+ Spyglasses.configure do |config|
251
+ config.api_key = Rails.application.credentials.spyglasses_api_key
252
+ config.debug = Rails.env.development?
253
+ config.platform_type = 'rails'
254
+ config.exclude_paths = [
255
+ '/rails/active_storage',
256
+ '/admin',
257
+ /^\/api\/internal/
258
+ ]
259
+ end
260
+
261
+ # Add middleware
262
+ Rails.application.config.middleware.use Spyglasses::Middleware
263
+ ```
264
+
265
+ ### Sinatra Integration
266
+
267
+ ```ruby
268
+ # app.rb
269
+ require 'sinatra'
270
+ require 'spyglasses'
271
+
272
+ configure do
273
+ Spyglasses.configure do |config|
274
+ config.api_key = ENV['SPYGLASSES_API_KEY']
275
+ config.platform_type = 'sinatra'
276
+ end
277
+
278
+ use Spyglasses::Middleware
279
+ end
280
+ ```
281
+
282
+ ## Testing
283
+
284
+ Add to your test helper:
285
+
286
+ ```ruby
287
+ # spec/spec_helper.rb or test/test_helper.rb
288
+ require 'spyglasses'
289
+
290
+ # Disable API calls in tests
291
+ Spyglasses.configure do |config|
292
+ config.api_key = nil
293
+ config.auto_sync = false
294
+ end
295
+ ```
296
+
297
+ Run the test suite:
298
+
299
+ ```bash
300
+ $ bundle exec rspec
301
+ ```
302
+
303
+ ## Development
304
+
305
+ After checking out the repo, run:
306
+
307
+ ```bash
308
+ $ bin/setup # Install dependencies
309
+ $ rake spec # Run tests
310
+ $ rake console # Interactive console
311
+ $ rake check # Run all checks (tests + linting)
312
+ ```
313
+
314
+ ## Performance
315
+
316
+ The Spyglasses middleware is designed for high-performance applications:
317
+
318
+ - **Pattern Caching**: Regex patterns are compiled and cached
319
+ - **Background Logging**: API calls are made in background threads
320
+ - **Minimal Overhead**: Typical overhead is <1ms per request
321
+ - **Smart Exclusions**: Static assets and health checks are automatically excluded
322
+
323
+ ## Contributing
324
+
325
+ Bug reports and pull requests are welcome on GitHub at https://github.com/spyglasses/spyglasses-ruby.
326
+
327
+ ## License
328
+
329
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
330
+
331
+ ## Support
332
+
333
+ - 📧 Email: support@spyglasses.io
334
+ - 📖 Documentation: https://docs.spyglasses.io
335
+ - 🐛 Issues: https://github.com/spyglasses/spyglasses-ruby/issues
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new
9
+
10
+ desc 'Run tests with coverage'
11
+ task :coverage do
12
+ ENV['COVERAGE'] = 'true'
13
+ Rake::Task[:spec].invoke
14
+ end
15
+
16
+ desc 'Run all checks (tests, rubocop, etc.)'
17
+ task :check do
18
+ Rake::Task[:spec].invoke
19
+ Rake::Task[:rubocop].invoke
20
+ end
21
+
22
+ task default: :check
23
+
24
+ desc 'Build and install gem locally'
25
+ task :install_local do
26
+ Rake::Task[:build].invoke
27
+ gemfile = Dir.glob('pkg/*.gem').last
28
+ system "gem install #{gemfile}"
29
+ end
30
+
31
+ desc 'Run console with gem loaded'
32
+ task :console do
33
+ require 'bundler/setup'
34
+ require 'spyglasses'
35
+ require 'pry'
36
+ Pry.start
37
+ end