cinchdb 0.1.14__py3-none-any.whl → 0.1.15__py3-none-any.whl
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.
- cinchdb/__init__.py +5 -1
- cinchdb/cli/commands/__init__.py +2 -1
- cinchdb/cli/commands/data.py +350 -0
- cinchdb/cli/commands/index.py +2 -2
- cinchdb/cli/commands/tenant.py +47 -0
- cinchdb/cli/main.py +3 -6
- cinchdb/core/connection.py +12 -17
- cinchdb/core/database.py +207 -70
- cinchdb/core/path_utils.py +1 -1
- cinchdb/infrastructure/metadata_connection_pool.py +0 -1
- cinchdb/infrastructure/metadata_db.py +15 -1
- cinchdb/managers/branch.py +1 -1
- cinchdb/managers/data.py +189 -13
- cinchdb/managers/index.py +1 -2
- cinchdb/managers/query.py +0 -1
- cinchdb/managers/table.py +30 -5
- cinchdb/managers/tenant.py +89 -149
- cinchdb/plugins/__init__.py +17 -0
- cinchdb/plugins/base.py +99 -0
- cinchdb/plugins/decorators.py +45 -0
- cinchdb/plugins/manager.py +178 -0
- {cinchdb-0.1.14.dist-info → cinchdb-0.1.15.dist-info}/METADATA +15 -24
- {cinchdb-0.1.14.dist-info → cinchdb-0.1.15.dist-info}/RECORD +26 -23
- cinchdb/security/__init__.py +0 -1
- cinchdb/security/encryption.py +0 -108
- {cinchdb-0.1.14.dist-info → cinchdb-0.1.15.dist-info}/WHEEL +0 -0
- {cinchdb-0.1.14.dist-info → cinchdb-0.1.15.dist-info}/entry_points.txt +0 -0
- {cinchdb-0.1.14.dist-info → cinchdb-0.1.15.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cinchdb
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.15
|
4
4
|
Summary: A Git-like SQLite database management system with branching and multi-tenancy
|
5
5
|
Project-URL: Homepage, https://github.com/russellromney/cinchdb
|
6
6
|
Project-URL: Documentation, https://russellromney.github.io/cinchdb
|
@@ -156,24 +156,16 @@ db.update("posts", post_id, {"content": "Updated content"})
|
|
156
156
|
- **Python SDK**: Core functionality for local development
|
157
157
|
- **CLI**: Full-featured command-line interface
|
158
158
|
|
159
|
-
## Security
|
159
|
+
## Security
|
160
160
|
|
161
|
-
|
161
|
+
CinchDB uses standard SQLite security features:
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
# Install encryption library
|
169
|
-
pip install pysqlcipher3
|
170
|
-
```
|
163
|
+
- **WAL mode**: Better concurrency and crash recovery
|
164
|
+
- **Foreign key constraints**: Enforced data integrity
|
165
|
+
- **File permissions**: Standard OS-level access control
|
166
|
+
- **Multi-tenant isolation**: Separate database files per tenant
|
171
167
|
|
172
|
-
|
173
|
-
- **Metadata**: Unencrypted for operational simplicity
|
174
|
-
- **Integration**: Transparent - no code changes needed
|
175
|
-
|
176
|
-
Works without encryption libraries - gracefully falls back to standard SQLite.
|
168
|
+
For production deployments, consider additional security measures at the infrastructure level.
|
177
169
|
|
178
170
|
## Development
|
179
171
|
|
@@ -186,14 +178,13 @@ make test
|
|
186
178
|
|
187
179
|
## Future
|
188
180
|
|
189
|
-
|
190
|
-
|
191
|
-
-
|
192
|
-
-
|
193
|
-
-
|
194
|
-
-
|
195
|
-
-
|
196
|
-
- leader-follower abilities for edge deployment
|
181
|
+
CinchDB focuses on being a simple, reliable SQLite management layer. Future development will prioritize:
|
182
|
+
|
183
|
+
- Remote API server improvements
|
184
|
+
- Better CLI user experience
|
185
|
+
- Performance optimizations
|
186
|
+
- Additional language SDKs (TypeScript, Go, etc.)
|
187
|
+
- Enhanced codegen features
|
197
188
|
|
198
189
|
|
199
190
|
## License
|
@@ -1,43 +1,44 @@
|
|
1
|
-
cinchdb/__init__.py,sha256=
|
1
|
+
cinchdb/__init__.py,sha256=qnBv5kpL4GJjNbQkp-nBcOgrsskwDr7WTnUPCGwg3zs,603
|
2
2
|
cinchdb/__main__.py,sha256=OpkDqn9zkTZhhYgvv_grswWLAHKbmxs4M-8C6Z5HfWY,85
|
3
3
|
cinchdb/config.py,sha256=gocjMnYKLWhgvnteo6zprgwtK6Oevoxq547J_v-C9Ns,5265
|
4
4
|
cinchdb/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
cinchdb/cli/main.py,sha256=
|
5
|
+
cinchdb/cli/main.py,sha256=x2bF19e0lY_0V3_tx6CO9M3AaFlII75bAdWaOg0ne_A,4587
|
6
6
|
cinchdb/cli/utils.py,sha256=InAGuo7uENvsfBQu6EKIbbiNXqmvg-BecLmhLvOz5qg,6485
|
7
|
-
cinchdb/cli/commands/__init__.py,sha256=
|
7
|
+
cinchdb/cli/commands/__init__.py,sha256=Wjj_cmfscb_mpC-yFXxWW0-pJoBlI-Vpunb37SARsTs,291
|
8
8
|
cinchdb/cli/commands/branch.py,sha256=Nz8YQYJ7lizSXEAv0usTx85TDOC-N5Ul9KIxN8JQtKc,17973
|
9
9
|
cinchdb/cli/commands/codegen.py,sha256=WsRWmXNTDuaLPyECW5psXM9zOQnKHpUiv8BJnBAjMII,6189
|
10
10
|
cinchdb/cli/commands/column.py,sha256=nUVgjYbxSobJR9CC-qdOvrCl1TgFySr-ctQb0djKZtQ,11676
|
11
|
+
cinchdb/cli/commands/data.py,sha256=tRXVeYCShVp5VKJ--Q_XzTokPE6G0gaHSad48iFHa3E,12662
|
11
12
|
cinchdb/cli/commands/database.py,sha256=A3ew8Z987a25dRxmY5XeoB-Ka6SXLKtWogj3XAKUNZE,7332
|
12
|
-
cinchdb/cli/commands/index.py,sha256=
|
13
|
+
cinchdb/cli/commands/index.py,sha256=qL3-UOk_cBLBNR4qK2uPTyFI7qAMxQSE7YtXFXNeSdg,6094
|
13
14
|
cinchdb/cli/commands/query.py,sha256=XW_YL6M5IYHHHMpVB5p-M01kawFxwDOK5B5hGIy_BA8,5044
|
14
15
|
cinchdb/cli/commands/remote.py,sha256=i07hfiAxgrROB9lVJVaKK_nWxT1SGiSbtFb4jvEwxEo,4445
|
15
16
|
cinchdb/cli/commands/table.py,sha256=K233WOV102-g6QlHhL97FhfiGz67zIctbxZblAjY4Lg,10516
|
16
|
-
cinchdb/cli/commands/tenant.py,sha256=
|
17
|
+
cinchdb/cli/commands/tenant.py,sha256=snpMc9Jk2uGmEJCKP39zD26BZLYBhiRxP2M5oGyz0rQ,8309
|
17
18
|
cinchdb/cli/commands/view.py,sha256=ZmS1IW7idzzHAXmgVyY3C4IQRo7toHb6fHNFY_tQJjI,6385
|
18
19
|
cinchdb/cli/handlers/__init__.py,sha256=f2f-Cc96rSBLbVsiIbf-b4pZCKZoHfmhNEvnZ0OurRs,131
|
19
20
|
cinchdb/cli/handlers/codegen_handler.py,sha256=i5we_AbiUW3zfO6pIKWxvtO8OvOqz3H__4xPmTLEuQM,6524
|
20
21
|
cinchdb/core/__init__.py,sha256=iNlT0iO9cM0HLoYwzBavUBoXRh1Tcnz1l_vfbwVxK_Q,246
|
21
|
-
cinchdb/core/connection.py,sha256=
|
22
|
-
cinchdb/core/database.py,sha256=
|
22
|
+
cinchdb/core/connection.py,sha256=FdYVQuoFYo7B0JSHfCTZFTq3DkM_NWHF4ei-fMyyEMI,5171
|
23
|
+
cinchdb/core/database.py,sha256=K5zPG8wXdh9-jAg69QZ7ImE0u3qAuvCDulfAx1fOq5U,33307
|
23
24
|
cinchdb/core/initializer.py,sha256=CAzq947plgEF-KXV-PD-ycJ8Zy4zXCQqCrmQ0-pV0i4,14474
|
24
25
|
cinchdb/core/maintenance.py,sha256=PAgrSL7Cj9p3rKHV0h_L7gupN6nLD0-5eQpJZNiqyEs,2097
|
25
|
-
cinchdb/core/path_utils.py,sha256=
|
26
|
-
cinchdb/infrastructure/metadata_connection_pool.py,sha256=
|
27
|
-
cinchdb/infrastructure/metadata_db.py,sha256=
|
26
|
+
cinchdb/core/path_utils.py,sha256=Va4y2Dkd5QI6FI5h1ePyVH5pwr7tzRpYZLA4KEpDV0Q,4874
|
27
|
+
cinchdb/infrastructure/metadata_connection_pool.py,sha256=PeVsyuZKdI3Y7_InWMOn9HcSNhE0MVcP7I7wAj9esmI,4859
|
28
|
+
cinchdb/infrastructure/metadata_db.py,sha256=t3WDyE9SjWhTB2S0-v82AmWKXfl1571V_dv4Bv1-u10,15894
|
28
29
|
cinchdb/managers/__init__.py,sha256=ic61ZUdsg-muq0ETYO6fuZRQWF4j7l920PthTkt2QrE,808
|
29
|
-
cinchdb/managers/branch.py,sha256=
|
30
|
+
cinchdb/managers/branch.py,sha256=bEzl83mN9a9KW8AHC_w50QHtVdVPHUzEY-j9T2EAyR4,9445
|
30
31
|
cinchdb/managers/change_applier.py,sha256=cCgjUL6SJvrgVCCHAw0mAbGqZqKmMsLa0QbziSiuW68,15576
|
31
32
|
cinchdb/managers/change_comparator.py,sha256=08pwybpSt36cFwhZRSIkHynvFMUaLKEVwa8Ajn_R9yQ,6862
|
32
33
|
cinchdb/managers/change_tracker.py,sha256=U93BPnuGv8xSaO5qr_y5Q8ppKrVXygozdp5zUvLUqwg,5054
|
33
34
|
cinchdb/managers/codegen.py,sha256=1CfIwjgHnNDdjrq4SzQ9VE7DFgnWfk7RtpupBFUTqxk,21804
|
34
35
|
cinchdb/managers/column.py,sha256=i0EzDKavMvZeeaVrY9OVRNHOW60v0rUEkDjMtIs3PaE,20749
|
35
|
-
cinchdb/managers/data.py,sha256=
|
36
|
-
cinchdb/managers/index.py,sha256=
|
36
|
+
cinchdb/managers/data.py,sha256=9JAcJ1bxTKb15s0Zb0ATH4YW-6O03iSvyJnk1SsDq80,23170
|
37
|
+
cinchdb/managers/index.py,sha256=55_fafWd4lSju4Nw32B_1Fi1c2DPHxOgAhdsqcTR404,10343
|
37
38
|
cinchdb/managers/merge_manager.py,sha256=R8S2hLkLJg4hLDpeJTzjVkduZgqPOjXtYgOSJhTXXrE,15690
|
38
|
-
cinchdb/managers/query.py,sha256=
|
39
|
-
cinchdb/managers/table.py,sha256=
|
40
|
-
cinchdb/managers/tenant.py,sha256=
|
39
|
+
cinchdb/managers/query.py,sha256=hgNHda20PWMijbVRnjTKFGFBvBthep2fulkJEK1gkqU,8562
|
40
|
+
cinchdb/managers/table.py,sha256=GgwW_lVl9qmbr5x6JXDdvTBL_Ylkk4AzAD2HXQAOH0E,15246
|
41
|
+
cinchdb/managers/tenant.py,sha256=Oy60CKWTgDetF_SpbTFcS8bjumlNjEInd_APRg86f5M,31628
|
41
42
|
cinchdb/managers/view.py,sha256=v9gYtRufZyxywPKLGvIjvlUXcxYh9CLRArefu9QX6zk,7809
|
42
43
|
cinchdb/models/__init__.py,sha256=cZ-ailJ6qu44Iap5Rq555iB-_w9ufXVDBH3rDH-ojk0,622
|
43
44
|
cinchdb/models/base.py,sha256=7j4rlFTP5K9ZuF8vxwC7lMFEaL7O90NJ47Ig5i7ubcw,1320
|
@@ -48,13 +49,15 @@ cinchdb/models/project.py,sha256=6GMXUZUsEIebqQJgRXIthWzpWKuNNmJ3drgI1vFDrMo,644
|
|
48
49
|
cinchdb/models/table.py,sha256=nxf__C_YvDOW-6-vdOQ4xKmwWPZwgEdYw1I4mO_C44o,2955
|
49
50
|
cinchdb/models/tenant.py,sha256=wTvGoO_tQdtueVB0faZFVIhSjh_DNJzywflrUpngWTM,1072
|
50
51
|
cinchdb/models/view.py,sha256=q6j-jYzFJuhRJO87rKt6Uv8hOizHQx8xwoPKoH6XnNY,530
|
51
|
-
cinchdb/
|
52
|
-
cinchdb/
|
52
|
+
cinchdb/plugins/__init__.py,sha256=cpqB9y9sY6b9N5Gy9f78Zd2LJ-VpRnwEMS6GpQeW-KY,301
|
53
|
+
cinchdb/plugins/base.py,sha256=f0WOTVOLAqWLOSKI6GSNLhHN-wziBGWJza7z1QH0_MY,3038
|
54
|
+
cinchdb/plugins/decorators.py,sha256=vSTDC3TDywqDi8Da5aoKe7rRVA2EbTuJXAk6VV4BosM,1533
|
55
|
+
cinchdb/plugins/manager.py,sha256=1GcDhCwJvdkXSrgYe-jGA7g8NJNyYk0037_tMNugijE,6807
|
53
56
|
cinchdb/utils/__init__.py,sha256=yQQhEjndDiB2SUJybUmp9dvEOQKiR-GySe-WiCius5E,490
|
54
57
|
cinchdb/utils/name_validator.py,sha256=dyGX5bjlTFRA9EGrWRQKp6kR__HSV04hLV5VueJs4IQ,4027
|
55
58
|
cinchdb/utils/sql_validator.py,sha256=aWOGlPX0gBkuR6R1EBP2stbP4PHZuI6FUBi2Ljx7JUI,5815
|
56
|
-
cinchdb-0.1.
|
57
|
-
cinchdb-0.1.
|
58
|
-
cinchdb-0.1.
|
59
|
-
cinchdb-0.1.
|
60
|
-
cinchdb-0.1.
|
59
|
+
cinchdb-0.1.15.dist-info/METADATA,sha256=LdviGmMLfCUhko3Y6v9ViCFPVaX9KtiXv_ZwGhKwwlo,5958
|
60
|
+
cinchdb-0.1.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
61
|
+
cinchdb-0.1.15.dist-info/entry_points.txt,sha256=VBOIzvnGbkKudMCCmNORS3885QSyjZUVKJQ-Syqa62w,47
|
62
|
+
cinchdb-0.1.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
63
|
+
cinchdb-0.1.15.dist-info/RECORD,,
|
cinchdb/security/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
"""Security module for CinchDB encryption."""
|
cinchdb/security/encryption.py
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
"""Simple SQLite encryption using environment variables with KMS upgrade path."""
|
2
|
-
|
3
|
-
import os
|
4
|
-
import sqlite3
|
5
|
-
import logging
|
6
|
-
from pathlib import Path
|
7
|
-
|
8
|
-
logger = logging.getLogger(__name__)
|
9
|
-
|
10
|
-
|
11
|
-
class SQLiteEncryption:
|
12
|
-
"""Simple SQLite encryption with static keys and KMS upgrade path."""
|
13
|
-
|
14
|
-
def __init__(self):
|
15
|
-
# Encryption is optional for open source users
|
16
|
-
self.enabled = os.getenv("CINCH_ENCRYPT_DATA", "false").lower() == "true"
|
17
|
-
self._encryption_key = None
|
18
|
-
|
19
|
-
if self.enabled:
|
20
|
-
self._encryption_key = self._get_encryption_key()
|
21
|
-
|
22
|
-
def _get_encryption_key(self) -> str:
|
23
|
-
"""Get encryption key with future KMS support."""
|
24
|
-
|
25
|
-
# Future KMS support - check for KMS configuration first
|
26
|
-
kms_provider = os.getenv("CINCH_KMS_PROVIDER")
|
27
|
-
if kms_provider:
|
28
|
-
# TODO: Implement KMS key retrieval
|
29
|
-
# return self._get_key_from_kms(kms_provider)
|
30
|
-
logger.warning("KMS provider configured but not implemented yet")
|
31
|
-
|
32
|
-
# Require explicit key
|
33
|
-
static_key = os.getenv("CINCH_ENCRYPTION_KEY")
|
34
|
-
if static_key:
|
35
|
-
return static_key
|
36
|
-
|
37
|
-
# Fail fast if no key provided
|
38
|
-
raise ValueError(
|
39
|
-
"CINCH_ENCRYPTION_KEY environment variable is required when CINCH_ENCRYPT_DATA=true. "
|
40
|
-
"Generate a key with: python -c \"import secrets; print(secrets.token_urlsafe(32))\""
|
41
|
-
)
|
42
|
-
|
43
|
-
def get_connection(self, db_path: Path) -> sqlite3.Connection:
|
44
|
-
"""Get SQLite connection with optional encryption."""
|
45
|
-
# Connect with datetime parsing support
|
46
|
-
conn = sqlite3.connect(
|
47
|
-
str(db_path),
|
48
|
-
detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES,
|
49
|
-
)
|
50
|
-
|
51
|
-
if self.enabled and self._encryption_key:
|
52
|
-
try:
|
53
|
-
# Apply encryption key
|
54
|
-
conn.execute(f"PRAGMA key = '{self._encryption_key}'")
|
55
|
-
|
56
|
-
# Configure recommended cipher (ChaCha20-Poly1305) if supported
|
57
|
-
try:
|
58
|
-
conn.execute("PRAGMA cipher = 'chacha20'")
|
59
|
-
except sqlite3.OperationalError:
|
60
|
-
# Fallback to default cipher if ChaCha20 not available
|
61
|
-
logger.debug("ChaCha20 cipher not available, using default")
|
62
|
-
|
63
|
-
# Security hardening
|
64
|
-
conn.execute("PRAGMA temp_store = MEMORY") # Encrypt temp data
|
65
|
-
conn.execute("PRAGMA secure_delete = ON") # Overwrite deleted data
|
66
|
-
|
67
|
-
except sqlite3.OperationalError as e:
|
68
|
-
logger.error(f"Failed to apply encryption to {db_path}: {e}")
|
69
|
-
# Close connection and re-raise with helpful message
|
70
|
-
conn.close()
|
71
|
-
raise sqlite3.OperationalError(
|
72
|
-
f"Failed to apply encryption. Make sure SQLite3MultipleCiphers is installed. Error: {e}"
|
73
|
-
) from e
|
74
|
-
|
75
|
-
# Standard SQLite optimizations
|
76
|
-
conn.execute("PRAGMA journal_mode = WAL")
|
77
|
-
conn.execute("PRAGMA synchronous = NORMAL")
|
78
|
-
conn.execute("PRAGMA cache_size = -2000")
|
79
|
-
|
80
|
-
return conn
|
81
|
-
|
82
|
-
def is_encrypted(self, db_path: Path) -> bool:
|
83
|
-
"""Check if database file is encrypted."""
|
84
|
-
if not db_path.exists():
|
85
|
-
return False
|
86
|
-
|
87
|
-
try:
|
88
|
-
# Try to open without key
|
89
|
-
test_conn = sqlite3.connect(str(db_path))
|
90
|
-
test_conn.execute("SELECT name FROM sqlite_master LIMIT 1")
|
91
|
-
test_conn.close()
|
92
|
-
return False # Successfully opened = not encrypted
|
93
|
-
except sqlite3.DatabaseError:
|
94
|
-
return True # Failed to open = likely encrypted
|
95
|
-
|
96
|
-
def test_encryption_support(self) -> bool:
|
97
|
-
"""Test if SQLite encryption is available."""
|
98
|
-
try:
|
99
|
-
conn = sqlite3.connect(':memory:')
|
100
|
-
conn.execute("PRAGMA key = 'test'")
|
101
|
-
conn.close()
|
102
|
-
return True
|
103
|
-
except sqlite3.OperationalError:
|
104
|
-
return False
|
105
|
-
|
106
|
-
|
107
|
-
# Global instance for easy access
|
108
|
-
encryption = SQLiteEncryption()
|
File without changes
|
File without changes
|
File without changes
|