cortexdb-connectors 0.2.20__tar.gz → 0.2.22__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 (71) hide show
  1. cortexdb_connectors-0.2.22/LICENSE +202 -0
  2. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/PKG-INFO +114 -7
  3. cortexdb_connectors-0.2.22/README.md +254 -0
  4. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/__init__.py +40 -40
  5. cortexdb_connectors-0.2.22/cortexdb_connectors/base.py +2978 -0
  6. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/cli.py +850 -698
  7. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/confluence/__init__.py +655 -635
  8. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/discord/__init__.py +718 -717
  9. cortexdb_connectors-0.2.22/cortexdb_connectors/event_ledger.py +1145 -0
  10. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/freshdesk/__init__.py +719 -695
  11. cortexdb_connectors-0.2.22/cortexdb_connectors/github/__init__.py +1792 -0
  12. cortexdb_connectors-0.2.22/cortexdb_connectors/github/backfill.py +653 -0
  13. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/gitlab/__init__.py +741 -749
  14. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/google_workspace/__init__.py +1153 -1108
  15. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/hubspot/__init__.py +493 -489
  16. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/insights/__init__.py +40 -40
  17. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/insights/api.py +252 -252
  18. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/insights/detectors.py +803 -803
  19. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/insights/engine.py +308 -308
  20. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/intercom/__init__.py +645 -631
  21. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/jira/__init__.py +1365 -1099
  22. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/linear/__init__.py +734 -705
  23. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/notion/__init__.py +928 -913
  24. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/pagerduty/__init__.py +317 -298
  25. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/salesforce/__init__.py +397 -399
  26. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/servicenow/__init__.py +460 -460
  27. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/slack/__init__.py +1035 -1030
  28. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/state.py +523 -430
  29. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/teams/__init__.py +713 -657
  30. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/tldv/__init__.py +552 -485
  31. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/webhooks.py +1673 -1563
  32. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/worker.py +360 -307
  33. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors/zendesk/__init__.py +511 -496
  34. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/PKG-INFO +114 -7
  35. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/SOURCES.txt +7 -0
  36. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/pyproject.toml +92 -92
  37. cortexdb_connectors-0.2.22/tests/test_base.py +2267 -0
  38. cortexdb_connectors-0.2.22/tests/test_canonical_source_identity.py +499 -0
  39. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_connector_coverage.py +86 -86
  40. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_discord_normalize.py +153 -153
  41. cortexdb_connectors-0.2.22/tests/test_fingerprint_normalizers.py +551 -0
  42. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_freshdesk_findings_0_2_20.py +453 -449
  43. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_github.py +503 -432
  44. cortexdb_connectors-0.2.22/tests/test_github_backfill.py +1057 -0
  45. cortexdb_connectors-0.2.22/tests/test_github_findings_0_2_22.py +1130 -0
  46. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_ingest_e2e.py +139 -88
  47. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_jira_attachments.py +303 -265
  48. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_jira_findings_0_2_11.py +985 -660
  49. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_jira_findings_0_2_9.py +359 -341
  50. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_notion_comments.py +334 -318
  51. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_notion_findings_0_2_19.py +192 -192
  52. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_product_findings_0_2_12.py +205 -205
  53. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_product_findings_0_2_14.py +218 -218
  54. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_slack.py +296 -296
  55. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_slack_file_ingestion.py +602 -599
  56. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_slack_findings_0_2_16.py +368 -298
  57. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_slack_findings_0_2_17.py +540 -474
  58. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_streaming_cursor.py +188 -113
  59. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_tldv_findings_0_2_12.py +366 -353
  60. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_tldv_findings_0_2_15.py +402 -393
  61. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_webhooks.py +912 -661
  62. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/tests/test_webhooks_replay.py +160 -160
  63. cortexdb_connectors-0.2.20/README.md +0 -148
  64. cortexdb_connectors-0.2.20/cortexdb_connectors/base.py +0 -825
  65. cortexdb_connectors-0.2.20/cortexdb_connectors/github/__init__.py +0 -400
  66. cortexdb_connectors-0.2.20/tests/test_base.py +0 -416
  67. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/dependency_links.txt +0 -0
  68. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/entry_points.txt +0 -0
  69. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/requires.txt +0 -0
  70. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/cortexdb_connectors.egg-info/top_level.txt +0 -0
  71. {cortexdb_connectors-0.2.20 → cortexdb_connectors-0.2.22}/setup.cfg +0 -0
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortexdb-connectors
3
- Version: 0.2.20
4
- Summary: Data connectors for CortexDB — ingest from Slack, GitHub, GitLab, Jira, Linear, Confluence, Notion, PagerDuty, Discord, Teams, Google Workspace, Salesforce, HubSpot, Zendesk, Intercom, and ServiceNow into the v1 memory API.
3
+ Version: 0.2.22
4
+ Summary: Data connectors for CortexDB — ingest business-system data into the v1 memory API.
5
5
  Author-email: CortexDB Team <team@cortexdb.ai>
