airbyte-internal-ops 0.4.2__py3-none-any.whl → 0.5.0__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.
Files changed (53) hide show
  1. {airbyte_internal_ops-0.4.2.dist-info → airbyte_internal_ops-0.5.0.dist-info}/METADATA +1 -1
  2. {airbyte_internal_ops-0.4.2.dist-info → airbyte_internal_ops-0.5.0.dist-info}/RECORD +13 -52
  3. airbyte_ops_mcp/cli/cloud.py +27 -0
  4. airbyte_ops_mcp/cloud_admin/api_client.py +473 -0
  5. airbyte_ops_mcp/cloud_admin/models.py +56 -0
  6. airbyte_ops_mcp/mcp/cloud_connector_versions.py +460 -0
  7. airbyte_ops_mcp/mcp/prerelease.py +5 -44
  8. airbyte_ops_mcp/regression_tests/ci_output.py +8 -4
  9. airbyte_ops_mcp/regression_tests/http_metrics.py +21 -2
  10. airbyte_ops_mcp/regression_tests/models.py +6 -0
  11. airbyte_ops_mcp/telemetry.py +162 -0
  12. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/.gitignore +0 -1
  13. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/README.md +0 -420
  14. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/__init__.py +0 -2
  15. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/__init__.py +0 -1
  16. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/__init__.py +0 -8
  17. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/base_backend.py +0 -16
  18. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/duckdb_backend.py +0 -87
  19. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/file_backend.py +0 -165
  20. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/connection_objects_retrieval.py +0 -377
  21. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/connector_runner.py +0 -247
  22. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/errors.py +0 -7
  23. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/evaluation_modes.py +0 -25
  24. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/hacks.py +0 -23
  25. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/json_schema_helper.py +0 -384
  26. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/mitm_addons.py +0 -37
  27. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/models.py +0 -595
  28. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/proxy.py +0 -207
  29. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/secret_access.py +0 -47
  30. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/segment_tracking.py +0 -45
  31. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/utils.py +0 -214
  32. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/conftest.py.disabled +0 -751
  33. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/consts.py +0 -4
  34. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/poetry.lock +0 -4480
  35. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/pytest.ini +0 -9
  36. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/__init__.py +0 -1
  37. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_check.py +0 -61
  38. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_discover.py +0 -117
  39. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_read.py +0 -627
  40. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_spec.py +0 -43
  41. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/report.py +0 -542
  42. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/stash_keys.py +0 -38
  43. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/__init__.py +0 -0
  44. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/private_details.html.j2 +0 -305
  45. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/report.html.j2 +0 -515
  46. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/utils.py +0 -187
  47. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/__init__.py +0 -0
  48. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_check.py +0 -61
  49. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_discover.py +0 -217
  50. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_read.py +0 -177
  51. airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_spec.py +0 -631
  52. {airbyte_internal_ops-0.4.2.dist-info → airbyte_internal_ops-0.5.0.dist-info}/WHEEL +0 -0
  53. {airbyte_internal_ops-0.4.2.dist-info → airbyte_internal_ops-0.5.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: airbyte-internal-ops
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: MCP and API interfaces that let the agents do the admin work
5
5
  Author-email: Aaron Steers <aj@airbyte.io>
6
6
  Keywords: admin,airbyte,api,mcp
@@ -5,6 +5,7 @@ airbyte_ops_mcp/gcp_auth.py,sha256=i0cm1_xX4fj_31iKlfARpNvTaSr85iGTSw9KMf4f4MU,7
5
5
  airbyte_ops_mcp/github_actions.py,sha256=FSi_tjS9TbwRVp8dwlDZhFOi7lJXEZQLhPm2KpcjNlY,7022
6
6
  airbyte_ops_mcp/github_api.py,sha256=ezpMR1vjqQ-1f5yOLBVbxW70OPtUferl1uA0u_gUVo8,12733
7
7
  airbyte_ops_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ airbyte_ops_mcp/telemetry.py,sha256=GUQX-oD6besFl-kAyycci1HCk1jov_JFwUAqKVN0yKE,5230
8
9
  airbyte_ops_mcp/_legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
10
  airbyte_ops_mcp/_legacy/airbyte_ci/README.md,sha256=qEYx4geDR8AEDjrcA303h7Nol-CMDLojxUyiGzQprM8,236
10
11
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_erd_generator/README.md,sha256=wRQ9tSkf__riq8wTht2IKt_jPK1bW0v10dDo5tSsbZM,842
@@ -22,46 +23,6 @@ airbyte_ops_mcp/_legacy/airbyte_ci/connector_insights/pylint.py,sha256=jnQJTA-cq
22
23
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_insights/result_backends.py,sha256=Y02Q0d4_dQPzmFs_hk12MlqAhPHWEG5kyKbQjC-Ry28,4058
23
24
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_insights/utils.py,sha256=gYnmJMJM5LlFjNvKyU8FCxQd8LbTgDhs3IYsARohQlE,3189
24
25
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_insights/pylint_plugins/cdk_deprecation_checkers.py,sha256=M31bV-BRnkNuUOD80S9sJs9Q3NnrwVRBNlVQwvGdyKY,2677
25
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/.gitignore,sha256=hezODgoJG1gosD6k_mLf3vy3dGxbM5LrsgCS7c5ZUn4,27
26
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/README.md,sha256=RbzoUEUCkrF50pAOJ-COqOWCjpGyApdJbctfh7UoIsM,15299
27
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/__init__.py,sha256=STIY57jAIPRSp9m2aYFzaQD4MsNFPphaVilP1tQ6y60,58
28
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/conftest.py.disabled,sha256=fbHkaY_lRalFD5VW9EgeTinNYtLarAKRZOIQ_qVneqg,28169
29
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/consts.py,sha256=wZaZSAcLl3eSASrpqR_45n9n1ss4aqk5FL1MOxeIYQI,120
30
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/poetry.lock,sha256=7ePhtVKe_fi3W3VUUe5NyOCALuKYalSQy0hq4qX99ls,362992
31
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/pytest.ini,sha256=bIqTl-q7al042Y_3CbKa2feUgsPrxdvAOH6aQTK95s4,314
32
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/report.py,sha256=UE_uLvRD-NXa0hO_QpaIaTXwgLdyXjkOW4P-Ys8iXAE,21908
33
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/stash_keys.py,sha256=VdBX4c9T7VcWGrKolm-UsxLck0gaaKt9vI63cg9sh7k,1667
34
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/utils.py,sha256=8j6V4WE6NRdjxNr9EJFW_e-2I8byn2pVywmbxhYaFgM,6433
35
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/__init__.py,sha256=G8L2E8OSuhpnMnK0HMO9iDiZF6Hb8iubfV6FJ-40Dm8,57
36
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/connection_objects_retrieval.py,sha256=Oo3sCc6gdfwDwaKHZAc_HkXxrviFre144gPzkkQuANg,15776
37
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/connector_runner.py,sha256=TlQlmCP3P_svxkTmEZqaYW438EvFh4CWvP7JnHLcPPw,9896
38
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/errors.py,sha256=i0G3BKwTstHWL5rTWsUepKqjPWYTwbIk3sR56EJSKGw,196
39
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/evaluation_modes.py,sha256=VE_9VBL9oyCHe98E3PrMriSkAFGyWbJ9dAuWTGFbd2o,870
40
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/hacks.py,sha256=oIwDL_wGNjp5ZDby5RAb0CPLCObB6kqZ0hFVzvG5Wc4,1009
41
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/json_schema_helper.py,sha256=9ecYGiryX4M759Y-BAQ73oGiVYb7migBPEgGlSCeAeE,13325
42
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/mitm_addons.py,sha256=9IlIJ7886bsi0_nvyoRDS8OQ9Ob3y9tBEstfhtdlBT4,1302
43
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/models.py,sha256=IxRPkBnk0Aqn1EatH68OdV9HHbdYMUAG48_0Dd2CBf8,21604
44
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/proxy.py,sha256=qDl0Xv3kt-RRSTDI5747905qkSZXW4WnWOgY1jI_2Z4,9035
45
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/secret_access.py,sha256=e-Ypy721XLosqBh6BBw3i9kHVnZ1SzhUvwRJz7R1wtc,1647
46
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/segment_tracking.py,sha256=SS-ZLkNlJpJMjCZo7KBBMnUqW88zz4uXxBqlzGKA7sw,1274
47
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/utils.py,sha256=x35pbCfAlsfSQfZ78zwtXQhNCba-YZCzoCVtQ3TDCz8,7801
48
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/__init__.py,sha256=igpz_JxLRYJTXWuM5G2yr8mCkoWXjJir2ywxbeaCHgc,270
49
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/base_backend.py,sha256=vnrWioE7UY2WI7zyBJ5hNvgI3SlxIAtk6JPP3HxPUX4,454
50
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/duckdb_backend.py,sha256=hWvzauicoI3JgtOGVbfeai4GhJZ_exW0JQyeVqf7C3M,3420
51
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/commons/backends/file_backend.py,sha256=yWoedpDnLgI8b9lNU8Ei4bdfkNfGXH0qULxYo4W7Ijo,6551
52
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/__init__.py,sha256=G8L2E8OSuhpnMnK0HMO9iDiZF6Hb8iubfV6FJ-40Dm8,57
53
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_check.py,sha256=Dg8VKP6GIxoA2LWWS6qfCN9J4JxmnnagqxUuvZt1Urw,2129
54
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_discover.py,sha256=pHAlNOOt9dkbNFFzeuJDPQOfGu-YnRj0BkC5_LzCGRc,4063
55
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_read.py,sha256=iyMPkLIEJ9PiqlJqxHegzXbwirgUMFqnPMLIN_8L9Qw,26750
56
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/regression_tests/test_spec.py,sha256=6pkDPTUNE14YZKJoGzuYERzfRFk42jLuxoNIDVcJM04,1485
57
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/private_details.html.j2,sha256=vwU1Y_mEF7AHqZOdnAZOKpDLOguNST4JJ9FG8WTPBHo,9078
59
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/templates/report.html.j2,sha256=ZdMJ7YDoDa9sbpIBCI6HfrD6KHsXJX7SotLfj_DmqMY,20131
60
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_check.py,sha256=1opKdmFiB-tDyelXTwFtef0ByhKN2FSCS2NXBrdsxHk,1733
62
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_discover.py,sha256=SpiA9DU1pAQAKsNs7ccyUo2nLyZLAT02S0OatnvlmwE,8024
63
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_read.py,sha256=U3XSVB8uwYzirrDk4r3VIA1vN96E05JGtrTA0moe8gI,6773
64
- airbyte_ops_mcp/_legacy/airbyte_ci/connector_live_tests/validation_tests/test_spec.py,sha256=_PuwluCueXxDzE95tUWa1PyjQ_60Oo2KtDWMT3S8rpQ,26397
65
26
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_ops/README.md,sha256=bkrbgjGvnbuUBgDWaQ6f-WF7p3h3Ft3lZAMR1LLTMm4,1317
66
27
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_ops/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
67
28
  airbyte_ops_mcp/_legacy/airbyte_ci/connector_ops/utils.py,sha256=yZsrdj2Jv-6rb97recNncZCkmY79EqpPiZOMUOf8ke4,28573
@@ -353,15 +314,15 @@ airbyte_ops_mcp/cli/__init__.py,sha256=XpL7FyVfgabfBF2JR7u7NwJ2krlYqjd_OwLcWf-Xc
353
314
  airbyte_ops_mcp/cli/_base.py,sha256=I8tWnyQf0ks4r3J8N8h-5GZxyn37T-55KsbuHnxYlcg,415
354
315
  airbyte_ops_mcp/cli/_shared.py,sha256=jg-xMyGzTCGPqKd8VTfE_3kGPIyO_3Kx5sQbG4rPc0Y,1311
355
316
  airbyte_ops_mcp/cli/app.py,sha256=SEdBpqFUG2O8zGV5ifwptxrLGFph_dLr66-MX9d69gQ,789
356
- airbyte_ops_mcp/cli/cloud.py,sha256=7Iy8gpIM-Im5GMy2aShi3gE-BSPZABXPICnOyrZrJAw,44621
317
+ airbyte_ops_mcp/cli/cloud.py,sha256=b5oiu2oNXJXA3AcjpBcOKf1t84Tc5seSNsSwYhK0oI8,45587
357
318
  airbyte_ops_mcp/cli/gh.py,sha256=koJPu0MDB6AW7mJq2z4dZV65ofvsZTkqoeitGF8KJR8,5364
358
319
  airbyte_ops_mcp/cli/registry.py,sha256=L4nDKhlegr31gSE-GUvDFSq10KgDz5kJuZXgLIxYIyg,9785
359
320
  airbyte_ops_mcp/cli/repo.py,sha256=G1hoQpH0XYhUH3FFOsia9xabGB0LP9o3XcwBuqvFVo0,16331
360
321
  airbyte_ops_mcp/cloud_admin/__init__.py,sha256=cqE96Q10Kp6elhH9DAi6TVsIwSUy3sooDLLrxTaktGk,816
361
- airbyte_ops_mcp/cloud_admin/api_client.py,sha256=ysTztSbLX0SZSK3qneHTSKVODRzVmLbHBC3ND0j_LTc,38020
322
+ airbyte_ops_mcp/cloud_admin/api_client.py,sha256=vFklWFQECau0oLor-ngW6pgkhH5np9x9yaPCUxgix_Q,56701
362
323
  airbyte_ops_mcp/cloud_admin/auth.py,sha256=qE2Aqe0qbZB755KscL65s54Jz78-F-X5a8fXKsrYEOQ,3749
363
324
  airbyte_ops_mcp/cloud_admin/connection_config.py,sha256=9opGQer-cGMJANmm-LFLMwvMCNu3nzxa2n2XHkZj9Fw,4899
364
- airbyte_ops_mcp/cloud_admin/models.py,sha256=YZ3FbEW-tZa50khKTTl4Bzvy_LsGyyQd6qcpXo62jls,2670
325
+ airbyte_ops_mcp/cloud_admin/models.py,sha256=yldPAL9Lce83U3JN-f6qPc2X5LPnLCYqgnXrM1DRq98,4799
365
326
  airbyte_ops_mcp/connection_config_retriever/__init__.py,sha256=Xoi-YvARrNPhECdpwEDDkdwEpnvj8zuUlwULpf4iRrU,800
366
327
  airbyte_ops_mcp/connection_config_retriever/audit_logging.py,sha256=QdOG9984NXeMaKeJnFUZ4oCOmqi37PBRG2NRBBjrZQQ,2753
367
328
  airbyte_ops_mcp/connection_config_retriever/retrieval.py,sha256=s6yeCyrboWkUd6KdaheEo87x-rLtQNTL8XeR8O9z2HI,12160
@@ -372,14 +333,14 @@ airbyte_ops_mcp/mcp/__init__.py,sha256=QqkNkxzdXlg-W03urBAQ3zmtOKFPf35rXgO9ceUjp
372
333
  airbyte_ops_mcp/mcp/_guidance.py,sha256=48tQSnDnxqXtyGJxxgjz0ZiI814o_7Fj7f6R8jpQ7so,2375
373
334
  airbyte_ops_mcp/mcp/_http_headers.py,sha256=9TAH2RYhFR3z2JugW4Q3WrrqJIdaCzAbyA1GhtQ_EMM,7278
374
335
  airbyte_ops_mcp/mcp/_mcp_utils.py,sha256=WNwcGzF7XGKZNAYRt0Uhj5BkRfmwqnFABCrk77OZjRw,11512
375
- airbyte_ops_mcp/mcp/cloud_connector_versions.py,sha256=5qUYRZapYBprmmc5J3lKQzeQ3yJUiFQbrxBgUvnLUgQ,16297
336
+ airbyte_ops_mcp/mcp/cloud_connector_versions.py,sha256=M_dA1YuZkEw-K8xiE1NSqKAP_CvXGo0_Ewv-Y2oc_wQ,33105
376
337
  airbyte_ops_mcp/mcp/connector_analysis.py,sha256=OC4KrOSkMkKPkOisWnSv96BDDE5TQYHq-Jxa2vtjJpo,298
377
338
  airbyte_ops_mcp/mcp/connector_qa.py,sha256=aImpqdnqBPDrz10BS0owsV4kuIU2XdalzgbaGZsbOL0,258
378
339
  airbyte_ops_mcp/mcp/gcp_logs.py,sha256=IPtq4098_LN1Cgeba4jATO1iYFFFpL2-aRO0pGcOdzs,2689
379
340
  airbyte_ops_mcp/mcp/github_actions.py,sha256=_mAVTl6UX3F7S_HeV1-M5R4jMNzNQGI3ADs3sBzden8,11760
380
341
  airbyte_ops_mcp/mcp/github_repo_ops.py,sha256=PiERpt8abo20Gz4CfXhrDNlVM4o4FOt5sweZJND2a0s,5314
381
342
  airbyte_ops_mcp/mcp/metadata.py,sha256=fwGW97WknR5lfKcQnFtK6dU87aA6TmLj1NkKyqDAV9g,270
382
- airbyte_ops_mcp/mcp/prerelease.py,sha256=OoZxwy3-PAiTiKuWhhbfv_DrsHBDs9LVz4Y6EuL0Qkk,10596
343
+ airbyte_ops_mcp/mcp/prerelease.py,sha256=KxBNRxwkIzfD981xphi07cvlgR-QEDmSe88aBfqNAyQ,9561
383
344
  airbyte_ops_mcp/mcp/prod_db_queries.py,sha256=VsiBBnVbOjc8lBb2Xr1lmcH3wu7QHQfjd4lORarEE1s,42700
384
345
  airbyte_ops_mcp/mcp/prompts.py,sha256=mJld9mdPECXYZffWXGSvNs4Xevx3rxqUGNlzGKVC2_s,1599
385
346
  airbyte_ops_mcp/mcp/registry.py,sha256=PW-VYUj42qx2pQ_apUkVaoUFq7VgB9zEU7-aGrkSCCw,290
@@ -396,14 +357,14 @@ airbyte_ops_mcp/registry/models.py,sha256=B4L4TKr52wo0xs0CqvCBrpowqjShzVnZ5eTr2-
396
357
  airbyte_ops_mcp/registry/publish.py,sha256=VoPxsM2_0zJ829orzCRN-kjgcJtuBNyXgW4I9J680ro,12717
397
358
  airbyte_ops_mcp/regression_tests/__init__.py,sha256=8pwJIdz1Lb9oFV6UQ3DSjYKd8HCSqU8RpH5SDgEcEBA,1038
398
359
  airbyte_ops_mcp/regression_tests/cdk_secrets.py,sha256=iRjqqBS96KZoswfgT7ju-pE_pfbYoDy4PfrK-K8uyYs,3204
399
- airbyte_ops_mcp/regression_tests/ci_output.py,sha256=DwBVCaCZAhI4MNf39EpUDIzOsHx5T1BZp268IAdaayg,15180
360
+ airbyte_ops_mcp/regression_tests/ci_output.py,sha256=os69gcEhbomrGRAfnwPYAXhsAiJSWOuyW1gWZPx9-hw,15498
400
361
  airbyte_ops_mcp/regression_tests/config.py,sha256=dwWeY0tatdbwl9BqbhZ7EljoZDCtKmGO5fvOAIxeXmA,5873
401
362
  airbyte_ops_mcp/regression_tests/connection_fetcher.py,sha256=5wIiA0VvCFNEc-fr6Po18gZMX3E5fyPOGf2SuVOqv5U,12799
402
363
  airbyte_ops_mcp/regression_tests/connection_secret_retriever.py,sha256=FhWNVWq7sON4nwUmVJv8BgXBOqg1YV4b5WuWyCzZ0LU,4695
403
364
  airbyte_ops_mcp/regression_tests/connector_runner.py,sha256=OZzUa2aLh0sHaEARsDePOA-e3qEX4cvh3Jhnvi8S1rY,10130
404
365
  airbyte_ops_mcp/regression_tests/evaluation_modes.py,sha256=lAL6pEDmy_XCC7_m4_NXjt_f6Z8CXeAhMkc0FU8bm_M,1364
405
- airbyte_ops_mcp/regression_tests/http_metrics.py,sha256=oTD7f2MnQOvx4plOxHop2bInQ0-whvuToSsrC7TIM-M,12469
406
- airbyte_ops_mcp/regression_tests/models.py,sha256=brtAT9oO1TwjFcP91dFcu0XcUNqQb-jf7di1zkoVEuo,8782
366
+ airbyte_ops_mcp/regression_tests/http_metrics.py,sha256=busCYLb7qID0vv7yAtzARf__-HukpE3mAoc-pYI_gCQ,13256
367
+ airbyte_ops_mcp/regression_tests/models.py,sha256=jfe__WV8j2_fK9Cp256x5OhS9STRC63iPLG-36iPUgc,9104
407
368
  airbyte_ops_mcp/regression_tests/obfuscation.py,sha256=JanpCLj6M9-_Zto6PABzNaY3OA93Frq3YpJ1411QNtQ,4395
408
369
  airbyte_ops_mcp/regression_tests/schema_generation.py,sha256=cUYztcSOejsgkUREUWvfi6QBYK6fC4Dbxtztxxt8bdc,5323
409
370
  airbyte_ops_mcp/regression_tests/commons/__init__.py,sha256=lNew_sAL4c8dPy3gMFbGC5_FuUX1P6QzGULbqS2H4M0,104
@@ -414,7 +375,7 @@ airbyte_ops_mcp/regression_tests/regression/comparators.py,sha256=MJkLZEKHivgrG0
414
375
  airbyte_ops_mcp/regression_tests/validation/__init__.py,sha256=MBEwGOoNuqT4_oCahtoK62OKWIjUCfWa7vZTxNj_0Ek,1532
415
376
  airbyte_ops_mcp/regression_tests/validation/catalog_validators.py,sha256=jqqVAMOk0mtdPgwu4d0hA0ZEjtsNh5gapvGydRv3_qk,12553
416
377
  airbyte_ops_mcp/regression_tests/validation/record_validators.py,sha256=RjauAhKWNwxMBTu0eNS2hMFNQVs5CLbQU51kp6FOVDk,7432
417
- airbyte_internal_ops-0.4.2.dist-info/METADATA,sha256=RP-Eu-2phGMnspxD4d5rQBI9Q6jnU-Zr0Fdi8hrzpqY,5679
418
- airbyte_internal_ops-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
419
- airbyte_internal_ops-0.4.2.dist-info/entry_points.txt,sha256=WxP0l7bRFss4Cr5uQqVj9mTEKwnRKouNuphXQF0lotA,171
420
- airbyte_internal_ops-0.4.2.dist-info/RECORD,,
378
+ airbyte_internal_ops-0.5.0.dist-info/METADATA,sha256=vCU17MQXGD6FZ9PfnzKV_gBSgNkTx_W4klz3aOFEulM,5679
379
+ airbyte_internal_ops-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
380
+ airbyte_internal_ops-0.5.0.dist-info/entry_points.txt,sha256=WxP0l7bRFss4Cr5uQqVj9mTEKwnRKouNuphXQF0lotA,171
381
+ airbyte_internal_ops-0.5.0.dist-info/RECORD,,
@@ -82,6 +82,7 @@ from airbyte_ops_mcp.regression_tests.models import (
82
82
  ExecutionInputs,
83
83
  TargetOrControl,
84
84
  )
85
+ from airbyte_ops_mcp.telemetry import track_regression_test
85
86
 
86
87
  # Path to connectors directory within the airbyte repo
87
88
  CONNECTORS_SUBDIR = Path("airbyte-integrations") / "connectors"
@@ -953,6 +954,32 @@ def regression_test(
953
954
  f"Failed to pull control connector image: {resolved_control_image}"
954
955
  )
955
956
 
957
+ # Track telemetry for the regression test
958
+ # Extract version from image tag (e.g., "airbyte/source-github:1.0.0" -> "1.0.0")
959
+ target_version = (
960
+ resolved_test_image.rsplit(":", 1)[-1]
961
+ if ":" in resolved_test_image
962
+ else "unknown"
963
+ )
964
+ control_version = None
965
+ if resolved_control_image and ":" in resolved_control_image:
966
+ control_version = resolved_control_image.rsplit(":", 1)[-1]
967
+
968
+ # Get tester identity from environment (GitHub Actions sets GITHUB_ACTOR)
969
+ tester = os.getenv("GITHUB_ACTOR") or os.getenv("USER")
970
+
971
+ track_regression_test(
972
+ user_id=tester,
973
+ connector_image=resolved_test_image,
974
+ command=command,
975
+ target_version=target_version,
976
+ control_version=control_version,
977
+ additional_properties={
978
+ "connection_id": connection_id,
979
+ "skip_compare": skip_compare,
980
+ },
981
+ )
982
+
956
983
  # Execute the appropriate mode
957
984
  if skip_compare:
958
985
  # Single-version mode: run only the connector image
@@ -15,6 +15,9 @@ from airbyte import constants
15
15
  from airbyte.exceptions import PyAirbyteInputError
16
16
 
17
17
  from airbyte_ops_mcp import constants as ops_constants
18
+ from airbyte_ops_mcp.mcp.prod_db_queries import (
19
+ _resolve_canonical_name_to_definition_id,
20
+ )
18
21
 
19
22
  # Internal enums for scoped configuration API "magic strings"
20
23
  # These values caused issues during development and are now centralized here
@@ -959,3 +962,473 @@ def set_connector_version_override(
959
962
  )
960
963
 
961
964
  return True
965
+
966
+
967
+ def set_workspace_connector_version_override(
968
+ workspace_id: str,
969
+ connector_name: str,
970
+ connector_type: Literal["source", "destination"],
971
+ api_root: str,
972
+ client_id: str | None = None,
973
+ client_secret: str | None = None,
974
+ version: str | None = None,
975
+ unset: bool = False,
976
+ override_reason: str | None = None,
977
+ override_reason_reference_url: str | None = None,
978
+ user_email: str | None = None,
979
+ bearer_token: str | None = None,
980
+ ) -> bool:
981
+ """Set or clear a workspace-level version override for a connector type.
982
+
983
+ This pins ALL instances of a connector type within a workspace to a specific version.
984
+ For example, pinning 'source-github' at workspace level means all GitHub sources
985
+ in that workspace will use the pinned version.
986
+
987
+ Args:
988
+ workspace_id: The workspace ID
989
+ connector_name: The connector name (e.g., 'source-github')
990
+ connector_type: Either "source" or "destination"
991
+ api_root: The API root URL
992
+ client_id: The Airbyte Cloud client ID (required if no bearer_token)
993
+ client_secret: The Airbyte Cloud client secret (required if no bearer_token)
994
+ version: The version to pin to (e.g., "0.1.0"), or None to unset
995
+ unset: If True, removes any existing override
996
+ override_reason: Required when setting. Explanation for the override
997
+ override_reason_reference_url: Optional URL with more context
998
+ user_email: Email of user creating the override
999
+ bearer_token: Pre-existing bearer token (takes precedence over client credentials)
1000
+
1001
+ Returns:
1002
+ True if operation succeeded, False if no override existed (unset only)
1003
+
1004
+ Raises:
1005
+ PyAirbyteInputError: If the API request fails or parameters are invalid
1006
+ """
1007
+ # Input validation
1008
+ if (version is None) == (not unset):
1009
+ raise PyAirbyteInputError(
1010
+ message="Must specify EXACTLY ONE of version (to set) OR unset=True (to clear), but not both",
1011
+ )
1012
+
1013
+ if not unset and (not override_reason or len(override_reason.strip()) < 10):
1014
+ raise PyAirbyteInputError(
1015
+ message="override_reason is required when setting a version and must be at least 10 characters",
1016
+ )
1017
+
1018
+ access_token = _get_access_token(client_id, client_secret, bearer_token)
1019
+
1020
+ # Resolve connector name to actor_definition_id using the shared registry lookup
1021
+ actor_definition_id = _resolve_canonical_name_to_definition_id(connector_name)
1022
+
1023
+ if unset:
1024
+ # Get the existing workspace-level configuration
1025
+ active_config = _get_scoped_configuration_context(
1026
+ actor_definition_id=actor_definition_id,
1027
+ scope_type=_ScopeType.WORKSPACE,
1028
+ scope_id=workspace_id,
1029
+ api_root=api_root,
1030
+ access_token=access_token,
1031
+ )
1032
+
1033
+ if not active_config:
1034
+ return False
1035
+
1036
+ # Verify this is actually a workspace-scoped config (not inherited from org)
1037
+ api_scope_type = active_config.get("scope_type", "").lower()
1038
+ api_scope_id = active_config.get("scope_id", "")
1039
+ if api_scope_type != _ScopeType.WORKSPACE.value or api_scope_id != workspace_id:
1040
+ raise PyAirbyteInputError(
1041
+ message=f"Cannot delete: the active config is not workspace-scoped. "
1042
+ f"Expected scope_type='{_ScopeType.WORKSPACE.value}' and scope_id='{workspace_id}', "
1043
+ f"but got scope_type='{api_scope_type}' and scope_id='{api_scope_id}'. "
1044
+ f"This may be an inherited config from organization level.",
1045
+ context={
1046
+ "workspace_id": workspace_id,
1047
+ "expected_scope_type": _ScopeType.WORKSPACE.value,
1048
+ "actual_scope_type": api_scope_type,
1049
+ "actual_scope_id": api_scope_id,
1050
+ "full_config": active_config,
1051
+ },
1052
+ )
1053
+
1054
+ # Delete the configuration
1055
+ delete_endpoint = f"{api_root}/scoped_configuration/delete"
1056
+ delete_payload = {"scopedConfigurationId": active_config["id"]}
1057
+
1058
+ response = requests.post(
1059
+ delete_endpoint,
1060
+ json=delete_payload,
1061
+ headers={
1062
+ "Authorization": f"Bearer {access_token}",
1063
+ "User-Agent": ops_constants.USER_AGENT,
1064
+ "Content-Type": "application/json",
1065
+ },
1066
+ timeout=30,
1067
+ )
1068
+
1069
+ if response.status_code not in (200, 204):
1070
+ raise PyAirbyteInputError(
1071
+ message=f"Failed to delete workspace version override: {response.status_code} {response.text}",
1072
+ context={
1073
+ "delete_endpoint": delete_endpoint,
1074
+ "config_id": active_config["id"],
1075
+ "status_code": response.status_code,
1076
+ "response": response.text,
1077
+ },
1078
+ )
1079
+
1080
+ return True
1081
+
1082
+ # Set a new workspace-level override
1083
+ # Resolve version string to version ID
1084
+ version_id = resolve_connector_version_id(
1085
+ actor_definition_id=actor_definition_id,
1086
+ connector_type=connector_type,
1087
+ version=version,
1088
+ api_root=api_root,
1089
+ bearer_token=access_token,
1090
+ )
1091
+
1092
+ # Check for existing workspace-level configuration
1093
+ existing_config = _get_scoped_configuration_context(
1094
+ actor_definition_id=actor_definition_id,
1095
+ scope_type=_ScopeType.WORKSPACE,
1096
+ scope_id=workspace_id,
1097
+ api_root=api_root,
1098
+ access_token=access_token,
1099
+ )
1100
+
1101
+ if existing_config:
1102
+ existing_version_id = existing_config.get("value")
1103
+ existing_version_name = existing_config.get("value_name", "unknown")
1104
+
1105
+ # If already pinned to the same version, no action needed
1106
+ if existing_version_id == version_id:
1107
+ raise PyAirbyteInputError(
1108
+ message=f"Workspace is already pinned to version {existing_version_name} for {connector_name}. "
1109
+ f"Use unset=True first if you want to re-pin to a different version.",
1110
+ context={
1111
+ "workspace_id": workspace_id,
1112
+ "connector_name": connector_name,
1113
+ "existing_version": existing_version_name,
1114
+ "requested_version": version,
1115
+ },
1116
+ )
1117
+
1118
+ # Verify this is a workspace-scoped config before deleting
1119
+ api_scope_type = existing_config.get("scope_type", "").lower()
1120
+ api_scope_id = existing_config.get("scope_id", "")
1121
+ if (
1122
+ api_scope_type == _ScopeType.WORKSPACE.value
1123
+ and api_scope_id == workspace_id
1124
+ ):
1125
+ # Delete existing workspace-level config before creating new one
1126
+ delete_endpoint = f"{api_root}/scoped_configuration/delete"
1127
+ delete_payload = {"scopedConfigurationId": existing_config["id"]}
1128
+
1129
+ delete_response = requests.post(
1130
+ delete_endpoint,
1131
+ json=delete_payload,
1132
+ headers={
1133
+ "Authorization": f"Bearer {access_token}",
1134
+ "User-Agent": ops_constants.USER_AGENT,
1135
+ "Content-Type": "application/json",
1136
+ },
1137
+ timeout=30,
1138
+ )
1139
+
1140
+ if delete_response.status_code not in (200, 204):
1141
+ raise PyAirbyteInputError(
1142
+ message=f"Failed to delete existing workspace version override: "
1143
+ f"{delete_response.status_code} {delete_response.text}",
1144
+ )
1145
+
1146
+ # Get user ID from email
1147
+ if not user_email:
1148
+ raise PyAirbyteInputError(
1149
+ message="user_email is required to set a version override",
1150
+ )
1151
+ origin = get_user_id_by_email(
1152
+ email=user_email,
1153
+ api_root=api_root,
1154
+ bearer_token=access_token,
1155
+ )
1156
+
1157
+ # Create the override
1158
+ endpoint = f"{api_root}/scoped_configuration/create"
1159
+ payload: dict[str, Any] = {
1160
+ "config_key": _ScopedConfigKey.CONNECTOR_VERSION.value,
1161
+ "resource_type": _ResourceType.ACTOR_DEFINITION.value,
1162
+ "resource_id": actor_definition_id,
1163
+ "scope_type": _ScopeType.WORKSPACE.value,
1164
+ "scope_id": workspace_id,
1165
+ "value": version_id,
1166
+ "description": override_reason,
1167
+ "origin_type": _OriginType.USER.value,
1168
+ "origin": origin,
1169
+ }
1170
+
1171
+ if override_reason_reference_url:
1172
+ payload["reference_url"] = override_reason_reference_url
1173
+
1174
+ response = requests.post(
1175
+ endpoint,
1176
+ json=payload,
1177
+ headers={
1178
+ "Authorization": f"Bearer {access_token}",
1179
+ "User-Agent": ops_constants.USER_AGENT,
1180
+ "Content-Type": "application/json",
1181
+ },
1182
+ timeout=30,
1183
+ )
1184
+
1185
+ if response.status_code not in (200, 201):
1186
+ raise PyAirbyteInputError(
1187
+ message=f"Failed to set workspace version override: {response.status_code} {response.text}",
1188
+ context={
1189
+ "workspace_id": workspace_id,
1190
+ "connector_name": connector_name,
1191
+ "version": version,
1192
+ "endpoint": endpoint,
1193
+ "status_code": response.status_code,
1194
+ "response": response.text,
1195
+ },
1196
+ )
1197
+
1198
+ return True
1199
+
1200
+
1201
+ def set_organization_connector_version_override(
1202
+ organization_id: str,
1203
+ connector_name: str,
1204
+ connector_type: Literal["source", "destination"],
1205
+ api_root: str,
1206
+ client_id: str | None = None,
1207
+ client_secret: str | None = None,
1208
+ version: str | None = None,
1209
+ unset: bool = False,
1210
+ override_reason: str | None = None,
1211
+ override_reason_reference_url: str | None = None,
1212
+ user_email: str | None = None,
1213
+ bearer_token: str | None = None,
1214
+ ) -> bool:
1215
+ """Set or clear an organization-level version override for a connector type.
1216
+
1217
+ This pins ALL instances of a connector type across an entire organization to a
1218
+ specific version. For example, pinning 'source-github' at organization level means
1219
+ all GitHub sources in all workspaces within that organization will use the pinned version.
1220
+
1221
+ Args:
1222
+ organization_id: The organization ID
1223
+ connector_name: The connector name (e.g., 'source-github')
1224
+ connector_type: Either "source" or "destination"
1225
+ api_root: The API root URL
1226
+ client_id: The Airbyte Cloud client ID (required if no bearer_token)
1227
+ client_secret: The Airbyte Cloud client secret (required if no bearer_token)
1228
+ version: The version to pin to (e.g., "0.1.0"), or None to unset
1229
+ unset: If True, removes any existing override
1230
+ override_reason: Required when setting. Explanation for the override
1231
+ override_reason_reference_url: Optional URL with more context
1232
+ user_email: Email of user creating the override
1233
+ bearer_token: Pre-existing bearer token (takes precedence over client credentials)
1234
+
1235
+ Returns:
1236
+ True if operation succeeded, False if no override existed (unset only)
1237
+
1238
+ Raises:
1239
+ PyAirbyteInputError: If the API request fails or parameters are invalid
1240
+ """
1241
+ # Input validation
1242
+ if (version is None) == (not unset):
1243
+ raise PyAirbyteInputError(
1244
+ message="Must specify EXACTLY ONE of version (to set) OR unset=True (to clear), but not both",
1245
+ )
1246
+
1247
+ if not unset and (not override_reason or len(override_reason.strip()) < 10):
1248
+ raise PyAirbyteInputError(
1249
+ message="override_reason is required when setting a version and must be at least 10 characters",
1250
+ )
1251
+
1252
+ access_token = _get_access_token(client_id, client_secret, bearer_token)
1253
+
1254
+ # Resolve connector name to actor_definition_id using the shared registry lookup
1255
+ actor_definition_id = _resolve_canonical_name_to_definition_id(connector_name)
1256
+
1257
+ if unset:
1258
+ # Get the existing organization-level configuration
1259
+ active_config = _get_scoped_configuration_context(
1260
+ actor_definition_id=actor_definition_id,
1261
+ scope_type=_ScopeType.ORGANIZATION,
1262
+ scope_id=organization_id,
1263
+ api_root=api_root,
1264
+ access_token=access_token,
1265
+ )
1266
+
1267
+ if not active_config:
1268
+ return False
1269
+
1270
+ # Verify this is actually an organization-scoped config
1271
+ api_scope_type = active_config.get("scope_type", "").lower()
1272
+ api_scope_id = active_config.get("scope_id", "")
1273
+ if (
1274
+ api_scope_type != _ScopeType.ORGANIZATION.value
1275
+ or api_scope_id != organization_id
1276
+ ):
1277
+ raise PyAirbyteInputError(
1278
+ message=f"Cannot delete: the active config is not organization-scoped. "
1279
+ f"Expected scope_type='{_ScopeType.ORGANIZATION.value}' and scope_id='{organization_id}', "
1280
+ f"but got scope_type='{api_scope_type}' and scope_id='{api_scope_id}'.",
1281
+ context={
1282
+ "organization_id": organization_id,
1283
+ "expected_scope_type": _ScopeType.ORGANIZATION.value,
1284
+ "actual_scope_type": api_scope_type,
1285
+ "actual_scope_id": api_scope_id,
1286
+ "full_config": active_config,
1287
+ },
1288
+ )
1289
+
1290
+ # Delete the configuration
1291
+ delete_endpoint = f"{api_root}/scoped_configuration/delete"
1292
+ delete_payload = {"scopedConfigurationId": active_config["id"]}
1293
+
1294
+ response = requests.post(
1295
+ delete_endpoint,
1296
+ json=delete_payload,
1297
+ headers={
1298
+ "Authorization": f"Bearer {access_token}",
1299
+ "User-Agent": ops_constants.USER_AGENT,
1300
+ "Content-Type": "application/json",
1301
+ },
1302
+ timeout=30,
1303
+ )
1304
+
1305
+ if response.status_code not in (200, 204):
1306
+ raise PyAirbyteInputError(
1307
+ message=f"Failed to delete organization version override: {response.status_code} {response.text}",
1308
+ context={
1309
+ "delete_endpoint": delete_endpoint,
1310
+ "config_id": active_config["id"],
1311
+ "status_code": response.status_code,
1312
+ "response": response.text,
1313
+ },
1314
+ )
1315
+
1316
+ return True
1317
+
1318
+ # Set a new organization-level override
1319
+ # Resolve version string to version ID
1320
+ version_id = resolve_connector_version_id(
1321
+ actor_definition_id=actor_definition_id,
1322
+ connector_type=connector_type,
1323
+ version=version,
1324
+ api_root=api_root,
1325
+ bearer_token=access_token,
1326
+ )
1327
+
1328
+ # Check for existing organization-level configuration
1329
+ existing_config = _get_scoped_configuration_context(
1330
+ actor_definition_id=actor_definition_id,
1331
+ scope_type=_ScopeType.ORGANIZATION,
1332
+ scope_id=organization_id,
1333
+ api_root=api_root,
1334
+ access_token=access_token,
1335
+ )
1336
+
1337
+ if existing_config:
1338
+ existing_version_id = existing_config.get("value")
1339
+ existing_version_name = existing_config.get("value_name", "unknown")
1340
+
1341
+ # If already pinned to the same version, no action needed
1342
+ if existing_version_id == version_id:
1343
+ raise PyAirbyteInputError(
1344
+ message=f"Organization is already pinned to version {existing_version_name} for {connector_name}. "
1345
+ f"Use unset=True first if you want to re-pin to a different version.",
1346
+ context={
1347
+ "organization_id": organization_id,
1348
+ "connector_name": connector_name,
1349
+ "existing_version": existing_version_name,
1350
+ "requested_version": version,
1351
+ },
1352
+ )
1353
+
1354
+ # Verify this is an organization-scoped config before deleting
1355
+ api_scope_type = existing_config.get("scope_type", "").lower()
1356
+ api_scope_id = existing_config.get("scope_id", "")
1357
+ if (
1358
+ api_scope_type == _ScopeType.ORGANIZATION.value
1359
+ and api_scope_id == organization_id
1360
+ ):
1361
+ # Delete existing organization-level config before creating new one
1362
+ delete_endpoint = f"{api_root}/scoped_configuration/delete"
1363
+ delete_payload = {"scopedConfigurationId": existing_config["id"]}
1364
+
1365
+ delete_response = requests.post(
1366
+ delete_endpoint,
1367
+ json=delete_payload,
1368
+ headers={
1369
+ "Authorization": f"Bearer {access_token}",
1370
+ "User-Agent": ops_constants.USER_AGENT,
1371
+ "Content-Type": "application/json",
1372
+ },
1373
+ timeout=30,
1374
+ )
1375
+
1376
+ if delete_response.status_code not in (200, 204):
1377
+ raise PyAirbyteInputError(
1378
+ message=f"Failed to delete existing organization version override: "
1379
+ f"{delete_response.status_code} {delete_response.text}",
1380
+ )
1381
+
1382
+ # Get user ID from email
1383
+ if not user_email:
1384
+ raise PyAirbyteInputError(
1385
+ message="user_email is required to set a version override",
1386
+ )
1387
+ origin = get_user_id_by_email(
1388
+ email=user_email,
1389
+ api_root=api_root,
1390
+ bearer_token=access_token,
1391
+ )
1392
+
1393
+ # Create the override
1394
+ endpoint = f"{api_root}/scoped_configuration/create"
1395
+ payload: dict[str, Any] = {
1396
+ "config_key": _ScopedConfigKey.CONNECTOR_VERSION.value,
1397
+ "resource_type": _ResourceType.ACTOR_DEFINITION.value,
1398
+ "resource_id": actor_definition_id,
1399
+ "scope_type": _ScopeType.ORGANIZATION.value,
1400
+ "scope_id": organization_id,
1401
+ "value": version_id,
1402
+ "description": override_reason,
1403
+ "origin_type": _OriginType.USER.value,
1404
+ "origin": origin,
1405
+ }
1406
+
1407
+ if override_reason_reference_url:
1408
+ payload["reference_url"] = override_reason_reference_url
1409
+
1410
+ response = requests.post(
1411
+ endpoint,
1412
+ json=payload,
1413
+ headers={
1414
+ "Authorization": f"Bearer {access_token}",
1415
+ "User-Agent": ops_constants.USER_AGENT,
1416
+ "Content-Type": "application/json",
1417
+ },
1418
+ timeout=30,
1419
+ )
1420
+
1421
+ if response.status_code not in (200, 201):
1422
+ raise PyAirbyteInputError(
1423
+ message=f"Failed to set organization version override: {response.status_code} {response.text}",
1424
+ context={
1425
+ "organization_id": organization_id,
1426
+ "connector_name": connector_name,
1427
+ "version": version,
1428
+ "endpoint": endpoint,
1429
+ "status_code": response.status_code,
1430
+ "response": response.text,
1431
+ },
1432
+ )
1433
+
1434
+ return True