vectra-client 0.3.0 → 0.3.2

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.
@@ -0,0 +1,216 @@
1
+ ---
2
+ layout: page
3
+ title: "Runbook: Pool Exhaustion"
4
+ permalink: /guides/runbooks/pool-exhausted/
5
+ ---
6
+
7
+ # Runbook: Pool Exhaustion
8
+
9
+ **Alert:** `VectraPoolExhausted`
10
+ **Severity:** Critical
11
+ **Threshold:** 0 available connections for 1 minute
12
+
13
+ ## Symptoms
14
+
15
+ - `Vectra::Pool::TimeoutError` exceptions
16
+ - Requests timing out waiting for connections
17
+ - Application threads blocked
18
+
19
+ ## Quick Diagnosis
20
+
21
+ ```ruby
22
+ # Check pool stats
23
+ client = Vectra::Client.new(provider: :pgvector, host: ENV['DATABASE_URL'])
24
+ puts client.provider.pool_stats
25
+ # => { available: 0, checked_out: 10, size: 10 }
26
+ ```
27
+
28
+ ```bash
29
+ # Check PostgreSQL connections
30
+ psql -c "SELECT count(*) FROM pg_stat_activity WHERE application_name LIKE '%vectra%';"
31
+ ```
32
+
33
+ ## Investigation Steps
34
+
35
+ ### 1. Check Current Pool State
36
+
37
+ ```ruby
38
+ stats = client.provider.pool_stats
39
+ puts "Available: #{stats[:available]}"
40
+ puts "Checked out: #{stats[:checked_out]}"
41
+ puts "Total size: #{stats[:size]}"
42
+ puts "Shutdown: #{stats[:shutdown]}"
43
+ ```
44
+
45
+ ### 2. Identify Connection Leaks
46
+
47
+ ```ruby
48
+ # Look for connections not being returned
49
+ # Common causes:
50
+ # - Missing ensure blocks
51
+ # - Exceptions before checkin
52
+ # - Long-running operations
53
+
54
+ # Bad:
55
+ conn = pool.checkout
56
+ do_something(conn) # If this raises, connection is leaked!
57
+ pool.checkin(conn)
58
+
59
+ # Good:
60
+ pool.with_connection do |conn|
61
+ do_something(conn)
62
+ end # Always returns connection
63
+ ```
64
+
65
+ ### 3. Check for Long-Running Queries
66
+
67
+ ```sql
68
+ -- PostgreSQL: Find long-running queries
69
+ SELECT pid, now() - pg_stat_activity.query_start AS duration, query
70
+ FROM pg_stat_activity
71
+ WHERE state != 'idle'
72
+ AND query NOT LIKE '%pg_stat_activity%'
73
+ ORDER BY duration DESC;
74
+
75
+ -- Kill long-running query if needed
76
+ SELECT pg_terminate_backend(pid);
77
+ ```
78
+
79
+ ### 4. Check Application Thread Count
80
+
81
+ ```ruby
82
+ # If using Puma/Sidekiq
83
+ # Ensure pool_size >= max_threads
84
+ puts "Thread count: #{Thread.list.count}"
85
+ puts "Pool size: #{client.config.pool_size}"
86
+ ```
87
+
88
+ ## Resolution Steps
89
+
90
+ ### Immediate: Restart Connection Pool
91
+
92
+ ```ruby
93
+ # Force pool restart
94
+ client.provider.shutdown_pool
95
+ # Pool will be recreated on next operation
96
+ ```
97
+
98
+ ### Increase Pool Size
99
+
100
+ ```ruby
101
+ Vectra.configure do |config|
102
+ config.provider = :pgvector
103
+ config.host = ENV['DATABASE_URL']
104
+ config.pool_size = 20 # Increase from default 5
105
+ config.pool_timeout = 10 # Increase timeout
106
+ end
107
+ ```
108
+
109
+ ### Fix Connection Leaks
110
+
111
+ ```ruby
112
+ # Always use with_connection block
113
+ client.provider.with_pooled_connection do |conn|
114
+ # Your code here
115
+ # Connection automatically returned
116
+ end
117
+
118
+ # Or ensure checkin in rescue
119
+ begin
120
+ conn = pool.checkout
121
+ do_work(conn)
122
+ ensure
123
+ pool.checkin(conn) if conn
124
+ end
125
+ ```
126
+
127
+ ### Reduce Connection Hold Time
128
+
129
+ ```ruby
130
+ # Break up long operations
131
+ large_dataset.each_slice(100) do |batch|
132
+ client.provider.with_pooled_connection do |conn|
133
+ process_batch(batch, conn)
134
+ end
135
+ # Connection returned between batches
136
+ end
137
+ ```
138
+
139
+ ### Add Connection Warmup
140
+
141
+ ```ruby
142
+ # In application initializer
143
+ client = Vectra::Client.new(provider: :pgvector, host: ENV['DATABASE_URL'])
144
+ client.provider.warmup_pool(5) # Pre-create 5 connections
145
+ ```
146
+
147
+ ## Prevention
148
+
149
+ ### 1. Right-size Pool
150
+
151
+ ```ruby
152
+ # Formula: pool_size = (max_threads * 1.5) + background_workers
153
+ # Example: Puma with 5 threads, 3 Sidekiq workers
154
+ pool_size = (5 * 1.5) + 3 # = 10.5, round to 12
155
+ ```
156
+
157
+ ### 2. Monitor Pool Usage
158
+
159
+ ```promql
160
+ # Alert when pool is >80% utilized
161
+ vectra_pool_connections{state="checked_out"}
162
+ / vectra_pool_connections{state="available"} > 0.8
163
+ ```
164
+
165
+ ### 3. Implement Connection Timeout
166
+
167
+ ```ruby
168
+ Vectra.configure do |config|
169
+ config.pool_timeout = 5 # Fail fast instead of hanging
170
+ end
171
+ ```
172
+
173
+ ### 4. Use Connection Pool Metrics
174
+
175
+ ```ruby
176
+ # Log pool stats periodically
177
+ every(60.seconds) do
178
+ stats = client.provider.pool_stats
179
+ logger.info "Pool: avail=#{stats[:available]} out=#{stats[:checked_out]}"
180
+ end
181
+ ```
182
+
183
+ ## PostgreSQL-Specific
184
+
185
+ ### Check max_connections
186
+
187
+ ```sql
188
+ SHOW max_connections; -- Default: 100
189
+
190
+ -- Increase if needed (requires restart)
191
+ ALTER SYSTEM SET max_connections = 200;
192
+ ```
193
+
194
+ ### Monitor Connection Usage
195
+
196
+ ```sql
197
+ SELECT
198
+ count(*) as total,
199
+ count(*) FILTER (WHERE state = 'active') as active,
200
+ count(*) FILTER (WHERE state = 'idle') as idle
201
+ FROM pg_stat_activity;
202
+ ```
203
+
204
+ ## Escalation
205
+
206
+ | Time | Action |
207
+ |------|--------|
208
+ | 1 min | Restart pool, page on-call |
209
+ | 5 min | Increase pool size, restart app |
210
+ | 15 min | Check for connection leaks |
211
+ | 30 min | Escalate to DBA |
212
+
213
+ ## Related
214
+
215
+ - [High Error Rate Runbook]({{ site.baseurl }}/guides/runbooks/high-error-rate)
216
+ - [Performance Guide]({{ site.baseurl }}/guides/performance)
@@ -0,0 +1,348 @@
1
+ ---
2
+ layout: page
3
+ title: Security Best Practices
4
+ permalink: /guides/security/
5
+ ---
6
+
7
+ # Security Best Practices
8
+
9
+ Complete guide for securing Vectra in production environments.
10
+
11
+ ## API Key Management
12
+
13
+ ### Environment Variables (Recommended)
14
+
15
+ **Always use environment variables for API keys:**
16
+
17
+ ```ruby
18
+ # ✅ Good
19
+ Vectra.configure do |config|
20
+ config.provider = :pinecone
21
+ config.api_key = ENV['PINECONE_API_KEY'] # Set in .env or system env
22
+ config.environment = ENV['PINECONE_ENVIRONMENT'] || 'us-east-1'
23
+ end
24
+ ```
25
+
26
+ ```bash
27
+ # Set in environment
28
+ export PINECONE_API_KEY="your-key-here"
29
+ export PINECONE_ENVIRONMENT="us-east-1"
30
+ ```
31
+
32
+ ### Rails Credentials (Encrypted)
33
+
34
+ ```ruby
35
+ # ✅ Good - Rails encrypted credentials
36
+ Vectra.configure do |config|
37
+ config.api_key = Rails.application.credentials.dig(:pinecone, :api_key)
38
+ end
39
+ ```
40
+
41
+ ```bash
42
+ # Edit credentials
43
+ rails credentials:edit
44
+
45
+ # Add to credentials.yml.enc:
46
+ # pinecone:
47
+ # api_key: your-key-here
48
+ ```
49
+
50
+ ### Secret Management Services
51
+
52
+ ```ruby
53
+ # ✅ Good - AWS Secrets Manager
54
+ require 'aws-sdk-secretsmanager'
55
+
56
+ secrets = Aws::SecretsManager::Client.new
57
+ secret = JSON.parse(
58
+ secrets.get_secret_value(secret_id: 'vectra/pinecone').secret_string
59
+ )
60
+
61
+ Vectra.configure do |config|
62
+ config.api_key = secret['api_key']
63
+ end
64
+ ```
65
+
66
+ ```ruby
67
+ # ✅ Good - HashiCorp Vault
68
+ require 'vault'
69
+
70
+ Vault.auth.aws
71
+ secret = Vault.logical.read("secret/vectra/pinecone")
72
+
73
+ Vectra.configure do |config|
74
+ config.api_key = secret.data[:api_key]
75
+ end
76
+ ```
77
+
78
+ ### What NOT to Do
79
+
80
+ ```ruby
81
+ # ❌ NEVER hardcode API keys
82
+ Vectra.configure do |config|
83
+ config.api_key = "pk-123456789" # This will be committed to git!
84
+ end
85
+
86
+ # ❌ NEVER store in config files
87
+ # config/vectra.yml
88
+ # api_key: "pk-123456789" # This will be committed!
89
+
90
+ # ❌ NEVER log API keys
91
+ logger.info("API key: #{config.api_key}") # Will appear in logs!
92
+ ```
93
+
94
+ ## Credential Rotation
95
+
96
+ Use built-in credential rotation for zero-downtime key updates:
97
+
98
+ ```ruby
99
+ require 'vectra/credential_rotation'
100
+
101
+ # Setup rotation
102
+ rotator = Vectra::CredentialRotator.new(
103
+ primary_key: ENV['PINECONE_API_KEY'],
104
+ secondary_key: ENV['PINECONE_API_KEY_NEW'],
105
+ provider: :pinecone
106
+ )
107
+
108
+ # Test new key before switching
109
+ if rotator.test_secondary
110
+ rotator.switch_to_secondary
111
+ puts "✅ Rotation complete"
112
+ else
113
+ puts "❌ New key validation failed - keeping primary"
114
+ end
115
+
116
+ # Rollback if issues occur
117
+ rotator.rollback
118
+ ```
119
+
120
+ ### Multi-Provider Rotation
121
+
122
+ ```ruby
123
+ # Register multiple providers
124
+ Vectra::CredentialRotationManager.register(:pinecone,
125
+ primary: ENV['PINECONE_API_KEY'],
126
+ secondary: ENV['PINECONE_API_KEY_NEW']
127
+ )
128
+
129
+ Vectra::CredentialRotationManager.register(:qdrant,
130
+ primary: ENV['QDRANT_API_KEY'],
131
+ secondary: ENV['QDRANT_API_KEY_NEW']
132
+ )
133
+
134
+ # Test all new keys
135
+ results = Vectra::CredentialRotationManager.test_all_secondary
136
+ # => { pinecone: true, qdrant: false }
137
+
138
+ # Rotate all if tests pass
139
+ if results.values.all?
140
+ Vectra::CredentialRotationManager.rotate_all
141
+ end
142
+
143
+ # Check rotation status
144
+ Vectra::CredentialRotationManager.status
145
+ ```
146
+
147
+ ### Rotation Best Practices
148
+
149
+ 1. **Test before switching** - Always validate new credentials
150
+ 2. **Monitor after rotation** - Watch for errors for 24-48 hours
151
+ 3. **Keep old key active** - Don't revoke immediately
152
+ 4. **Rotate during low traffic** - Minimize impact
153
+ 5. **Use gradual migration** - For high-traffic systems
154
+
155
+ ## Audit Logging
156
+
157
+ Enable audit logging for compliance and security monitoring:
158
+
159
+ ```ruby
160
+ require 'vectra/audit_log'
161
+
162
+ # Setup audit logging
163
+ audit = Vectra::AuditLog.new(
164
+ output: "log/audit.json.log",
165
+ app: "my-service",
166
+ env: Rails.env
167
+ )
168
+
169
+ # Log access events
170
+ audit.log_access(
171
+ user_id: current_user.id,
172
+ operation: "query",
173
+ index: "sensitive-data",
174
+ result_count: 10
175
+ )
176
+
177
+ # Log authentication
178
+ audit.log_authentication(
179
+ user_id: user.id,
180
+ success: true,
181
+ provider: "pinecone"
182
+ )
183
+
184
+ # Log credential rotations
185
+ audit.log_credential_rotation(
186
+ provider: "pinecone",
187
+ success: true,
188
+ rotated_by: admin_user.id
189
+ )
190
+
191
+ # Log data modifications
192
+ audit.log_data_modification(
193
+ user_id: user.id,
194
+ operation: "upsert",
195
+ index: "vectors",
196
+ record_count: 100
197
+ )
198
+ ```
199
+
200
+ ### Global Audit Logging
201
+
202
+ ```ruby
203
+ # Setup once in initializer
204
+ Vectra::AuditLogging.setup!(
205
+ output: "log/audit.json.log",
206
+ app: "my-service"
207
+ )
208
+
209
+ # Use anywhere
210
+ Vectra::AuditLogging.log(:access,
211
+ user_id: current_user.id,
212
+ operation: "query",
213
+ index: "data"
214
+ )
215
+ ```
216
+
217
+ ### Audit Log Format
218
+
219
+ ```json
220
+ {
221
+ "timestamp": "2025-01-08T12:00:00.123Z",
222
+ "level": "info",
223
+ "logger": "vectra",
224
+ "message": "audit.access",
225
+ "event_type": "access",
226
+ "user_id": "user123",
227
+ "operation": "query",
228
+ "resource": "my-index",
229
+ "result_count": 10
230
+ }
231
+ ```
232
+
233
+ ## Network Security
234
+
235
+ ### HTTPS/TLS
236
+
237
+ - **Always use HTTPS** - Enforced by default
238
+ - **Verify certificates** - Enabled by default
239
+ - **Use VPN/private networks** when possible
240
+
241
+ ### mTLS (Mutual TLS)
242
+
243
+ For providers supporting mutual TLS authentication:
244
+
245
+ ```ruby
246
+ # pgvector with client certificates
247
+ Vectra.configure do |config|
248
+ config.provider = :pgvector
249
+ config.host = "postgresql://user:pass@host/db?" \
250
+ "sslmode=verify-full&" \
251
+ "sslcert=/path/to/client.crt&" \
252
+ "sslkey=/path/to/client.key&" \
253
+ "sslrootcert=/path/to/ca.crt"
254
+ end
255
+ ```
256
+
257
+ **Note:** mTLS support depends on provider capabilities. Check provider documentation.
258
+
259
+ ## Data Security
260
+
261
+ ### Input Sanitization
262
+
263
+ ```ruby
264
+ # Sanitize metadata before upsert
265
+ def sanitize_metadata(metadata)
266
+ metadata.reject { |k, _| k.to_s.match?(/password|secret|token|ssn|credit_card/i) }
267
+ end
268
+
269
+ vectors = [{
270
+ id: "vec1",
271
+ values: embedding,
272
+ metadata: sanitize_metadata(user_data)
273
+ }]
274
+
275
+ client.upsert(index: "my-index", vectors: vectors)
276
+ ```
277
+
278
+ ### Access Control
279
+
280
+ ```ruby
281
+ # Implement application-level access control
282
+ class VectorService
283
+ def query(user:, index:, vector:, top_k:)
284
+ # Check permissions
285
+ unless user.can_access?(index)
286
+ audit.log_authorization(
287
+ user_id: user.id,
288
+ resource: index,
289
+ allowed: false,
290
+ reason: "Insufficient permissions"
291
+ )
292
+ raise ForbiddenError, "Access denied"
293
+ end
294
+
295
+ # Log access
296
+ audit.log_access(
297
+ user_id: user.id,
298
+ operation: "query",
299
+ index: index,
300
+ result_count: top_k
301
+ )
302
+
303
+ client.query(index: index, vector: vector, top_k: top_k)
304
+ end
305
+ end
306
+ ```
307
+
308
+ ## Compliance
309
+
310
+ ### GDPR/Privacy
311
+
312
+ - **Data retention policies** - Implement automatic deletion
313
+ - **Right to deletion** - Support user data removal
314
+ - **Data encryption** - Encrypt sensitive metadata
315
+ - **Access logs** - Maintain audit trails
316
+
317
+ ### HIPAA/Healthcare
318
+
319
+ - **Encryption at rest** - Provider responsibility
320
+ - **Encryption in transit** - HTTPS enforced
321
+ - **Access controls** - Application-level
322
+ - **Audit logging** - Required for compliance
323
+
324
+ ### PCI-DSS
325
+
326
+ - **No card data in vectors** - Never store card numbers
327
+ - **Tokenization** - Use tokens instead of raw data
328
+ - **Access monitoring** - Audit all access
329
+
330
+ ## Security Checklist
331
+
332
+ - [ ] API keys stored in environment variables or vaults
333
+ - [ ] No API keys in version control
334
+ - [ ] Different keys for dev/staging/production
335
+ - [ ] Credential rotation implemented
336
+ - [ ] Audit logging enabled
337
+ - [ ] HTTPS/TLS enforced
338
+ - [ ] Input sanitization implemented
339
+ - [ ] Access controls in place
340
+ - [ ] Rate limiting configured
341
+ - [ ] Error monitoring setup
342
+ - [ ] Security alerts configured
343
+
344
+ ## Related
345
+
346
+ - [SECURITY.md](https://github.com/stokry/vectra/blob/main/SECURITY.md) - Security policy
347
+ - [Monitoring Guide]({{ site.baseurl }}/guides/monitoring) - Security monitoring
348
+ - [Performance Guide]({{ site.baseurl }}/guides/performance) - Rate limiting