6
6
  License-Expression: Apache-2.0
7
7
  Project-URL: Homepage, https://cortexdb.ai
8
8
  Project-URL: Documentation, https://cortexdb.ai/docs/connectors/slack
9
- Project-URL: Repository, https://github.com/cortexdb/cortexdb
10
- Project-URL: Issues, https://github.com/cortexdb/cortexdb/issues
9
+ Project-URL: Support, https://cortexdb.ai/contact
11
10
  Keywords: ai,memory,connectors,etl,slack,github,jira,cortexdb
12
11
  Classifier: Development Status :: 4 - Beta
13
12
  Classifier: Environment :: Console
@@ -21,6 +20,7 @@ Classifier: Topic :: Database
21
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
21
  Requires-Python: >=3.10
23
22
  Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
24
  Requires-Dist: httpx>=0.27
25
25
  Requires-Dist: pydantic>=2.0
26
26
  Requires-Dist: croniter>=2.0
@@ -77,6 +77,7 @@ Requires-Dist: PyYAML>=6.0; extra == "all"
77
77
  Requires-Dist: starlette>=0.37; extra == "all"
78
78
  Requires-Dist: uvicorn>=0.29; extra == "all"
79
79
  Requires-Dist: python-multipart>=0.0.9; extra == "all"
80
+ Dynamic: license-file
80
81
 
81
82
  # cortexdb-connectors
82
83
 
@@ -123,11 +124,37 @@ Or set env vars:
123
124
  export CORTEXDB_URL=https://api-v1.cortexdb.ai
124
125
  export CORTEXDB_API_KEY=v4.public...
125
126
  export CORTEXDB_ACTOR=user:u_019e...
127
+ export CORTEXDB_TENANT_ID=acme # optional assertion; verified via whoami
126
128
  export CORTEXDB_SCOPE_TEMPLATE='org:acme/source:{source}' # optional
129
+ export CORTEXDB_SOURCE_INSTANCE_ID='acme-slack-workspace' # see below
127
130
  ```
128
131
 
129
132
  `{source}` (and `{scope}`, `{namespace}`, `{actor}`, `{entity.<type>}`) get filled in per event. (`{tenant}` is still accepted as a legacy alias of `{scope}`.)
130
133
 
134
+ **Self-hosted server with a static `CORTEX_API_KEY`:** that key has no `sub`
135
+ claim, and the server runs a request without `X-Cortex-Actor` as `user:local`.
136
+ When `CORTEXDB_ACTOR` is unset, `cortexdb-sync sync|watch` and the Docker
137
+ worker ask `GET /v1/auth/whoami` (without the header) and adopt `user:local`
138
+ only when the server confirms a static key (0.2.22+). With a PASETO/JWT token
139
+ the actor stays explicit and must equal the token's `sub`. When no actor can
140
+ be determined the sync stops before fetching anything, with one error naming
141
+ `CORTEXDB_ACTOR`, and the cursor is left untouched.
142
+
143
+ `CORTEXDB_SOURCE_INSTANCE_ID` is an optional stable, non-secret account/site
144
+ identifier. Set it (or `--source-instance-id`) whenever two accounts of the
145
+ same provider write to the same CortexDB endpoint, actor, and scope. Its digest
146
+ partitions canonical source ids and the lifecycle ledger; never put an access
147
+ token or other credential in it. The empty default preserves existing
148
+ single-account identities. Connector-specific YAML may set
149
+ `source_instance_id` under that connector as well.
150
+
151
+ Before it opens durable lifecycle state, the connector resolves the billing
152
+ tenant from `GET /v1/auth/whoami`. `CORTEXDB_TENANT_ID` (or
153
+ `--cortex-tenant-id`) is an optional expected value and must match that
154
+ authenticated response; it never bypasses verification. Tenant identity is
155
+ part of the opaque ledger namespace, so credentials for a different tenant
156
+ cannot reuse completed source rows.
157
+
131
158
  ## Run
132
159
 
133
160
  ```bash
