cvt-sdk 0.1.3__tar.gz

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.
Files changed (31) hide show
  1. cvt_sdk-0.1.3/LICENSE +21 -0
  2. cvt_sdk-0.1.3/PKG-INFO +439 -0
  3. cvt_sdk-0.1.3/README.md +410 -0
  4. cvt_sdk-0.1.3/cvt_sdk/__init__.py +1082 -0
  5. cvt_sdk-0.1.3/cvt_sdk/adapters/__init__.py +48 -0
  6. cvt_sdk-0.1.3/cvt_sdk/adapters/mock_adapter.py +358 -0
  7. cvt_sdk-0.1.3/cvt_sdk/adapters/requests_adapter.py +238 -0
  8. cvt_sdk-0.1.3/cvt_sdk/adapters/types.py +62 -0
  9. cvt_sdk-0.1.3/cvt_sdk/auto_register.py +222 -0
  10. cvt_sdk-0.1.3/cvt_sdk/producer/__init__.py +107 -0
  11. cvt_sdk-0.1.3/cvt_sdk/producer/adapters/__init__.py +11 -0
  12. cvt_sdk-0.1.3/cvt_sdk/producer/adapters/fastapi.py +344 -0
  13. cvt_sdk-0.1.3/cvt_sdk/producer/adapters/flask.py +304 -0
  14. cvt_sdk-0.1.3/cvt_sdk/producer/config.py +118 -0
  15. cvt_sdk-0.1.3/cvt_sdk/producer/producer.py +322 -0
  16. cvt_sdk-0.1.3/cvt_sdk/producer/testing.py +478 -0
  17. cvt_sdk-0.1.3/cvt_sdk/proto/__init__.py +73 -0
  18. cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2.py +127 -0
  19. cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2.pyi +472 -0
  20. cvt_sdk-0.1.3/cvt_sdk/proto/cvt_pb2_grpc.py +588 -0
  21. cvt_sdk-0.1.3/cvt_sdk.egg-info/PKG-INFO +439 -0
  22. cvt_sdk-0.1.3/cvt_sdk.egg-info/SOURCES.txt +29 -0
  23. cvt_sdk-0.1.3/cvt_sdk.egg-info/dependency_links.txt +1 -0
  24. cvt_sdk-0.1.3/cvt_sdk.egg-info/requires.txt +8 -0
  25. cvt_sdk-0.1.3/cvt_sdk.egg-info/top_level.txt +1 -0
  26. cvt_sdk-0.1.3/pyproject.toml +66 -0
  27. cvt_sdk-0.1.3/setup.cfg +4 -0
  28. cvt_sdk-0.1.3/tests/test_auto_register.py +377 -0
  29. cvt_sdk-0.1.3/tests/test_contract_validator.py +460 -0
  30. cvt_sdk-0.1.3/tests/test_producer.py +571 -0
  31. cvt_sdk-0.1.3/tests/test_producer_testing.py +205 -0
