cipherion 0.1.0__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.
@@ -0,0 +1,72 @@
1
+ .env
2
+ .venv
3
+ __pycache
4
+
5
+
6
+ # Byte-compiled / optimized / DLL files
7
+ __pycache__/
8
+ *.py[cod]
9
+ *$py.class
10
+
11
+ # C extensions
12
+ *.so
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ build/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ *.egg-info/
22
+ *.egg
23
+ MANIFEST
24
+
25
+ # Installer logs
26
+ pip-log.txt
27
+ pip-delete-this-directory.txt
28
+
29
+ # Unit test / coverage reports
30
+ htmlcov/
31
+ .tox/
32
+ .nox/
33
+ .coverage
34
+ .coverage.*
35
+ .cache
36
+ pytest_cache/
37
+ nosetests.xml
38
+ coverage.xml
39
+ *.cover
40
+ *.py,cover
41
+ .hypothesis/
42
+
43
+ # Type checkers
44
+ .mypy_cache/
45
+ .pyre/
46
+ .pytype/
47
+
48
+ # Virtual environments
49
+ .venv/
50
+ venv/
51
+ env/
52
+ ENV/
53
+
54
+ # IDEs and editors
55
+ .vscode/
56
+ .idea/
57
+ *.swp
58
+ *.swo
59
+
60
+ # OS files
61
+ .DS_Store
62
+ Thumbs.db
63
+
64
+ # PyPI API tokens (IMPORTANT)
65
+ .pypirc
66
+
67
+ # Logs
68
+ *.log
69
+
70
+ # Temporary files
71
+ *.tmp
72
+ *.bak
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cipherion
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.
@@ -0,0 +1,419 @@
1
+ Metadata-Version: 2.4
2
+ Name: cipherion
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the Cipherion field-level encryption API
5
+ Project-URL: Homepage, https://github.com/OneBoatSolutions/Cipherion-Python-SDK
6
+ Project-URL: Documentation, https://docs.cipherion.in
7
+ Project-URL: Repository, https://github.com/OneBoatSolutions/Cipherion-Python-SDK
8
+ Project-URL: Bug Tracker, https://github.com/OneBoatSolutions/Cipherion-Python-SDK/issues
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: cipherion,cryptography,encryption,field-level-encryption,security
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Security :: Cryptography
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: python-dotenv>=1.0.0
24
+ Requires-Dist: requests>=2.31.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
27
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
30
+ Requires-Dist: types-requests>=2.31.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Cipherion Python SDK
34
+
35
+ [![PyPI version](https://img.shields.io/pypi/v/cipherion.svg)](https://pypi.org/project/cipherion/)
36
+ [![Python versions](https://img.shields.io/pypi/pyversions/cipherion.svg)](https://pypi.org/project/cipherion/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
38
+ [![Typed](https://img.shields.io/badge/typing-fully%20typed-brightgreen)](https://mypy.readthedocs.io/)
39
+
40
+ A Python SDK for the [Cipherion](https://cipherion.io) field-level encryption API. Encrypt and decrypt individual strings, deeply-nested objects, and entire datasets, all through a single, fully-typed interface.
41
+
42
+ ---
43
+
44
+ ## Table of Contents
45
+
46
+ - [Features](#features)
47
+ - [Requirements](#requirements)
48
+ - [Installation](#installation)
49
+ - [Configuration](#configuration)
50
+ - [Usage](#usage)
51
+ - [Simple Encrypt / Decrypt](#simple-encrypt--decrypt)
52
+ - [Deep Encrypt / Decrypt](#deep-encrypt--decrypt)
53
+ - [Bulk Migration](#bulk-migration)
54
+ - [Runtime Config Updates](#runtime-config-updates)
55
+ - [Error Handling](#error-handling)
56
+ - [Logging](#logging)
57
+ - [Project Structure](#project-structure)
58
+ - [Development](#development)
59
+ - [License](#license)
60
+
61
+ ---
62
+
63
+ ## Features
64
+
65
+ - **Simple encryption** — encrypt and decrypt plain strings in one call
66
+ - **Deep encryption** — recursively encrypt every value in a nested dict or list while preserving its shape
67
+ - **Bulk migration** — process thousands of records in parallel batches with progress callbacks, per-item error isolation, and automatic retries
68
+ - **Automatic retries** — exponential back-off with jitter for network errors, rate limits, and 5xx responses
69
+ - **Structured logging** — rotating log files with sensitive-value redaction built in
70
+ - **Fully typed** — complete `py.typed` support for mypy and Pyright
71
+
72
+ ---
73
+
74
+ ## Requirements
75
+
76
+ - Python **3.10+**
77
+ - A [Cipherion](https://cipherion.io) account with a project ID and API key
78
+
79
+ ---
80
+
81
+ ## Installation
82
+
83
+ ```bash
84
+ pip install cipherion
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Configuration
90
+
91
+ ### Option A — Pass a config dict
92
+
93
+ ```python
94
+ from cipherion import CipherionClient
95
+
96
+ client = CipherionClient({
97
+ "base_url": "https://api.cipherion.io",
98
+ "project_id": "proj_abc123",
99
+ "api_key": "ak_live_...",
100
+ "passphrase": "my-strong-passphrase", # minimum 12 characters
101
+ })
102
+ ```
103
+
104
+ ### Option B — Environment variables
105
+
106
+ Create a `.env` file (or export the variables directly):
107
+
108
+ ```dotenv
109
+ CIPHERION_BASE_URL=https://api.cipherion.io
110
+ CIPHERION_PROJECT_ID=proj_abc123
111
+ CIPHERION_API_KEY=ak_live_...
112
+ CIPHERION_PASSPHRASE=my-strong-passphrase
113
+ ```
114
+
115
+ Then initialise with no arguments:
116
+
117
+ ```python
118
+ client = CipherionClient() # reads from environment automatically
119
+ ```
120
+
121
+ ### All configuration options
122
+
123
+ | Option | Type | Default | Description |
124
+ |---|---|---|---|
125
+ | `base_url` | `str` | env var | Cipherion API base URL |
126
+ | `project_id` | `str` | env var | Your project identifier |
127
+ | `api_key` | `str` | env var | API authentication key |
128
+ | `passphrase` | `str` | env var | Encryption passphrase (≥ 12 chars) |
129
+ | `timeout` | `int` | `30000` | Request timeout in milliseconds |
130
+ | `retries` | `int` | `3` | Max retry attempts per request |
131
+ | `log_level` | `str` | `"info"` | One of `"debug"`, `"info"`, `"warn"`, `"error"` |
132
+ | `enable_logging` | `bool` | `True` | Write structured logs to `cipherion-logs/` |
133
+
134
+ ---
135
+
136
+ ## Usage
137
+
138
+ ### Simple Encrypt / Decrypt
139
+
140
+ Use `encrypt` and `decrypt` for any plain string value — API tokens, passwords, PII snippets, and so on.
141
+
142
+ ```python
143
+ # Encrypt
144
+ ciphertext = client.encrypt("alice@example.com")
145
+ print(ciphertext) # "enc:v1:AbCdEf..."
146
+
147
+ # Decrypt
148
+ email = client.decrypt(ciphertext)
149
+ print(email) # "alice@example.com"
150
+ ```
151
+
152
+ ---
153
+
154
+ ### Deep Encrypt / Decrypt
155
+
156
+ `deep_encrypt` recurses into any dict or list and encrypts every leaf value while preserving the original structure. `deep_decrypt` reverses the process.
157
+
158
+ #### Basic example
159
+
160
+ ```python
161
+ user = {
162
+ "id": 42,
163
+ "name": "Alice",
164
+ "email": "alice@example.com",
165
+ "address": {
166
+ "street": "123 Main St",
167
+ "zip": "90210",
168
+ },
169
+ }
170
+
171
+ result = client.deep_encrypt(user)
172
+ encrypted_user = result["encrypted"]
173
+
174
+ # encrypted_user looks like:
175
+ # {
176
+ # "id": "enc:v1:...",
177
+ # "name": "enc:v1:...",
178
+ # "email": "enc:v1:...",
179
+ # "address": {
180
+ # "street": "enc:v1:...",
181
+ # "zip": "enc:v1:...",
182
+ # },
183
+ # }
184
+ ```
185
+
186
+ #### Excluding fields
187
+
188
+ Pass an `ExclusionOptions` object to skip fields you want to leave in the clear:
189
+
190
+ ```python
191
+ from cipherion import ExclusionOptions
192
+
193
+ result = client.deep_encrypt(
194
+ user,
195
+ options=ExclusionOptions(
196
+ exclude_fields=["id"], # exact field name match
197
+ exclude_patterns=["created_*", "*_at"], # glob-style pattern match
198
+ ),
199
+ )
200
+ # "id" and any field matching the patterns are left unencrypted
201
+ ```
202
+
203
+ #### Decrypting back
204
+
205
+ ```python
206
+ decrypted = client.deep_decrypt(encrypted_user)
207
+ original = decrypted["data"]
208
+ # original == user ✓
209
+ ```
210
+
211
+ #### Graceful decryption failures
212
+
213
+ When processing data you don't fully control, use `fail_gracefully` to leave undecryptable fields as-is rather than raising an error:
214
+
215
+ ```python
216
+ decrypted = client.deep_decrypt(
217
+ partially_encrypted_payload,
218
+ options=ExclusionOptions(fail_gracefully=True),
219
+ )
220
+ ```
221
+
222
+ #### `ExclusionOptions` reference
223
+
224
+ | Field | Type | Description |
225
+ |---|---|---|
226
+ | `exclude_fields` | `list[str]` | Exact field names to leave unencrypted |
227
+ | `exclude_patterns` | `list[str]` | Glob patterns — e.g. `"*_id"`, `"meta_*"` |
228
+ | `fail_gracefully` | `bool` | Skip undecryptable fields instead of raising (`deep_decrypt` only) |
229
+
230
+ ---
231
+
232
+ ### Bulk Migration
233
+
234
+ `migrate_encrypt` and `migrate_decrypt` process a list of records in parallel batches. Each item is handled independently — a failure on one record never aborts the rest.
235
+
236
+ ```python
237
+ from cipherion import MigrationOptions
238
+
239
+ # Imagine these came from a database export
240
+ records = [
241
+ {"id": 1, "ssn": "111-22-3333", "dob": "1990-01-15"},
242
+ {"id": 2, "ssn": "444-55-6666", "dob": "1985-07-04"},
243
+ # ... thousands more
244
+ ]
245
+
246
+ result = client.migrate_encrypt(
247
+ records,
248
+ options=MigrationOptions(
249
+ batch_size=50, # records per parallel batch
250
+ delay_between_batches=250, # ms pause between batches (avoids rate limits)
251
+ max_retries=3, # per-item retry attempts
252
+ on_progress=lambda p: print(
253
+ f"Progress: {p.successful}/{p.total} "
254
+ f"({p.percentage:.1f}%) failed={p.failed}"
255
+ ),
256
+ on_error=lambda err, item: print(f"[WARN] item {item['id']} failed: {err}"),
257
+ ),
258
+ )
259
+
260
+ print(result.summary)
261
+ # MigrationProgress(total=1000, processed=1000, successful=997, failed=3, percentage=99.7)
262
+
263
+ # Work with results
264
+ for encrypted_record in result.successful:
265
+ db.save(encrypted_record["encrypted"])
266
+
267
+ for failure in result.failed:
268
+ logger.error("Migration failure", extra={"item": failure.item, "error": str(failure.error)})
269
+ ```
270
+
271
+ Decrypting a previously migrated dataset works the same way:
272
+
273
+ ```python
274
+ result = client.migrate_decrypt(encrypted_records)
275
+ ```
276
+
277
+ #### `MigrationOptions` reference
278
+
279
+ | Field | Type | Default | Description |
280
+ |---|---|---|---|
281
+ | `batch_size` | `int` | `10` | Records per batch (clamped 1–100) |
282
+ | `delay_between_batches` | `int` | `1000` | Milliseconds to wait between batches |
283
+ | `max_retries` | `int` | `3` | Per-item retry attempts (clamped 1–10) |
284
+ | `on_progress` | `Callable` | `None` | Called after every record with a `MigrationProgress` snapshot |
285
+ | `on_error` | `Callable` | `None` | Called when an individual item fails |
286
+ | `exclusion_options` | `ExclusionOptions` | `None` | Fields/patterns to skip during deep encrypt/decrypt |
287
+
288
+ ---
289
+
290
+ ### Runtime Config Updates
291
+
292
+ Read or change non-sensitive settings without restarting:
293
+
294
+ ```python
295
+ # Inspect current config (api_key and passphrase are never returned)
296
+ print(client.get_config())
297
+ # {
298
+ # "base_url": "https://api.cipherion.io",
299
+ # "project_id": "proj_abc123",
300
+ # "timeout": 30000,
301
+ # "retries": 3,
302
+ # "log_level": "info",
303
+ # "enable_logging": True,
304
+ # }
305
+
306
+ # Increase timeout and switch to debug logging at runtime
307
+ client.update_config({"timeout": 60_000, "log_level": "debug"})
308
+ ```
309
+
310
+ > **Note:** `api_key` and `passphrase` cannot be changed after initialisation. Create a new client instance instead.
311
+
312
+ ---
313
+
314
+ ## Error Handling
315
+
316
+ Every method raises `CipherionError` on failure. It carries enough context to decide whether to retry, what to show the user, and what to log:
317
+
318
+ ```python
319
+ from cipherion import CipherionClient, CipherionError
320
+
321
+ try:
322
+ ciphertext = client.encrypt("sensitive value")
323
+
324
+ except CipherionError as e:
325
+ print(e.status_code) # HTTP status (0 = network/connection error)
326
+ print(e.message) # Technical error message
327
+ print(e.details) # Optional additional context from the API
328
+ print(e.timestamp) # ISO-8601 UTC timestamp of the error
329
+
330
+ print(e.get_user_message()) # Safe, friendly string for end-user display
331
+ print(e.is_retryable()) # True for 5xx, 429, and network errors
332
+ print(e.to_json()) # Dict safe to pass to your logging pipeline
333
+ ```
334
+
335
+ #### Status code quick-reference
336
+
337
+ | Code | Meaning | `is_retryable()` |
338
+ |---|---|---|
339
+ | `0` | Network / connection error | ✅ Yes |
340
+ | `400` | Bad request (invalid input) | ❌ No |
341
+ | `401` / `403` | Authentication / authorisation failure | ❌ No |
342
+ | `429` | Rate limit exceeded | ✅ Yes |
343
+ | `5xx` | Server-side error | ✅ Yes |
344
+
345
+ ---
346
+
347
+ ## Logging
348
+
349
+ The SDK writes two rotating log files under `cipherion-logs/`:
350
+
351
+ | File | Content |
352
+ |---|---|
353
+ | `combined.log` | All log levels |
354
+ | `error.log` | Errors only |
355
+
356
+ Files rotate at **10 MB** with up to **5 backups** kept. A colourised console handler is added automatically unless `CIPHERION_ENV=production`.
357
+
358
+ Sensitive keys (`passphrase`, `api_key`, `token`, `secret`, `authorization`, `credential`) are automatically redacted to `[REDACTED]` before any value reaches a log handler. String values longer than 100 characters are truncated.
359
+
360
+ To disable file logging entirely:
361
+
362
+ ```python
363
+ client = CipherionClient({"enable_logging": False, ...})
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Project Structure
369
+
370
+ ```
371
+ cipherion-python-sdk/
372
+ ├── src/
373
+ │ └── cipherion/
374
+ │ ├── __init__.py ← public API surface
375
+ │ ├── client/
376
+ │ │ └── cipherion_client.py
377
+ │ ├── errors/
378
+ │ │ └── cipherion_error.py
379
+ │ ├── types/
380
+ │ │ ├── api.py ← API request / response dataclasses
381
+ │ │ └── client.py ← config & migration dataclasses
382
+ │ └── utils/
383
+ │ ├── http.py ← requests wrapper with retry logic
384
+ │ ├── logger.py ← structured rotating logger
385
+ │ ├── migration.py ← parallel batch processor
386
+ │ └── validation.py ← input validators
387
+ ├── examples/
388
+ │ └── basic_usage.py
389
+ ├── tests/
390
+ ├── pyproject.toml
391
+ └── README.md
392
+ ```
393
+
394
+ ---
395
+
396
+ ## Development
397
+
398
+ ```bash
399
+ # Clone and install with dev dependencies
400
+ git clone https://github.com/OneBoatSolutions/Cipherion-Python-SDK
401
+ cd Cipherion-Python-SDK
402
+ pip install -e ".[dev]"
403
+
404
+ # Run the test suite
405
+ pytest
406
+
407
+ # Type-check
408
+ mypy src/cipherion
409
+
410
+ # Lint and auto-format
411
+ ruff check src/
412
+ ruff format src/
413
+ ```
414
+
415
+ ---
416
+
417
+ ## License
418
+
419
+ MIT © Cipherion