@@ -156,10 +183,10 @@ All 18 connectors are **🟢 Free** to self-host and **🔒 Starter+** ($29/mo)
156
183
 
157
184
  ```
158
185
  slack SLACK_BOT_TOKEN
159
- github GITHUB_TOKEN
186
+ github GITHUB_TOKEN, GITHUB_REPOS
160
187
  gitlab GITLAB_TOKEN
161
- jira JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN (incl. attachments → /v1/blobs multimodal extraction, 0.2.10+)
162
- freshdesk FRESHDESK_DOMAIN, FRESHDESK_API_KEY (incl. attachments → /v1/blobs multimodal extraction, 0.2.20+)
188
+ jira JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN (incl. crash-safe keyed attachments + multimodal extraction, 0.2.10+)
189
+ freshdesk FRESHDESK_DOMAIN, FRESHDESK_API_KEY (incl. crash-safe keyed attachments + multimodal extraction, 0.2.20+)
163
190
  tldv TLDV_API_KEY
164
191
  linear LINEAR_API_KEY
165
192
  confluence CONFLUENCE_URL, CONFLUENCE_EMAIL, CONFLUENCE_API_TOKEN
@@ -175,6 +202,44 @@ intercom INTERCOM_TOKEN
175
202
  servicenow SNOW_INSTANCE, SNOW_USERNAME, SNOW_PASSWORD
176
203
  ```
177
204
 