cvt_sdk-0.1.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 CVT Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
cvt_sdk-0.1.3/PKG-INFO ADDED
@@ -0,0 +1,439 @@
1
+ Metadata-Version: 2.4
2
+ Name: cvt-sdk
3
+ Version: 0.1.3
4
+ Summary: Contract Validator Toolkit - Python SDK for validating HTTP interactions against OpenAPI schemas
5
+ Author: sahina
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sahina/cvt
8
+ Project-URL: Documentation, https://github.com/sahina/cvt/tree/main/sdks/python
9
+ Project-URL: Repository, https://github.com/sahina/cvt
10
+ Project-URL: Issues, https://github.com/sahina/cvt/issues
11
+ Keywords: openapi,contract-testing,grpc,api-validation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Testing
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: grpcio>=1.76.0
23
+ Requires-Dist: protobuf>=6.33.2
24
+ Provides-Extra: requests
25
+ Requires-Dist: requests>=2.32.0; extra == "requests"
26
+ Provides-Extra: all
27
+ Requires-Dist: requests>=2.32.0; extra == "all"
28
+ Dynamic: license-file
29
+
30
+ # Contract Validator Toolkit (CVT) - Python SDK
31
+
32
+ The **CVT Python SDK** allows you to validate HTTP interactions (requests and responses) against OpenAPI schemas using the CVT gRPC service.
33
+
34
+ > **Status**: Fully Implemented
35
+
36
+ ## Installation
37
+
38
+ ### From PyPI (recommended)
39
+
40
+ ```bash
41
+ pip install cvt-sdk
42
+ ```
43
+
44
+ Or with uv:
45
+
46
+ ```bash
47
+ uv add cvt-sdk
48
+ ```
49
+
50
+ With the optional requests adapter:
51
+
52
+ ```bash
53
+ pip install "cvt-sdk[requests]"
54
+ ```
55
+
56
+ ### From local source (development)
57
+
58
+ ```bash
59
+ # From the project root
60
+ pip install -e sdks/python
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ### Initialize and Register Schema
66
+
67
+ ```python
68
+ from cvt_sdk import ContractValidator
69
+
70
+ validator = ContractValidator(host="localhost:9550")
71
+
72
+ # Register from local file
73
+ validator.register_schema("my-schema", "path/to/openapi.json")
74
+
75
+ # Register from URL
76
+ validator.register_schema("petstore", "https://petstore.swagger.io/v2/swagger.json")
77
+ ```
78
+
79
+ ### Validate Interactions
80
+
81
+ ```python
82
+ from cvt_sdk import ContractValidator
83
+
84
+ validator = ContractValidator()
85
+
86
+ request = {
87
+ "method": "POST",
88
+ "path": "/users",
89
+ "body": {"username": "alice", "email": "alice@example.com"}
90
+ }
91
+
92
+ response = {
93
+ "status_code": 201
94
+ }
95
+
96
+ result = validator.validate(request, response)
97
+
98
+ if result.valid:
99
+ print("✅ Valid interaction")
100
+ else:
101
+ print(f"❌ Validation errors: {result.errors}")
102
+ ```
103
+
104
+ ## HTTP Adapter (Requests)
105
+
106
+ The SDK includes a Requests adapter for automatic HTTP traffic validation:
107
+
108
+ ```python
109
+ from cvt_sdk import ContractValidator
110
+ from cvt_sdk.adapters import ContractValidatingSession
111
+
112
+ validator = ContractValidator(host="localhost:9550")
113
+ validator.register_schema("petstore", "./openapi.json")
114
+
115
+ # Create a validating session (drop-in replacement for requests.Session)
116
+ session = ContractValidatingSession(
117
+ validator=validator,
118
+ schema_id="petstore",
119
+ auto_validate=True,
120
+ exclude_paths=["/health", "/metrics"],
121
+ on_validation_failure=lambda result, interaction: print(f"Failed: {result.errors}")
122
+ )
123
+
124
+ # All requests are now automatically validated
125
+ response = session.post("https://api.example.com/pets", json={"name": "Fluffy"})
126
+ ```
127
+
128
+ ### Adapter Options
129
+
130
+ - `auto_validate`: Enable/disable automatic validation (default: True)
131
+ - `include_paths`: List of paths/regex to include
132
+ - `exclude_paths`: List of paths/regex to exclude
133
+ - `on_validation_failure`: Custom error handler
134
+ - `get_interactions()`: Retrieve captured interactions
135
+ - `clear_interactions()`: Reset captured data
136
+
137
+ ## Producer Validation (Server-Side Middleware)
138
+
139
+ Validate incoming requests and outgoing responses against your OpenAPI contract on the server side.
140
+
141
+ > **Full documentation:** See [Validation Modes](../../docs/guides/validation-modes.mdx) for detailed behavior, rollout strategy, and metrics information.
142
+
143
+ ### Validation Modes
144
+
145
+ | Mode | Request Violation | Response Violation | Use Case |
146
+ | ----------------------- | ----------------- | ------------------ | ---------------------- |
147
+ | `ValidationMode.STRICT` | Reject with 400 | Log error | Production enforcement |
148
+ | `ValidationMode.WARN` | Log, continue | Log, continue | Gradual rollout |
149
+ | `ValidationMode.SHADOW` | Metrics only | Metrics only | Initial deployment |
150
+
151
+ **Recommended rollout:** `SHADOW` → `WARN` → `STRICT`. See [Recommended Rollout Strategy](../../docs/guides/validation-modes.mdx#recommended-rollout-strategy).
152
+
153
+ ### FastAPI / ASGI Middleware
154
+
155
+ ```python
156
+ from cvt_sdk import ContractValidator
157
+ from cvt_sdk.producer import ProducerConfig, ValidationMode
158
+ from cvt_sdk.producer.adapters import ASGIMiddleware
159
+
160
+ validator = ContractValidator(host="localhost:9550")
161
+ validator.register_schema("my-api", "./openapi.json")
162
+
163
+ config = ProducerConfig(
164
+ schema_id="my-api",
165
+ validator=validator,
166
+ mode=ValidationMode.STRICT,
167
+ exclude_paths=["/health", "/metrics"],
168
+ )
169
+
170
+ app.add_middleware(ASGIMiddleware, config=config)
171
+ ```
172
+
173
+ ### Flask / WSGI Middleware
174
+
175
+ ```python
176
+ from cvt_sdk.producer.adapters import WSGIMiddleware
177
+
178
+ app.wsgi_app = WSGIMiddleware(app.wsgi_app, config=config)
179
+ ```
180
+
181
+ ### Configuration Options
182
+
183
+ | Option | Type | Description |
184
+ | --------------------- | ---------------- | ------------------------------------------ |
185
+ | `schema_id` | `str` | Schema ID to validate against |
186
+ | `validator` | `Validator` | ContractValidator instance |
187
+ | `mode` | `ValidationMode` | `STRICT`, `WARN`, or `SHADOW` |
188
+ | `exclude_paths` | `list[str]` | Paths to skip validation (e.g., `/health`) |
189
+ | `include_paths` | `list[str]` | Only validate matching paths |
190
+ | `validate_response` | `bool` | Enable response validation (default: True) |
191
+ | `on_validation_error` | `Callable` | Custom error handler callback |
192
+
193
+ ## Breaking Change Detection
194
+
195
+ Detect breaking changes between OpenAPI schema versions before deployment:
196
+
197
+ ```python
198
+ from cvt_sdk import ContractValidator
199
+
200
+ validator = ContractValidator(host="localhost:9550")
201
+
202
+ # Register both schema versions
203
+ validator.register_schema_with_version("my-api", "./openapi-v1.json", "1.0.0")
204
+ validator.register_schema_with_version("my-api", "./openapi-v2.json", "2.0.0")
205
+
206
+ # Compare versions
207
+ result = validator.compare_schemas("my-api", "1.0.0", "2.0.0")
208
+
209
+ if not result.compatible:
210
+ print("Breaking changes detected:")
211
+ for change in result.breaking_changes:
212
+ print(f"- [{change.type}] {change.description}")
213
+ if change.path:
214
+ print(f" Path: {change.method} {change.path}")
215
+ sys.exit(1) # Fail CI build
216
+ ```
217
+
218
+ ### Breaking Change Types
219
+
220
+ | Type | Description |
221
+ | ---------------------- | ------------------------------------- |
222
+ | `ENDPOINT_REMOVED` | An endpoint was removed |
223
+ | `REQUIRED_FIELD_ADDED` | A required field was added to request |
224
+ | `FIELD_TYPE_CHANGED` | A field's type was changed |
225
+ | `ENUM_VALUE_REMOVED` | An allowed enum value was removed |
226
+
227
+ See `examples/breaking_changes.py` for a complete example.
228
+
229
+ ## Producer Testing
230
+
231
+ Test that your API handlers return responses matching your OpenAPI specification.
232
+
233
+ ### ProducerTestKit
234
+
235
+ ```python
236
+ from cvt_sdk.producer import ProducerTestKit, TestConfig, TestResponseData
237
+
238
+ test_kit = ProducerTestKit(TestConfig(
239
+ schema_id="user-api",
240
+ server_address="localhost:9550",
241
+ ))
242
+
243
+ # Validate handler response
244
+ result = test_kit.validate_response(
245
+ method="GET",
246
+ path="/users/123",
247
+ response=TestResponseData(
248
+ status_code=200,
249
+ body={"id": "123", "name": "Alice", "email": "alice@example.com"},
250
+ ),
251
+ )
252
+
253
+ assert result.valid
254
+
255
+ # Don't forget to close
256
+ test_kit.close()
257
+ ```
258
+
259
+ ### Consumer Registry
260
+
261
+ Track which services depend on your API:
262
+
263
+ ```python
264
+ # Register a consumer after successful contract tests
265
+ consumer = validator.register_consumer(
266
+ consumer_id="order-service",
267
+ consumer_version="2.1.0",
268
+ schema_id="user-api",
269
+ schema_version="1.0.0",
270
+ environment="prod",
271
+ used_endpoints=[
272
+ {"method": "GET", "path": "/users/{id}", "used_fields": ["id", "email"]},
273
+ ],
274
+ )
275
+
276
+ # List all consumers of a schema
277
+ consumers = validator.list_consumers(schema_id="user-api", environment="prod")
278
+
279
+ # Deregister a consumer
280
+ validator.deregister_consumer("order-service", "user-api", "prod")
281
+ ```
282
+
283
+ ### Deployment Safety (can-i-deploy)
284
+
285
+ Check if a new schema version can be safely deployed:
286
+
287
+ ```python
288
+ result = validator.can_i_deploy(
289
+ schema_id="user-api",
290
+ new_version="2.0.0",
291
+ environment="prod",
292
+ )
293
+
294
+ if not result.safe_to_deploy:
295
+ print(f"Cannot deploy: {result.summary}")
296
+ for consumer in result.affected_consumers:
297
+ if consumer.will_break:
298
+ print(f"- {consumer.consumer_id} will break")
299
+ sys.exit(1)
300
+ ```
301
+
302
+ See [Producer Testing Guide](../../docs/guides/producer-testing.mdx) for complete documentation.
303
+
304
+ ## Security Configuration
305
+
306
+ ### TLS
307
+
308
+ ```python
309
+ validator = ContractValidator(
310
+ host="localhost:9550",
311
+ tls_enabled=True,
312
+ tls_root_cert="./certs/ca.crt",
313
+ tls_client_cert="./certs/client.crt", # For mTLS
314
+ tls_client_key="./certs/client.key" # For mTLS
315
+ )
316
+ ```
317
+
318
+ ### API Key Authentication
319
+
320
+ ```python
321
+ validator = ContractValidator(
322
+ host="localhost:9550",
323
+ api_key="your-api-key-here"
324
+ )
325
+ ```
326
+
327
+ ## Prerequisites
328
+
329
+ Ensure the CVT gRPC server is running (default: `localhost:9550`).
330
+
331
+ ## Testing
332
+
333
+ The Python SDK includes tests covering:
334
+
335
+ - Client initialization and configuration
336
+ - Schema registration
337
+ - Validation requests and responses
338
+ - Error handling
339
+
340
+ ### Running Tests
341
+
342
+ ```bash
343
+ # Install dependencies
344
+ uv sync
345
+
346
+ # Run all tests
347
+ uv run pytest
348
+
349
+ # Run tests with coverage
350
+ uv run pytest --cov=cvt_sdk --cov-report=html
351
+
352
+ # View coverage report
353
+ open htmlcov/index.html
354
+
355
+ # Run specific test file
356
+ uv run pytest tests/test_validator.py
357
+
358
+ # Run with verbose output
359
+ uv run pytest -v -s
360
+ ```
361
+
362
+ ### Test Structure
363
+
364
+ ```shell
365
+ tests/
366
+ ├── test_validator.py # Main SDK test suite
367
+ ├── test_registration.py # Schema registration tests
368
+ └── conftest.py # Test fixtures
369
+ ```
370
+
371
+ ### Writing Tests
372
+
373
+ Example test using pytest:
374
+
375
+ ```python
376
+ import pytest
377
+ from cvt_sdk import ContractValidator
378
+
379
+ @pytest.fixture
380
+ def validator():
381
+ """Create validator instance for testing."""
382
+ v = ContractValidator(host="localhost:9550")
383
+ yield v
384
+ v.close()
385
+
386
+ def test_validate_correct_interaction(validator):
387
+ """Test validation of a correct interaction."""
388
+ validator.register_schema("test", "tests/fixtures/openapi.json")
389
+
390
+ result = validator.validate(
391
+ request={"method": "GET", "path": "/users"},
392
+ response={"status_code": 200, "body": []}
393
+ )
394
+
395
+ assert result.valid is True
396
+
397
+ def test_validate_incorrect_interaction(validator):
398
+ """Test validation of an incorrect interaction."""
399
+ validator.register_schema("test", "tests/fixtures/openapi.json")
400
+
401
+ result = validator.validate(
402
+ request={"method": "GET", "path": "/users"},
403
+ response={"status_code": 500} # Should be 200
404
+ )
405
+
406
+ assert result.valid is False
407
+ assert len(result.errors) > 0
408
+ ```
409
+
410
+ ### Coverage
411
+
412
+ The SDK targets 60%+ test coverage.
413
+
414
+ ## Development
415
+
416
+ ```bash
417
+ # Install development dependencies
418
+ uv sync --all-extras
419
+
420
+ # Run linter
421
+ uv run ruff check cvt_sdk
422
+
423
+ # Format code
424
+ uv run ruff format cvt_sdk
425
+
426
+ # Type checking
427
+ uv run mypy cvt_sdk
428
+
429
+ # Build package
430
+ uv build
431
+ ```
432
+
433
+ ## Contributing
434
+
435
+ Contributions are welcome!
436
+
437
+ ## License
438
+
439
+ MIT License