connection-hub 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. connection_hub-0.0.3/PKG-INFO +121 -0
  2. connection_hub-0.0.3/README.md +99 -0
  3. connection_hub-0.0.3/pyproject.toml +43 -0
  4. connection_hub-0.0.3/setup.cfg +4 -0
  5. connection_hub-0.0.3/src/connection_hub/__init__.py +58 -0
  6. connection_hub-0.0.3/src/connection_hub/agent_account_scope.py +155 -0
  7. connection_hub-0.0.3/src/connection_hub/authenticators/__init__.py +34 -0
  8. connection_hub-0.0.3/src/connection_hub/authenticators/authority.py +265 -0
  9. connection_hub-0.0.3/src/connection_hub/authenticators/client.py +75 -0
  10. connection_hub-0.0.3/src/connection_hub/authenticators/models.py +309 -0
  11. connection_hub-0.0.3/src/connection_hub/authority_inventory.py +342 -0
  12. connection_hub-0.0.3/src/connection_hub/authority_projection.py +241 -0
  13. connection_hub-0.0.3/src/connection_hub/authority_providers/__init__.py +13 -0
  14. connection_hub-0.0.3/src/connection_hub/authority_registry.py +430 -0
  15. connection_hub-0.0.3/src/connection_hub/authority_registry_client.py +235 -0
  16. connection_hub-0.0.3/src/connection_hub/authority_registry_config.py +365 -0
  17. connection_hub-0.0.3/src/connection_hub/client.py +135 -0
  18. connection_hub-0.0.3/src/connection_hub/connection_edges.py +209 -0
  19. connection_hub-0.0.3/src/connection_hub/connector_app_resolution.py +82 -0
  20. connection_hub-0.0.3/src/connection_hub/consent_state.py +227 -0
  21. connection_hub-0.0.3/src/connection_hub/consent_state_adapters.py +130 -0
  22. connection_hub-0.0.3/src/connection_hub/contract.py +320 -0
  23. connection_hub-0.0.3/src/connection_hub/custom_authorities/__init__.py +30 -0
  24. connection_hub-0.0.3/src/connection_hub/delegated_credentials/__init__.py +4 -0
  25. connection_hub-0.0.3/src/connection_hub/delegated_credentials/access_map.py +225 -0
  26. connection_hub-0.0.3/src/connection_hub/delegated_credentials/admission.py +506 -0
  27. connection_hub-0.0.3/src/connection_hub/delegated_credentials/automation_access.py +3318 -0
  28. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cache_io.py +44 -0
  29. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cache_settings.py +121 -0
  30. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/__init__.py +48 -0
  31. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/cache.py +356 -0
  32. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/handles.py +66 -0
  33. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/migration.py +101 -0
  34. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/model.py +428 -0
  35. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/persistence.py +159 -0
  36. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/resolver.py +199 -0
  37. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/service.py +379 -0
  38. connection_hub-0.0.3/src/connection_hub/delegated_credentials/cards/store.py +234 -0
  39. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/__init__.py +52 -0
  40. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/authorization.py +344 -0
  41. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/drift.py +308 -0
  42. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/hashing.py +33 -0
  43. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/models.py +129 -0
  44. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/publisher.py +203 -0
  45. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/reconcile.py +168 -0
  46. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/resolver.py +131 -0
  47. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/runtime_cache.py +131 -0
  48. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/source.py +26 -0
  49. connection_hub-0.0.3/src/connection_hub/delegated_credentials/catalog/store.py +124 -0
  50. connection_hub-0.0.3/src/connection_hub/delegated_credentials/consent_denial.py +533 -0
  51. connection_hub-0.0.3/src/connection_hub/delegated_credentials/credential_view.py +304 -0
  52. connection_hub-0.0.3/src/connection_hub/delegated_credentials/durable_io.py +108 -0
  53. connection_hub-0.0.3/src/connection_hub/delegated_credentials/live_grant.py +145 -0
  54. connection_hub-0.0.3/src/connection_hub/delegated_credentials/named_service_policy.py +296 -0
  55. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/__init__.py +42 -0
  56. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/account_requirements.py +335 -0
  57. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/authority.py +198 -0
  58. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/client_metadata.py +535 -0
  59. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/clients.py +168 -0
  60. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/config.py +669 -0
  61. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/consent.py +885 -0
  62. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/flow.py +126 -0
  63. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/grants.py +104 -0
  64. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/metadata.py +155 -0
  65. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/pkce.py +21 -0
  66. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/store.py +574 -0
  67. connection_hub-0.0.3/src/connection_hub/delegated_credentials/oauth/surface_policy.py +833 -0
  68. connection_hub-0.0.3/src/connection_hub/delegated_credentials/serving.py +208 -0
  69. connection_hub-0.0.3/src/connection_hub/delegated_mcp.py +309 -0
  70. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/__init__.py +105 -0
  71. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/adapters.py +239 -0
  72. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/broker.py +557 -0
  73. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/client.py +266 -0
  74. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/config.py +58 -0
  75. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/consent_demand.py +721 -0
  76. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/models.py +547 -0
  77. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/oauth.py +179 -0
  78. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/operations.py +675 -0
  79. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/preflight.py +443 -0
  80. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/__init__.py +27 -0
  81. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/email.py +28 -0
  82. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/generic_oauth.py +174 -0
  83. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/google.py +88 -0
  84. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/linkedin.py +202 -0
  85. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/providers/slack.py +92 -0
  86. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/public_base.py +57 -0
  87. connection_hub-0.0.3/src/connection_hub/delegated_to_kdcube/store.py +406 -0
  88. connection_hub-0.0.3/src/connection_hub/federated_tokens/__init__.py +32 -0
  89. connection_hub-0.0.3/src/connection_hub/federated_tokens/data_bus.py +363 -0
  90. connection_hub-0.0.3/src/connection_hub/hub/__init__.py +4 -0
  91. connection_hub-0.0.3/src/connection_hub/hub/authenticator_store.py +275 -0
  92. connection_hub-0.0.3/src/connection_hub/hub/edges.py +650 -0
  93. connection_hub-0.0.3/src/connection_hub/hub/resolver.py +507 -0
  94. connection_hub-0.0.3/src/connection_hub/mcp_consent.py +294 -0
  95. connection_hub-0.0.3/src/connection_hub/mcp_metadata.py +134 -0
  96. connection_hub-0.0.3/src/connection_hub/mcp_result.py +351 -0
  97. connection_hub-0.0.3/src/connection_hub/mcp_tool_enforcement.py +260 -0
  98. connection_hub-0.0.3/src/connection_hub/named_service_admission.py +511 -0
  99. connection_hub-0.0.3/src/connection_hub/named_service_boundary.py +229 -0
  100. connection_hub-0.0.3/src/connection_hub/py.typed +1 -0
  101. connection_hub-0.0.3/src/connection_hub/request_auth.py +241 -0
  102. connection_hub-0.0.3/src/connection_hub.egg-info/PKG-INFO +121 -0
  103. connection_hub-0.0.3/src/connection_hub.egg-info/SOURCES.txt +134 -0
  104. connection_hub-0.0.3/src/connection_hub.egg-info/dependency_links.txt +1 -0
  105. connection_hub-0.0.3/src/connection_hub.egg-info/requires.txt +6 -0
  106. connection_hub-0.0.3/src/connection_hub.egg-info/top_level.txt +1 -0
  107. connection_hub-0.0.3/tests/test_access_map.py +158 -0
  108. connection_hub-0.0.3/tests/test_account_store.py +67 -0
  109. connection_hub-0.0.3/tests/test_admission.py +225 -0
  110. connection_hub-0.0.3/tests/test_authority_projection.py +45 -0
  111. connection_hub-0.0.3/tests/test_authority_registry.py +90 -0
  112. connection_hub-0.0.3/tests/test_authority_registry_config.py +248 -0
  113. connection_hub-0.0.3/tests/test_cache_settings.py +49 -0
  114. connection_hub-0.0.3/tests/test_card_service.py +125 -0
  115. connection_hub-0.0.3/tests/test_catalog_documents.py +160 -0
  116. connection_hub-0.0.3/tests/test_catalog_publisher.py +64 -0
  117. connection_hub-0.0.3/tests/test_client.py +59 -0
  118. connection_hub-0.0.3/tests/test_connector_app_resolution.py +19 -0
  119. connection_hub-0.0.3/tests/test_consent_demand.py +145 -0
  120. connection_hub-0.0.3/tests/test_consent_state.py +124 -0
  121. connection_hub-0.0.3/tests/test_contract.py +41 -0
  122. connection_hub-0.0.3/tests/test_credential_view.py +101 -0
  123. connection_hub-0.0.3/tests/test_delegated_mcp.py +274 -0
  124. connection_hub-0.0.3/tests/test_federated_tokens.py +107 -0
  125. connection_hub-0.0.3/tests/test_host_ports.py +92 -0
  126. connection_hub-0.0.3/tests/test_mcp_consent.py +120 -0
  127. connection_hub-0.0.3/tests/test_mcp_result.py +109 -0
  128. connection_hub-0.0.3/tests/test_mcp_tool_enforcement.py +104 -0
  129. connection_hub-0.0.3/tests/test_named_service_admission.py +139 -0
  130. connection_hub-0.0.3/tests/test_named_service_boundary.py +96 -0
  131. connection_hub-0.0.3/tests/test_oauth_config.py +55 -0
  132. connection_hub-0.0.3/tests/test_oauth_grants.py +84 -0
  133. connection_hub-0.0.3/tests/test_public_import_surface.py +19 -0
  134. connection_hub-0.0.3/tests/test_request_auth.py +107 -0
  135. connection_hub-0.0.3/tests/test_serving_ports.py +71 -0
  136. connection_hub-0.0.3/tests/test_surface_policy.py +170 -0
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: connection-hub
3
+ Version: 0.0.3
4
+ Summary: Connection Hub delegated-access authority and client SDK.
5
+ Author: Elena Viter
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/elenaviter/app-ecosystem
8
+ Project-URL: Repository, https://github.com/elenaviter/app-ecosystem
9
+ Project-URL: Documentation, https://github.com/elenaviter/app-ecosystem/tree/main/docs/connection-hub
10
+ Project-URL: Issues, https://github.com/elenaviter/app-ecosystem/issues
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Security
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: aiohttp<4,>=3.9
18
+ Requires-Dist: httpx<1,>=0.27
19
+ Provides-Extra: test
20
+ Requires-Dist: pytest<10,>=8; extra == "test"
21
+ Requires-Dist: pytest-asyncio<2,>=0.23; extra == "test"
22
+
23
+ # Connection Hub
24
+
25
+ The Python library and client SDK for the Connection Hub product.
26
+
27
+ Connection Hub gives every agent, automation, and connected application its own
28
+ delegated-access card. The card records whose authority the caller uses, which
29
+ resources and operations it may reach, which connected accounts it may use,
30
+ and when that authority expires. A service resolves the current card and
31
+ current capability catalog at the operation boundary, so an edit or revocation
32
+ applies to the next call.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ python -m pip install connection-hub
38
+ ```
39
+
40
+ `0.0.3` is an alpha release. It contains the portable implementation used by
41
+ the Connection Hub application in this repository:
42
+
43
+ - versioned delegated cards and capability catalogs;
44
+ - live card/catalog admission for managed REST, MCP, and named-service calls;
45
+ - delegated OAuth client and connected-account policy contracts;
46
+ - structured, actionable denial results;
47
+ - direct protected-service admission with an opaque delegated bearer and an
48
+ independent replay-protected workload proof;
49
+ - explicit host ports for storage, identity, dispatch, secrets, and live
50
+ delivery.
51
+
52
+ The same product is currently hosted in KDCube under the technical app id
53
+ [`connection-hub@1-0`](../../apps/connection-hub@1-0/README.md). The library
54
+ owns portable authority semantics and client contracts; the application host
55
+ supplies authenticated sessions, storage, secret resolution, Redis protocol
56
+ state, HTTP surfaces, and the user interface.
57
+
58
+ ## Direct Protected-Service Admission
59
+
60
+ An external backend can accept a user's opaque delegated bearer and ask the
61
+ Connection Hub for a live decision about one concrete operation. The backend
62
+ also signs the request with its own registered workload secret; possession of
63
+ the user bearer alone is not service identity.
64
+
65
+ ```python
66
+ import secrets
67
+ import time
68
+
69
+ from connection_hub.delegated_credentials.admission import (
70
+ AdmissionRequest,
71
+ sign_admission_request,
72
+ )
73
+
74
+ request = AdmissionRequest(
75
+ resource="https://api.example.test/customers",
76
+ operation="customers.search",
77
+ )
78
+ timestamp = str(int(time.time()))
79
+ nonce = secrets.token_urlsafe(24)
80
+ signature = sign_admission_request(
81
+ secret=service_signing_secret,
82
+ service_id="crm-api",
83
+ timestamp=timestamp,
84
+ nonce=nonce,
85
+ delegated_token=user_delegated_bearer,
86
+ request=request,
87
+ )
88
+ ```
89
+
90
+ The service sends the semantic request body and the four `X-Connection-Hub-*` proof
91
+ headers to the configured Connection Hub admission endpoint, with the opaque
92
+ delegated bearer in `Authorization: Bearer ...`. An allow response contains a
93
+ service-scoped subject and only the bounded authority relevant to that
94
+ operation. It never returns provider credentials or the platform's internal
95
+ user id.
96
+
97
+ See the runnable
98
+ [`direct-admission-service`](../../examples/connection-hub/direct-admission-service/README.md)
99
+ and the [deployment recipe](../../docs/connection-hub/recipes/direct-protected-service.md).
100
+
101
+ ## Integration Boundaries
102
+
103
+ - The service registry authenticates workloads and binds each service to
104
+ resource selectors. It does not duplicate the operation/grant catalog.
105
+ - Every decision intersects the delegated bearer with the current card and
106
+ active catalog. A cached allow is not an authority source.
107
+ - Connected-account credential resolution is a separate trusted operation;
108
+ direct admission does not export provider secrets.
109
+ - A protected backend still applies its own domain authorization after
110
+ Connection Hub admission.
111
+
112
+ ## Documentation
113
+
114
+ - [Connection Hub architecture and semantic requirements](../../docs/connection-hub/connection-hub-architecture.md)
115
+ - [Delegated authority and admission](../../docs/connection-hub/package/delegated-authority-and-admission.md)
116
+ - [Delegated access cards](../../docs/connection-hub/package/delegated-cards.md)
117
+ - [OAuth delegated credential protocol](../../docs/connection-hub/package/oauth-delegated-credential-protocol.md)
118
+ - [Package extraction boundary](../../docs/connection-hub/package/extraction-architecture.md)
119
+ - [Package release procedure](../../docs/package-releases.md)
120
+
121
+ License: MIT. Source: https://github.com/elenaviter/app-ecosystem
@@ -0,0 +1,99 @@
1
+ # Connection Hub
2
+
3
+ The Python library and client SDK for the Connection Hub product.
4
+
5
+ Connection Hub gives every agent, automation, and connected application its own
6
+ delegated-access card. The card records whose authority the caller uses, which
7
+ resources and operations it may reach, which connected accounts it may use,
8
+ and when that authority expires. A service resolves the current card and
9
+ current capability catalog at the operation boundary, so an edit or revocation
10
+ applies to the next call.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ python -m pip install connection-hub
16
+ ```
17
+
18
+ `0.0.3` is an alpha release. It contains the portable implementation used by
19
+ the Connection Hub application in this repository:
20
+
21
+ - versioned delegated cards and capability catalogs;
22
+ - live card/catalog admission for managed REST, MCP, and named-service calls;
23
+ - delegated OAuth client and connected-account policy contracts;
24
+ - structured, actionable denial results;
25
+ - direct protected-service admission with an opaque delegated bearer and an
26
+ independent replay-protected workload proof;
27
+ - explicit host ports for storage, identity, dispatch, secrets, and live
28
+ delivery.
29
+
30
+ The same product is currently hosted in KDCube under the technical app id
31
+ [`connection-hub@1-0`](../../apps/connection-hub@1-0/README.md). The library
32
+ owns portable authority semantics and client contracts; the application host
33
+ supplies authenticated sessions, storage, secret resolution, Redis protocol
34
+ state, HTTP surfaces, and the user interface.
35
+
36
+ ## Direct Protected-Service Admission
37
+
38
+ An external backend can accept a user's opaque delegated bearer and ask the
39
+ Connection Hub for a live decision about one concrete operation. The backend
40
+ also signs the request with its own registered workload secret; possession of
41
+ the user bearer alone is not service identity.
42
+
43
+ ```python
44
+ import secrets
45
+ import time
46
+
47
+ from connection_hub.delegated_credentials.admission import (
48
+ AdmissionRequest,
49
+ sign_admission_request,
50
+ )
51
+
52
+ request = AdmissionRequest(
53
+ resource="https://api.example.test/customers",
54
+ operation="customers.search",
55
+ )
56
+ timestamp = str(int(time.time()))
57
+ nonce = secrets.token_urlsafe(24)
58
+ signature = sign_admission_request(
59
+ secret=service_signing_secret,
60
+ service_id="crm-api",
61
+ timestamp=timestamp,
62
+ nonce=nonce,
63
+ delegated_token=user_delegated_bearer,
64
+ request=request,
65
+ )
66
+ ```
67
+
68
+ The service sends the semantic request body and the four `X-Connection-Hub-*` proof
69
+ headers to the configured Connection Hub admission endpoint, with the opaque
70
+ delegated bearer in `Authorization: Bearer ...`. An allow response contains a
71
+ service-scoped subject and only the bounded authority relevant to that
72
+ operation. It never returns provider credentials or the platform's internal
73
+ user id.
74
+
75
+ See the runnable
76
+ [`direct-admission-service`](../../examples/connection-hub/direct-admission-service/README.md)
77
+ and the [deployment recipe](../../docs/connection-hub/recipes/direct-protected-service.md).
78
+
79
+ ## Integration Boundaries
80
+
81
+ - The service registry authenticates workloads and binds each service to
82
+ resource selectors. It does not duplicate the operation/grant catalog.
83
+ - Every decision intersects the delegated bearer with the current card and
84
+ active catalog. A cached allow is not an authority source.
85
+ - Connected-account credential resolution is a separate trusted operation;
86
+ direct admission does not export provider secrets.
87
+ - A protected backend still applies its own domain authorization after
88
+ Connection Hub admission.
89
+
90
+ ## Documentation
91
+
92
+ - [Connection Hub architecture and semantic requirements](../../docs/connection-hub/connection-hub-architecture.md)
93
+ - [Delegated authority and admission](../../docs/connection-hub/package/delegated-authority-and-admission.md)
94
+ - [Delegated access cards](../../docs/connection-hub/package/delegated-cards.md)
95
+ - [OAuth delegated credential protocol](../../docs/connection-hub/package/oauth-delegated-credential-protocol.md)
96
+ - [Package extraction boundary](../../docs/connection-hub/package/extraction-architecture.md)
97
+ - [Package release procedure](../../docs/package-releases.md)
98
+
99
+ License: MIT. Source: https://github.com/elenaviter/app-ecosystem
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "connection-hub"
7
+ version = "0.0.3"
8
+ description = "Connection Hub delegated-access authority and client SDK."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "Elena Viter" }]
12
+ requires-python = ">=3.10"
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Topic :: Security",
18
+ ]
19
+ dependencies = [
20
+ "aiohttp>=3.9,<4",
21
+ "httpx>=0.27,<1",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ test = [
26
+ "pytest>=8,<10",
27
+ "pytest-asyncio>=0.23,<2",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/elenaviter/app-ecosystem"
32
+ Repository = "https://github.com/elenaviter/app-ecosystem"
33
+ Documentation = "https://github.com/elenaviter/app-ecosystem/tree/main/docs/connection-hub"
34
+ Issues = "https://github.com/elenaviter/app-ecosystem/issues"
35
+
36
+ [tool.setuptools.packages.find]
37
+ where = ["src"]
38
+
39
+ [tool.setuptools.package-data]
40
+ connection_hub = ["py.typed"]
41
+
42
+ [tool.pytest.ini_options]
43
+ asyncio_mode = "auto"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,58 @@
1
+ """Connection Hub delegated-access authority and client SDK.
2
+
3
+ Every caller has its own identity card, authority lives in one central record,
4
+ and a guarded boundary resolves current authority on every call.
5
+
6
+ Version 0.0.3 is a development release. It contains the host-neutral authority
7
+ core, delegated card/catalog contracts, OAuth and connected-account policy,
8
+ named-service admission, and direct protected-service admission. Host storage,
9
+ identity, and transport adapters remain explicit integration responsibilities.
10
+ See the repository for status: https://github.com/elenaviter/app-ecosystem
11
+ """
12
+
13
+ from importlib import import_module
14
+ from typing import Any
15
+
16
+ __version__ = "0.0.3"
17
+
18
+ _EXPORTS: dict[str, str] = {}
19
+ for name in (
20
+ "NAMESPACE",
21
+ "CONNECTION_CATALOG",
22
+ "CONNECTION_STATUS",
23
+ "CONNECTION_GET_TOKEN",
24
+ "CONNECTION_DISCONNECT",
25
+ "OAUTH_START",
26
+ "AGENT_GRANT_GET_TOKEN",
27
+ "AGENT_GRANT_CHECK",
28
+ "CONNECTION_OPERATIONS",
29
+ "ConnectionOperationSpec",
30
+ "build_connection_operations",
31
+ "Connection",
32
+ "ConnectionToken",
33
+ "CatalogEntry",
34
+ "ClientApp",
35
+ "AmbiguousConnectionAccount",
36
+ ):
37
+ _EXPORTS[name] = "connection_hub.contract"
38
+ for name in ("ConnectionsClient", "ConnectionsError", "ConnectionsTransport"):
39
+ _EXPORTS[name] = "connection_hub.client"
40
+ for name in (
41
+ "AuthorityProviderSpec",
42
+ "AuthorityRegistry",
43
+ "AuthorityResolution",
44
+ "CredentialEnvelope",
45
+ "authority_provider_spec_from_declaration",
46
+ ):
47
+ _EXPORTS[name] = "connection_hub.authority_registry"
48
+
49
+ __all__ = ["__version__", *_EXPORTS]
50
+
51
+
52
+ def __getattr__(name: str) -> Any:
53
+ module_name = _EXPORTS.get(name)
54
+ if not module_name:
55
+ raise AttributeError(name)
56
+ value = getattr(import_module(module_name), name)
57
+ globals()[name] = value
58
+ return value
@@ -0,0 +1,155 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Elena Viter
3
+
4
+ """Request-scoped per-agent account binding for connected-account resolution.
5
+
6
+ The broker (`delegated_to_kdcube.broker.ensure_claim`) decides which connected
7
+ account satisfies a provider claim. The calling AGENT may be bound, per
8
+ provider, to specific account(s) AND — per account — to specific claims
9
+ (`account_scope: {provider_id: {account_id: [claims]}}` on its grant card). That
10
+ binding must reach the broker, but the shared resolver
11
+ (`integrations.connected_accounts.resolve_connected_account_claim`) runs
12
+ downstream of the door through a generic transport with no HTTP request.
13
+
14
+ Whoever HAS the agent's credential sets the binding into this contextvar at the
15
+ boundary — the door bridge from `request.state.delegated_credential`; a native
16
+ agent gate from the same view — and the resolver reads back the per-account
17
+ claim map for the provider it is resolving.
18
+
19
+ Default-closed for delegated callers: when an agent identity is bound for the
20
+ turn and the provider has NO binding entry, the resolver receives an EMPTY
21
+ mapping — "agent turn, nothing granted on this provider" — and the broker
22
+ denies with the agent-grant reason until the user binds an account. Only
23
+ non-agent turns (no delegated identity — the user's own trusted tools) resolve
24
+ to None, meaning no restriction. An agent never inherits the accounts the user
25
+ connected; the binding is the grant.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import contextvars
31
+ from contextlib import contextmanager
32
+ from typing import Any, Mapping
33
+
34
+ _ACCOUNT_SCOPE: contextvars.ContextVar[dict] = contextvars.ContextVar(
35
+ "kdcube_agent_account_scope", default={}
36
+ )
37
+
38
+ # The calling agent's delegated identity (client_id + delegated-resource id) for
39
+ # the current turn. The connected-account resolver reads it to route a
40
+ # per-account claim miss to THIS agent's grant card (Delegated by KDCube) instead
41
+ # of a connect-a-provider banner. Set alongside the account scope by the gate
42
+ # that holds the agent's credential; unset / non-agent turns leave it empty.
43
+ _AGENT_IDENTITY: contextvars.ContextVar[dict] = contextvars.ContextVar(
44
+ "kdcube_agent_identity", default={}
45
+ )
46
+
47
+
48
+ def normalize_account_scope(
49
+ scope: Mapping[str, Any] | None,
50
+ ) -> dict[str, dict[str, tuple[str, ...]]]:
51
+ """Normalize exact per-provider, per-account claim authority."""
52
+ normalized: dict[str, dict[str, tuple[str, ...]]] = {}
53
+ for provider, entry in dict(scope or {}).items():
54
+ pkey = str(provider or "").strip()
55
+ if not pkey:
56
+ continue
57
+ accounts: dict[str, tuple[str, ...]] = {}
58
+ if isinstance(entry, Mapping):
59
+ for account_id, claims in entry.items():
60
+ akey = str(account_id or "").strip()
61
+ if not akey:
62
+ continue
63
+ cl = tuple(str(c).strip() for c in (claims or ()) if str(c or "").strip())
64
+ accounts[akey] = cl or ("*",)
65
+ else:
66
+ for account_id in (entry or []):
67
+ akey = str(account_id or "").strip()
68
+ if akey:
69
+ accounts[akey] = ("*",)
70
+ if accounts:
71
+ normalized[pkey] = accounts
72
+ return normalized
73
+
74
+
75
+ def set_agent_account_scope(scope: Mapping[str, Any] | None) -> None:
76
+ """Bind the current agent's per-account claim scope
77
+ ({provider_id: {account_id: [claims]}}). Accepts the legacy list form
78
+ ({provider_id: [account_ids]}) and migrates it (account -> any claim)."""
79
+ _ACCOUNT_SCOPE.set(normalize_account_scope(scope))
80
+
81
+
82
+ def clear_agent_account_scope() -> None:
83
+ _ACCOUNT_SCOPE.set({})
84
+ _AGENT_IDENTITY.set({})
85
+
86
+
87
+ def set_agent_identity(*, client_id: str = "", resource: str = "") -> None:
88
+ """Bind the current agent's delegated identity (its
89
+ ``kdcube-agent:<app>:<agent>`` or ``dcr-…`` client id and the
90
+ delegated-resource id its grant is keyed under). The client id alone is
91
+ enough to mark the turn as a delegated (agent) turn — and with it the
92
+ default-closed account binding; the resource additionally lets a claim
93
+ miss deep-link the exact grant card. An empty client id clears the field."""
94
+ cid = str(client_id or "").strip()
95
+ res = str(resource or "").strip()
96
+ _AGENT_IDENTITY.set({"client_id": cid, "resource": res} if cid else {})
97
+
98
+
99
+ @contextmanager
100
+ def bind_agent_account_scope(
101
+ scope: Mapping[str, Any] | None,
102
+ *,
103
+ client_id: str,
104
+ resource: str = "",
105
+ ):
106
+ """Bind one delegated provider invocation and restore prior task state."""
107
+
108
+ cid = str(client_id or "").strip()
109
+ res = str(resource or "").strip()
110
+ scope_token = _ACCOUNT_SCOPE.set(normalize_account_scope(scope))
111
+ identity_token = _AGENT_IDENTITY.set(
112
+ {"client_id": cid, "resource": res} if cid else {}
113
+ )
114
+ try:
115
+ yield
116
+ finally:
117
+ _AGENT_IDENTITY.reset(identity_token)
118
+ _ACCOUNT_SCOPE.reset(scope_token)
119
+
120
+
121
+ def agent_identity() -> dict:
122
+ """The current agent's delegated identity ``{client_id, resource}``, or an
123
+ empty dict on a non-agent turn / when it was not set."""
124
+ return dict(_AGENT_IDENTITY.get() or {})
125
+
126
+
127
+ def account_claim_scope_for(provider_id: str) -> dict[str, tuple[str, ...]] | None:
128
+ """The current agent's per-account claim binding for ``provider_id`` —
129
+ ``{account_id: (claims...)}`` (account "*" = any account, claim "*" = any
130
+ claim).
131
+
132
+ Returns None ONLY on a non-agent turn (no delegated identity bound): the
133
+ user's own trusted tools are unrestricted. On an agent turn with no binding
134
+ entry for this provider it returns an EMPTY mapping — default-closed: the
135
+ agent is bound to no account there, and the broker denies with the
136
+ agent-grant reason until the user grants one."""
137
+ entry = _ACCOUNT_SCOPE.get().get(str(provider_id or "").strip())
138
+ if not entry:
139
+ return {} if _AGENT_IDENTITY.get() else None
140
+ return {
141
+ str(account_id).strip(): tuple(claims)
142
+ for account_id, claims in dict(entry).items()
143
+ if str(account_id or "").strip()
144
+ }
145
+
146
+
147
+ __all__ = [
148
+ "set_agent_account_scope",
149
+ "clear_agent_account_scope",
150
+ "account_claim_scope_for",
151
+ "set_agent_identity",
152
+ "agent_identity",
153
+ "bind_agent_account_scope",
154
+ "normalize_account_scope",
155
+ ]
@@ -0,0 +1,34 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Elena Viter
3
+
4
+ """Host-neutral request-authenticator contracts."""
5
+
6
+ from connection_hub.authenticators.authority import (
7
+ AuthRequestHints,
8
+ AuthorityIdentity,
9
+ SurfaceGuardRequirement,
10
+ select_authenticator_candidates,
11
+ )
12
+ from connection_hub.authenticators.models import (
13
+ AuthenticatedRequest,
14
+ AuthenticatorRegistration,
15
+ RequestEnvelope,
16
+ )
17
+ from connection_hub.authenticators.client import (
18
+ DEFAULT_CONNECTION_HUB_BUNDLE_ID,
19
+ REQUEST_AUTHENTICATE_OPERATION,
20
+ ConnectionHubAuthenticatorsClient,
21
+ )
22
+
23
+ __all__ = [
24
+ "AuthRequestHints",
25
+ "AuthenticatedRequest",
26
+ "AuthenticatorRegistration",
27
+ "AuthorityIdentity",
28
+ "ConnectionHubAuthenticatorsClient",
29
+ "DEFAULT_CONNECTION_HUB_BUNDLE_ID",
30
+ "REQUEST_AUTHENTICATE_OPERATION",
31
+ "RequestEnvelope",
32
+ "SurfaceGuardRequirement",
33
+ "select_authenticator_candidates",
34
+ ]