205
+ `cortexdb-sync list` prints the same required variables plus each connector's optional ones.
206
+
207
+ ### GitHub
208
+
209
+ ```bash
210
+ export GITHUB_TOKEN=ghp_... # PAT or GitHub App installation token
211
+ export GITHUB_REPOS=acme/api,acme/web # required: owner/repo, comma-separated (no discovery)
212
+ export GITHUB_EVENTS=pull_request,issues # optional; default: all six kinds below
213
+ export GITHUB_BACKFILL_DAYS=30 # optional; first-sync history, 0 disables
214
+ cortexdb-sync sync github
215
+ ```
216
+
217
+ - **What is stored (0.2.22+):** PRs as `PR #n [state]: title` plus the full
218
+ description; issues with their full body; issue comments, review bodies and
219
+ inline review comments (file, line and diff hunk) in full; pushes with the
220
+ newest 20 commit messages and the total count. Nothing is truncated — text
221
+ over 1 MiB is split losslessly into source-bound fragments.
222
+ - **`GITHUB_EVENTS` kinds:** `push`, `pull_request`, `issues`,
223
+ `issue_comment`, `pull_request_review`, `pull_request_review_comment`. Raw
224
+ Events API names (`PullRequestEvent`, `PullRequestReviewCommentEvent`, …)
225
+ are accepted too, case-insensitively.
226
+ - **Sources:** PRs, issues, issue comments and review comments are read from
227
+ the REST list endpoints on every sync (the first sync reaches back
228
+ `GITHUB_BACKFILL_DAYS`, default 30, as does the first sync of a
229
+ repository added to `GITHUB_REPOS` later); the repository Events feed, which
230
+ GitHub caps at 300 events / 30 days, supplies pushes and reviews. Each
231
+ record is keyed by the GitHub object — the same identity the webhook
232
+ receiver uses — so a PR re-read by the poller or delivered by a webhook
233
+ updates one record instead of adding another.
234
+ - **Persist `~/.cortexdb` between runs:** it holds the cursor (with the
235
+ work a run deferred — pushes and PR file lists / review listings held
236
+ when the API budget ran low, and a new repository's backfill items that
237
+ failed to ingest — retried on the next sync) and the
238
+ lifecycle ledger that retires superseded versions (or point
239
+ `CORTEXDB_STATE_DIR` at a volume for the ledger, and `--state-file` /
240
+ the worker's `CORTEX_SYNC_STATE_PATH` for the cursor). A throwaway
241
+ `docker run --rm` loses both.
242
+
178
243
  Per-connector setup pages live at https://cortexdb.ai/docs/connectors/ (e.g. [Slack](https://cortexdb.ai/docs/connectors/slack)). **The "Add Connector" button on those pages is the managed (Starter+) path** — the CLI on this page is the free path.
179
244
 
180
245
  For deep self-hosted operation — auth lifetimes, cursor state, retries, OAuth setup for Salesforce/Teams/Google Workspace — see [`SELF_HOSTING.md`](./SELF_HOSTING.md) in this directory.
@@ -186,6 +251,7 @@ If env vars get unwieldy, drop a `cortexdb-connectors.yaml` next to your sync in
186
251
  ```yaml
187
252
  slack:
188
253
  slack_bot_token: xoxb-...
254
+ source_instance_id: acme-slack-workspace
189
255
  channels: [C01ABCDEF, C02GHIJKL]
190
256
 
191
257
  github:
@@ -213,6 +279,8 @@ connector = SlackConnector(
213
279
  connector.bind(
214
280
  actor="user:u_019e...",
215
281
  scope_template="org:acme/source:slack/channel:{entity.channel}",
282
+ source_instance_id="acme-slack-workspace",
283
+ cortex_tenant_id="acme", # optional assertion, verified with whoami
216
284
  )
217
285
 
218
286
  result = asyncio.run(connector.sync())
@@ -223,6 +291,45 @@ print(result.episodes_ingested, "ingested,", len(result.errors), "errors")
223
291
 
224
292
  The `cortexdb-connectors[webhooks]` extra ships a Starlette-based webhook receiver for sources that push (Slack Events API, GitHub Apps, Jira webhooks, …) instead of polling. See `cortexdb_connectors/webhooks.py`.
225
293
 
294
+ ## Durable lifecycle ledger
295
+
296
+ Every canonical text or blob source is recorded in a local SQLite ledger before
297
+ a sync cursor advances or a webhook is acknowledged. It stores only opaque
298
+ source/version/idempotency digests, random upload tokens, and CortexDB
299
+ event/blob ids—never source text or file bytes. The default is
300
+ `~/.cortexdb/connector_event_ledger.sqlite3` (or under `CORTEXDB_STATE_DIR`);
301
+ override it with `CORTEX_CONNECTOR_EVENT_LEDGER_PATH`.
302
+ The authenticated billing tenant is included in its opaque namespace and an
303
+ optional configured tenant assertion must match `/v1/auth/whoami`.
304
+
305
+ Keep this database on durable local storage and back it up with SQLite's online
306
+ backup API (or stop writers and copy the database together with its `-wal` and
307
+ `-shm` files). A replica needs the same ledger to suppress replay beyond the
308
+ server idempotency window and to erase every historical source version, so run
309
+ one active connector writer per source namespace unless all writers share a
310
+ correctly coordinated ledger. Same-source generation changes use bounded,
311
+ crash-released OS advisory-lock stripes beside the SQLite file; network
312
+ filesystems are supported only when they provide equivalent locking semantics.
313
+ Accepted replacements retire older generations through exact derived-then-raw
314
+ erasure before the sync cursor advances; a failed cleanup remains durable for
315
+ retry. Rows are removed after confirmed source erasure or supersession;
316
+ monitor disk usage as part of connector operations.
317
+
318
+ New binary attachments use only CortexDB's versioned keyed-blob protocol. The
319
+ ledger commits a random, non-secret upload token before any blob network request,
320
+ then preflights and uploads the bytes through `/v1/blobs/idempotent`. A timeout
321
+ or restart reuses that same token and reconciles the authoritative blob ID, so
322
+ it cannot create a second physical object. Deletion tombstones the token through
323
+ the matching keyed endpoint before removing the local mapping. A missing,
324
+ disabled, malformed, or older server implementation is a hard sync failure;
325
+ connectors never fall back to an unkeyed upload. Existing blob-ID-only ledger
326
+ rows from releases before keyed uploads remain deletable through the legacy
327
+ ID route as a migration path, but no new rows are created that way.
328
+ Binary payloads over the 32 MiB source ceiling, malformed descriptors, and
329
+ invalid envelope metadata are rejected before whoami, ledger allocation, or
330
+ upload. Text-shaped attachments are strictly decoded and losslessly fragmented
331
+ at UTF-8 boundaries instead of taking the binary path.
332
+
226
333
  ## License
227
334
 
228
335
  Apache-2.0
@@ -0,0 +1,254 @@
1
+ # cortexdb-connectors
2
+
3
+ Managed data connectors for [CortexDB](https://cortexdb.ai). Run them yourself, or let CortexDB host them for you on the [Starter tier](https://cortexdb.ai/pricing).
4
+
5
+ Each connector pulls from a third-party system (Slack, GitHub, Jira, …) and writes every event into CortexDB as a v1 experience.
6
+
7
+ ## Plan availability (audit BLK-3)
8
+
9
+ | Mode | Plan | What it means |
10
+ |---|---|---|
11
+ | **Self-hosted** (`cortexdb-sync` CLI) | 🟢 **Free** (this package) | You run the poller / webhook receiver yourself. Cursor state lives in `~/.cortexdb/`. Every connector below works in this mode. |
12
+ | **Managed sync** (dashboard) | 🔒 **Starter+** ($29/mo) | CortexDB hosts the syncer, manages credentials, and surfaces health in the dashboard. The "Add Connector" button in the dashboard is gated on this plan. |
13
+
14
+ The free self-hosted path is always available; the managed dashboard path is what the pricing page calls "Starter+". The badge below appears on each connector's setup page for the same reason.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ # core only — no third-party SDK dependencies
20
+ pip install cortexdb-connectors
21
+
22
+ # with one source's SDK
23
+ pip install 'cortexdb-connectors[slack]'
24
+
25
+ # everything
26
+ pip install 'cortexdb-connectors[all]'
27
+ ```
28
+
29
+ Requires Python 3.10+.
30
+
31
+ ## Auth
32
+
33
+ The connectors talk to the CortexDB v1 API. Two things you need:
34
+
35
+ - **A PASETO bearer token** (`Authorization: Bearer …`)
36
+ - **An actor id** that matches the token's `sub` claim (`X-Cortex-Actor: …`)
37
+
38
+ The fastest way to get both is to install [`cortexdb-cli`](https://pypi.org/project/cortexdb-cli/) and run `cortexdb init` — anonymous signup, no email or card, 7-day free-tier token. The connectors read `~/.cortexdb/state.json` automatically.
39
+
40
+ Or set env vars:
41
+
42
+ ```bash
43
+ export CORTEXDB_URL=https://api-v1.cortexdb.ai
44
+ export CORTEXDB_API_KEY=v4.public...
45
+ export CORTEXDB_ACTOR=user:u_019e...
46
+ export CORTEXDB_TENANT_ID=acme # optional assertion; verified via whoami
47
+ export CORTEXDB_SCOPE_TEMPLATE='org:acme/source:{source}' # optional
48
+ export CORTEXDB_SOURCE_INSTANCE_ID='acme-slack-workspace' # see below
49
+ ```
50
+
51
+ `{source}` (and `{scope}`, `{namespace}`, `{actor}`, `{entity.<type>}`) get filled in per event. (`{tenant}` is still accepted as a legacy alias of `{scope}`.)
52
+
53
+ **Self-hosted server with a static `CORTEX_API_KEY`:** that key has no `sub`
54
+ claim, and the server runs a request without `X-Cortex-Actor` as `user:local`.
55
+ When `CORTEXDB_ACTOR` is unset, `cortexdb-sync sync|watch` and the Docker
56
+ worker ask `GET /v1/auth/whoami` (without the header) and adopt `user:local`
57
+ only when the server confirms a static key (0.2.22+). With a PASETO/JWT token
58
+ the actor stays explicit and must equal the token's `sub`. When no actor can
59
+ be determined the sync stops before fetching anything, with one error naming
60
+ `CORTEXDB_ACTOR`, and the cursor is left untouched.
61
+
62
+ `CORTEXDB_SOURCE_INSTANCE_ID` is an optional stable, non-secret account/site
63
+ identifier. Set it (or `--source-instance-id`) whenever two accounts of the
64
+ same provider write to the same CortexDB endpoint, actor, and scope. Its digest
65
+ partitions canonical source ids and the lifecycle ledger; never put an access
66
+ token or other credential in it. The empty default preserves existing
67
+ single-account identities. Connector-specific YAML may set
68
+ `source_instance_id` under that connector as well.
69
+
70
+ Before it opens durable lifecycle state, the connector resolves the billing
71
+ tenant from `GET /v1/auth/whoami`. `CORTEXDB_TENANT_ID` (or
72
+ `--cortex-tenant-id`) is an optional expected value and must match that
73
+ authenticated response; it never bypasses verification. Tenant identity is
74
+ part of the opaque ledger namespace, so credentials for a different tenant
75
+ cannot reuse completed source rows.
76
+
77
+ ## Run
78
+
79
+ ```bash
80
+ # one shot
81
+ cortexdb-sync sync slack
82
+
83
+ # poll loop, 60s between cycles
84
+ cortexdb-sync watch slack --interval 60
85
+
86
+ # resume from a specific point
87
+ cortexdb-sync sync github --since 2026-05-01T00:00:00Z
88
+
89
+ # see what's available
90
+ cortexdb-sync list
91
+
92
+ # check resolved CortexDB creds
93
+ cortexdb-sync auth
94
+
95
+ # cursor state across every connector
96
+ cortexdb-sync status
97
+ ```
98
+
99
+ ## Available connectors
100
+
101
+ All 18 connectors are **🟢 Free** to self-host and **🔒 Starter+** ($29/mo) to use via the managed dashboard.
102
+
103
+ ```
104
+ slack SLACK_BOT_TOKEN
105
+ github GITHUB_TOKEN, GITHUB_REPOS
106
+ gitlab GITLAB_TOKEN
107
+ jira JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN (incl. crash-safe keyed attachments + multimodal extraction, 0.2.10+)
108
+ freshdesk FRESHDESK_DOMAIN, FRESHDESK_API_KEY (incl. crash-safe keyed attachments + multimodal extraction, 0.2.20+)
109
+ tldv TLDV_API_KEY
110
+ linear LINEAR_API_KEY
111
+ confluence CONFLUENCE_URL, CONFLUENCE_EMAIL, CONFLUENCE_API_TOKEN
112
+ notion NOTION_TOKEN
113
+ pagerduty PAGERDUTY_API_KEY
114
+ discord DISCORD_BOT_TOKEN
115
+ teams TEAMS_TENANT_ID, TEAMS_CLIENT_ID, TEAMS_CLIENT_SECRET
116
+ google-workspace GW_SERVICE_ACCOUNT_KEY, GW_DELEGATED_USER
117
+ salesforce SF_INSTANCE_URL, SF_CLIENT_ID, SF_CLIENT_SECRET, SF_USERNAME, SF_PASSWORD
118
+ hubspot HUBSPOT_TOKEN
119
+ zendesk ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_TOKEN
120
+ intercom INTERCOM_TOKEN
121
+ servicenow SNOW_INSTANCE, SNOW_USERNAME, SNOW_PASSWORD
122
+ ```
123
+
124
+ `cortexdb-sync list` prints the same required variables plus each connector's optional ones.
125
+
126
+ ### GitHub
127
+
128
+ ```bash
129
+ export GITHUB_TOKEN=ghp_... # PAT or GitHub App installation token
130
+ export GITHUB_REPOS=acme/api,acme/web # required: owner/repo, comma-separated (no discovery)
131
+ export GITHUB_EVENTS=pull_request,issues # optional; default: all six kinds below
132
+ export GITHUB_BACKFILL_DAYS=30 # optional; first-sync history, 0 disables
133
+ cortexdb-sync sync github
134
+ ```
135
+
136
+ - **What is stored (0.2.22+):** PRs as `PR #n [state]: title` plus the full
137
+ description; issues with their full body; issue comments, review bodies and
138
+ inline review comments (file, line and diff hunk) in full; pushes with the
139
+ newest 20 commit messages and the total count. Nothing is truncated — text
140
+ over 1 MiB is split losslessly into source-bound fragments.
141
+ - **`GITHUB_EVENTS` kinds:** `push`, `pull_request`, `issues`,
142
+ `issue_comment`, `pull_request_review`, `pull_request_review_comment`. Raw
143
+ Events API names (`PullRequestEvent`, `PullRequestReviewCommentEvent`, …)
144
+ are accepted too, case-insensitively.
145
+ - **Sources:** PRs, issues, issue comments and review comments are read from
146
+ the REST list endpoints on every sync (the first sync reaches back
147
+ `GITHUB_BACKFILL_DAYS`, default 30, as does the first sync of a
148
+ repository added to `GITHUB_REPOS` later); the repository Events feed, which
149
+ GitHub caps at 300 events / 30 days, supplies pushes and reviews. Each
150
+ record is keyed by the GitHub object — the same identity the webhook
151
+ receiver uses — so a PR re-read by the poller or delivered by a webhook
152
+ updates one record instead of adding another.
153
+ - **Persist `~/.cortexdb` between runs:** it holds the cursor (with the
154
+ work a run deferred — pushes and PR file lists / review listings held
155
+ when the API budget ran low, and a new repository's backfill items that
156
+ failed to ingest — retried on the next sync) and the
157
+ lifecycle ledger that retires superseded versions (or point
158
+ `CORTEXDB_STATE_DIR` at a volume for the ledger, and `--state-file` /
159
+ the worker's `CORTEX_SYNC_STATE_PATH` for the cursor). A throwaway
160
+ `docker run --rm` loses both.
161
+
162
+ Per-connector setup pages live at https://cortexdb.ai/docs/connectors/ (e.g. [Slack](https://cortexdb.ai/docs/connectors/slack)). **The "Add Connector" button on those pages is the managed (Starter+) path** — the CLI on this page is the free path.
163
+
164
+ For deep self-hosted operation — auth lifetimes, cursor state, retries, OAuth setup for Salesforce/Teams/Google Workspace — see [`SELF_HOSTING.md`](./SELF_HOSTING.md) in this directory.
165
+
166
+ ## YAML config
167
+
168
+ If env vars get unwieldy, drop a `cortexdb-connectors.yaml` next to your sync invocation:
169
+
170
+ ```yaml
171
+ slack:
172
+ slack_bot_token: xoxb-...
173
+ source_instance_id: acme-slack-workspace
174
+ channels: [C01ABCDEF, C02GHIJKL]
175
+
176
+ github:
177
+ github_token: ghp_...
178
+ repos: [acme/api, acme/web]
179
+ events: [pull_request, issue_comment]
180
+ ```
181
+
182
+ ## Programmatic use
183
+
184
+ Skip the CLI entirely:
185
+
186
+ ```python
187
+ import asyncio
188
+ from cortexdb_connectors.slack import SlackConnector
189
+
190
+ connector = SlackConnector(
191
+ cortex_url="https://api-v1.cortexdb.ai",
192
+ cortex_api_key="v4.public...",
193
+ scope="org:acme/source:slack",
194
+ slack_bot_token="xoxb-...",
195
+ channels=["C01ABC", "C02DEF"],
196
+ )
197
+ # actor + a richer scope_template are set after construction:
198
+ connector.bind(
199
+ actor="user:u_019e...",
200
+ scope_template="org:acme/source:slack/channel:{entity.channel}",
201
+ source_instance_id="acme-slack-workspace",
202
+ cortex_tenant_id="acme", # optional assertion, verified with whoami
203
+ )
204
+
205
+ result = asyncio.run(connector.sync())
206
+ print(result.episodes_ingested, "ingested,", len(result.errors), "errors")
207
+ ```
208
+
209
+ ## Webhooks
210
+
211
+ The `cortexdb-connectors[webhooks]` extra ships a Starlette-based webhook receiver for sources that push (Slack Events API, GitHub Apps, Jira webhooks, …) instead of polling. See `cortexdb_connectors/webhooks.py`.
212
+
213
+ ## Durable lifecycle ledger
214
+
215
+ Every canonical text or blob source is recorded in a local SQLite ledger before
216
+ a sync cursor advances or a webhook is acknowledged. It stores only opaque
217
+ source/version/idempotency digests, random upload tokens, and CortexDB
218
+ event/blob ids—never source text or file bytes. The default is
219
+ `~/.cortexdb/connector_event_ledger.sqlite3` (or under `CORTEXDB_STATE_DIR`);
220
+ override it with `CORTEX_CONNECTOR_EVENT_LEDGER_PATH`.
221
+ The authenticated billing tenant is included in its opaque namespace and an
222
+ optional configured tenant assertion must match `/v1/auth/whoami`.
223
+
224
+ Keep this database on durable local storage and back it up with SQLite's online
225
+ backup API (or stop writers and copy the database together with its `-wal` and
226
+ `-shm` files). A replica needs the same ledger to suppress replay beyond the
227
+ server idempotency window and to erase every historical source version, so run
228
+ one active connector writer per source namespace unless all writers share a
229
+ correctly coordinated ledger. Same-source generation changes use bounded,
230
+ crash-released OS advisory-lock stripes beside the SQLite file; network
231
+ filesystems are supported only when they provide equivalent locking semantics.
232
+ Accepted replacements retire older generations through exact derived-then-raw
233
+ erasure before the sync cursor advances; a failed cleanup remains durable for
234
+ retry. Rows are removed after confirmed source erasure or supersession;
235
+ monitor disk usage as part of connector operations.
236
+
237
+ New binary attachments use only CortexDB's versioned keyed-blob protocol. The
238
+ ledger commits a random, non-secret upload token before any blob network request,
239
+ then preflights and uploads the bytes through `/v1/blobs/idempotent`. A timeout
240
+ or restart reuses that same token and reconciles the authoritative blob ID, so
241
+ it cannot create a second physical object. Deletion tombstones the token through
242
+ the matching keyed endpoint before removing the local mapping. A missing,
243
+ disabled, malformed, or older server implementation is a hard sync failure;
244
+ connectors never fall back to an unkeyed upload. Existing blob-ID-only ledger
245
+ rows from releases before keyed uploads remain deletable through the legacy
246
+ ID route as a migration path, but no new rows are created that way.
247
+ Binary payloads over the 32 MiB source ceiling, malformed descriptors, and
248
+ invalid envelope metadata are rejected before whoami, ledger allocation, or
249
+ upload. Text-shaped attachments are strictly decoded and losslessly fragmented
250
+ at UTF-8 boundaries instead of taking the binary path.
251
+
252
+ ## License
253
+
254
+ Apache-2.0