mrok 0.5.0__py3-none-any.whl → 0.7.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 (47) hide show
  1. mrok/agent/devtools/inspector/__main__.py +2 -24
  2. mrok/agent/devtools/inspector/app.py +408 -113
  3. mrok/agent/devtools/inspector/utils.py +149 -0
  4. mrok/agent/sidecar/app.py +9 -9
  5. mrok/agent/sidecar/main.py +31 -5
  6. mrok/agent/ziticorn.py +8 -2
  7. mrok/cli/commands/admin/bootstrap.py +3 -2
  8. mrok/cli/commands/admin/utils.py +2 -2
  9. mrok/cli/commands/agent/run/sidecar.py +59 -1
  10. mrok/cli/commands/frontend/run.py +43 -1
  11. mrok/cli/main.py +17 -1
  12. mrok/constants.py +21 -0
  13. mrok/controller/schemas.py +2 -2
  14. mrok/frontend/app.py +8 -8
  15. mrok/frontend/main.py +9 -1
  16. mrok/logging.py +0 -22
  17. mrok/proxy/app.py +10 -9
  18. mrok/proxy/asgi.py +96 -0
  19. mrok/proxy/backend.py +5 -3
  20. mrok/proxy/event_publisher.py +66 -0
  21. mrok/proxy/master.py +18 -60
  22. mrok/proxy/metrics.py +2 -2
  23. mrok/proxy/{middlewares.py → middleware.py} +11 -42
  24. mrok/proxy/{datastructures.py → models.py} +43 -17
  25. mrok/proxy/{streams.py → stream.py} +24 -1
  26. mrok/proxy/worker.py +64 -0
  27. mrok/proxy/ziticorn.py +76 -0
  28. mrok/types/__init__.py +0 -0
  29. mrok/{proxy/types.py → types/proxy.py} +7 -2
  30. mrok/types/ziti.py +1 -0
  31. mrok/ziti/api.py +16 -19
  32. mrok/ziti/bootstrap.py +3 -7
  33. mrok/ziti/identities.py +15 -13
  34. mrok/ziti/services.py +3 -2
  35. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/METADATA +8 -2
  36. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/RECORD +39 -40
  37. mrok/agent/devtools/__main__.py +0 -34
  38. mrok/cli/commands/agent/utils.py +0 -5
  39. mrok/proxy/config.py +0 -62
  40. mrok/proxy/constants.py +0 -22
  41. mrok/proxy/lifespan.py +0 -10
  42. mrok/proxy/protocol.py +0 -11
  43. mrok/proxy/server.py +0 -14
  44. mrok/proxy/utils.py +0 -90
  45. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/WHEEL +0 -0
  46. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/entry_points.txt +0 -0
  47. {mrok-0.5.0.dist-info → mrok-0.7.0.dist-info}/licenses/LICENSE.txt +0 -0
mrok/proxy/ziticorn.py ADDED
@@ -0,0 +1,76 @@
1
+ import logging
2
+ import socket
3
+ from collections.abc import Callable
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ import openziti
8
+ from uvicorn import config, server
9
+ from uvicorn.lifespan.on import LifespanOn
10
+ from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol as UvHttpToolsProtocol
11
+
12
+ from mrok.proxy.models import Identity
13
+ from mrok.types.proxy import ASGIApp
14
+
15
+ logger = logging.getLogger("mrok.proxy")
16
+
17
+ config.LIFESPAN["auto"] = "mrok.proxy.ziticorn:Lifespan"
18
+
19
+
20
+ class Lifespan(LifespanOn):
21
+ def __init__(self, lf_config: config.Config) -> None:
22
+ super().__init__(lf_config)
23
+ self.logger = logging.getLogger("mrok.proxy")
24
+
25
+
26
+ class HttpToolsProtocol(UvHttpToolsProtocol):
27
+ def __init__(self, *args, **kwargs):
28
+ super().__init__(*args, **kwargs)
29
+ self.logger = logging.getLogger("mrok.proxy")
30
+ self.access_logger = logging.getLogger("mrok.access")
31
+ self.access_log = self.access_logger.hasHandlers()
32
+
33
+
34
+ class Server(server.Server):
35
+ async def serve(self, sockets: list[socket.socket] | None = None) -> None:
36
+ if not sockets:
37
+ sockets = [self.config.bind_socket()]
38
+ with self.capture_signals():
39
+ await self._serve(sockets)
40
+
41
+
42
+ class BackendConfig(config.Config):
43
+ def __init__(
44
+ self,
45
+ app: ASGIApp | Callable[..., Any] | str,
46
+ identity_file: str | Path,
47
+ ziti_load_timeout_ms: int = 5000,
48
+ backlog: int = 2048,
49
+ ):
50
+ self.identity_file = identity_file
51
+ self.identity = Identity.load_from_file(self.identity_file)
52
+ self.ziti_load_timeout_ms = ziti_load_timeout_ms
53
+ super().__init__(
54
+ app,
55
+ loop="asyncio",
56
+ http=HttpToolsProtocol,
57
+ backlog=backlog,
58
+ )
59
+
60
+ def bind_socket(self) -> socket.socket:
61
+ logger.info(
62
+ "Connect to Ziti service "
63
+ f"'{self.identity.mrok.extension} ({self.identity.mrok.instance})'"
64
+ )
65
+
66
+ ctx, err = openziti.load(str(self.identity_file), timeout=self.ziti_load_timeout_ms)
67
+ if err != 0:
68
+ raise RuntimeError(f"Failed to load Ziti identity from {self.identity_file}: {err}")
69
+
70
+ sock = ctx.bind(self.identity.mrok.extension)
71
+ sock.listen(self.backlog)
72
+ logger.info(f"listening on ziti service {self.identity.mrok.extension} for connections")
73
+ return sock
74
+
75
+ def configure_logging(self) -> None:
76
+ return
mrok/types/__init__.py ADDED
File without changes
@@ -1,9 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Awaitable, Callable, Coroutine, MutableMapping
3
+ from collections.abc import Awaitable, Callable, Coroutine, Mapping, MutableMapping
4
+ from contextlib import AbstractAsyncContextManager
4
5
  from typing import Any, Never
5
6
 
6
- from mrok.proxy.datastructures import HTTPResponse
7
+ from mrok.proxy.models import HTTPResponse
7
8
 
8
9
  Scope = MutableMapping[str, Any]
9
10
  Message = MutableMapping[str, Any]
@@ -11,5 +12,9 @@ Message = MutableMapping[str, Any]
11
12
  ASGIReceive = Callable[[], Awaitable[Message]]
12
13
  ASGISend = Callable[[Message], Awaitable[None]]
13
14
  ASGIApp = Callable[[Scope, ASGIReceive, ASGISend], Awaitable[None]]
15
+ StatelessLifespan = Callable[[ASGIApp], AbstractAsyncContextManager[None]]
16
+ StatefulLifespan = Callable[[ASGIApp], AbstractAsyncContextManager[Mapping[str, Any]]]
17
+ Lifespan = StatelessLifespan | StatefulLifespan
18
+
14
19
  LifespanCallback = Callable[[], Awaitable[None]]
15
20
  ResponseCompleteCallback = Callable[[HTTPResponse], Coroutine[Any, Any, Never]]
mrok/types/ziti.py ADDED
@@ -0,0 +1 @@
1
+ Tags = dict[str, str | bool | None]
mrok/ziti/api.py CHANGED
@@ -11,12 +11,11 @@ from typing import Any, Literal
11
11
  import httpx
12
12
 
13
13
  from mrok.conf import Settings
14
+ from mrok.types.ziti import Tags
14
15
  from mrok.ziti.constants import MROK_VERSION_TAG, MROK_VERSION_TAG_NAME
15
16
 
16
17
  logger = logging.getLogger(__name__)
17
18
 
18
- TagsType = dict[str, str | bool | None]
19
-
20
19
 
21
20
  class ZitiAPIError(Exception):
22
21
  pass
@@ -63,14 +62,14 @@ class BaseZitiAPI(ABC):
63
62
  auth=self.auth,
64
63
  verify=self.settings.ziti.ssl_verify,
65
64
  timeout=httpx.Timeout(
66
- connect=0.25,
65
+ connect=self.settings.ziti.connect_timeout,
67
66
  read=self.settings.ziti.read_timeout,
68
67
  write=2.0,
69
68
  pool=5.0,
70
69
  ),
71
70
  )
72
71
 
73
- async def create(self, endpoint: str, payload: dict[str, Any], tags: TagsType | None) -> str:
72
+ async def create(self, endpoint: str, payload: dict[str, Any], tags: Tags | None) -> str:
74
73
  payload["tags"] = self._merge_tags(tags)
75
74
  response: httpx.Response = await self.httpx_client.post(
76
75
  endpoint,
@@ -156,8 +155,8 @@ class BaseZitiAPI(ABC):
156
155
  ) -> None:
157
156
  return await self.httpx_client.__aexit__(exc_type, exc_val, exc_tb)
158
157
 
159
- def _merge_tags(self, tags: TagsType | None) -> TagsType:
160
- prepared_tags: TagsType = tags or {}
158
+ def _merge_tags(self, tags: Tags | None) -> Tags:
159
+ prepared_tags: Tags = tags or {}
161
160
  prepared_tags.update(MROK_VERSION_TAG)
162
161
  return prepared_tags
163
162
 
@@ -281,9 +280,7 @@ class ZitiManagementAPI(BaseZitiAPI):
281
280
  async def search_config(self, id_or_name) -> dict[str, Any] | None:
282
281
  return await self.search_by_id_or_name("/configs", id_or_name)
283
282
 
284
- async def create_config(
285
- self, name: str, config_type_id: str, tags: TagsType | None = None
286
- ) -> str:
283
+ async def create_config(self, name: str, config_type_id: str, tags: Tags | None = None) -> str:
287
284
  return await self.create(
288
285
  "/configs",
289
286
  {
@@ -302,7 +299,7 @@ class ZitiManagementAPI(BaseZitiAPI):
302
299
  async def delete_config(self, config_id: str) -> None:
303
300
  return await self.delete("/configs", config_id)
304
301
 
305
- async def create_config_type(self, name: str, tags: TagsType | None = None) -> str:
302
+ async def create_config_type(self, name: str, tags: Tags | None = None) -> str:
306
303
  return await self.create(
307
304
  "/config-types",
308
305
  {
@@ -316,7 +313,7 @@ class ZitiManagementAPI(BaseZitiAPI):
316
313
  self,
317
314
  name: str,
318
315
  config_id: str,
319
- tags: TagsType | None = None,
316
+ tags: Tags | None = None,
320
317
  ) -> str:
321
318
  return await self.create(
322
319
  "/services",
@@ -332,7 +329,7 @@ class ZitiManagementAPI(BaseZitiAPI):
332
329
  self,
333
330
  name: str,
334
331
  service_id: str,
335
- tags: TagsType | None = None,
332
+ tags: Tags | None = None,
336
333
  ) -> str:
337
334
  return await self.create(
338
335
  "/service-edge-router-policies",
@@ -351,7 +348,7 @@ class ZitiManagementAPI(BaseZitiAPI):
351
348
  self,
352
349
  name: str,
353
350
  identity_id: str,
354
- tags: TagsType | None = None,
351
+ tags: Tags | None = None,
355
352
  ) -> str:
356
353
  return await self.create(
357
354
  "/edge-router-policies",
@@ -385,10 +382,10 @@ class ZitiManagementAPI(BaseZitiAPI):
385
382
  async def delete_service(self, service_id: str) -> None:
386
383
  return await self.delete("/services", service_id)
387
384
 
388
- async def create_user_identity(self, name: str, tags: TagsType | None = None) -> str:
385
+ async def create_user_identity(self, name: str, tags: Tags | None = None) -> str:
389
386
  return await self._create_identity(name, "User", tags=tags)
390
387
 
391
- async def create_device_identity(self, name: str, tags: TagsType | None = None) -> str:
388
+ async def create_device_identity(self, name: str, tags: Tags | None = None) -> str:
392
389
  return await self._create_identity(name, "Device", tags=tags)
393
390
 
394
391
  async def search_identity(self, id_or_name: str) -> dict[str, Any] | None:
@@ -412,12 +409,12 @@ class ZitiManagementAPI(BaseZitiAPI):
412
409
  return response.text
413
410
 
414
411
  async def create_dial_service_policy(
415
- self, name: str, service_id: str, identity_id: str, tags: TagsType | None = None
412
+ self, name: str, service_id: str, identity_id: str, tags: Tags | None = None
416
413
  ) -> str:
417
414
  return await self._create_service_policy("Dial", name, service_id, identity_id, tags)
418
415
 
419
416
  async def create_bind_service_policy(
420
- self, name: str, service_id: str, identity_id: str, tags: TagsType | None = None
417
+ self, name: str, service_id: str, identity_id: str, tags: Tags | None = None
421
418
  ) -> str:
422
419
  return await self._create_service_policy("Bind", name, service_id, identity_id, tags)
423
420
 
@@ -433,7 +430,7 @@ class ZitiManagementAPI(BaseZitiAPI):
433
430
  name: str,
434
431
  service_id: str,
435
432
  identity_id: str,
436
- tags: TagsType | None = None,
433
+ tags: Tags | None = None,
437
434
  ) -> str:
438
435
  return await self.create(
439
436
  "/service-policies",
@@ -451,7 +448,7 @@ class ZitiManagementAPI(BaseZitiAPI):
451
448
  self,
452
449
  name: str,
453
450
  type: Literal["User", "Device", "Default"],
454
- tags: TagsType | None = None,
451
+ tags: Tags | None = None,
455
452
  ) -> str:
456
453
  return await self.create(
457
454
  "/identities",
mrok/ziti/bootstrap.py CHANGED
@@ -1,7 +1,8 @@
1
1
  import logging
2
2
  from typing import Any
3
3
 
4
- from mrok.ziti.api import TagsType, ZitiClientAPI, ZitiManagementAPI
4
+ from mrok.types.ziti import Tags
5
+ from mrok.ziti.api import ZitiClientAPI, ZitiManagementAPI
5
6
  from mrok.ziti.identities import enroll_proxy_identity
6
7
 
7
8
  logger = logging.getLogger(__name__)
@@ -13,7 +14,7 @@ async def bootstrap_identity(
13
14
  identity_name: str,
14
15
  mode: str,
15
16
  forced: bool,
16
- tags: TagsType | None,
17
+ tags: Tags | None,
17
18
  ) -> tuple[str, dict[str, Any] | None]:
18
19
  logger.info(f"Bootstrapping '{identity_name}' identity...")
19
20
 
@@ -35,11 +36,6 @@ async def bootstrap_identity(
35
36
  logger.info("Deleted existing identity")
36
37
  existing_identity = None
37
38
 
38
- if forced and config_type:
39
- await mgmt_api.delete_config_type(config_type["id"])
40
- logger.info(f"Deleted existing config type '{config_type_name}' ({config_type['id']})")
41
- config_type = None
42
-
43
39
  if existing_identity:
44
40
  frontend_id = existing_identity["id"]
45
41
  logger.info(f"Identity '{identity_name}' ({frontend_id}) is already enrolled")
mrok/ziti/identities.py CHANGED
@@ -5,8 +5,9 @@ from typing import Any
5
5
  import jwt
6
6
 
7
7
  from mrok.conf import Settings
8
+ from mrok.types.ziti import Tags
8
9
  from mrok.ziti import pki
9
- from mrok.ziti.api import TagsType, ZitiClientAPI, ZitiManagementAPI
10
+ from mrok.ziti.api import ZitiClientAPI, ZitiManagementAPI
10
11
  from mrok.ziti.constants import (
11
12
  MROK_IDENTITY_TYPE_TAG_NAME,
12
13
  MROK_IDENTITY_TYPE_TAG_VALUE_INSTANCE,
@@ -29,7 +30,7 @@ async def register_identity(
29
30
  client_api: ZitiClientAPI,
30
31
  service_external_id: str,
31
32
  identity_external_id: str,
32
- tags: TagsType | None = None,
33
+ tags: Tags | None = None,
33
34
  ):
34
35
  service_name = service_external_id.lower()
35
36
  identity_tags = copy.copy(tags or {})
@@ -39,8 +40,9 @@ async def register_identity(
39
40
  if not service:
40
41
  raise ServiceNotFoundError(f"A service with name `{service_external_id}` does not exists.")
41
42
 
42
- identity_name = f"{identity_external_id.lower()}.{service_name}"
43
- service_policy_name = f"{identity_name}:bind"
43
+ identity_name = identity_external_id.lower()
44
+ router_policy_name = f"{identity_external_id.lower()}.{service_name}"
45
+ service_policy_name = f"{identity_external_id.lower()}.{service_name}:bind"
44
46
  self_service_policy_name = f"self.{service_policy_name}"
45
47
 
46
48
  identity = await mgmt_api.search_identity(identity_name)
@@ -51,7 +53,7 @@ async def register_identity(
51
53
  service_policy = await mgmt_api.search_service_policy(self_service_policy_name)
52
54
  if service_policy:
53
55
  await mgmt_api.delete_service_policy(service_policy["id"])
54
- router_policy = await mgmt_api.search_router_policy(identity_name)
56
+ router_policy = await mgmt_api.search_router_policy(router_policy_name)
55
57
  if router_policy:
56
58
  await mgmt_api.delete_router_policy(router_policy["id"])
57
59
  await mgmt_api.delete_identity(identity["id"])
@@ -65,9 +67,8 @@ async def register_identity(
65
67
  identity_id,
66
68
  identity,
67
69
  mrok={
68
- "identity": identity_name,
69
- "extension": service_external_id,
70
- "instance": identity_external_id,
70
+ "extension": service_name,
71
+ "instance": identity_name,
71
72
  "domain": settings.proxy.domain,
72
73
  "tags": identity_tags,
73
74
  },
@@ -83,7 +84,7 @@ async def register_identity(
83
84
  self_service["id"],
84
85
  identity_id,
85
86
  )
86
- await mgmt_api.create_router_policy(identity_name, identity_id)
87
+ await mgmt_api.create_router_policy(router_policy_name, identity_id)
87
88
 
88
89
  return identity, identity_json
89
90
 
@@ -99,8 +100,9 @@ async def unregister_identity(
99
100
  if not service:
100
101
  raise ServiceNotFoundError(f"A service with name `{service_external_id}` does not exists.")
101
102
 
102
- identity_name = f"{identity_external_id.lower()}.{service_name}"
103
- service_policy_name = f"{identity_name}:bind"
103
+ identity_name = identity_external_id.lower()
104
+ router_policy_name = f"{identity_external_id.lower()}.{service_name}"
105
+ service_policy_name = f"{identity_external_id.lower()}.{service_name}:bind"
104
106
 
105
107
  identity = await mgmt_api.search_identity(identity_name)
106
108
  if not identity:
@@ -119,7 +121,7 @@ async def unregister_identity(
119
121
  service_policy = await mgmt_api.search_service_policy(service_policy_name)
120
122
  if service_policy:
121
123
  await mgmt_api.delete_service_policy(service_policy["id"])
122
- router_policy = await mgmt_api.search_router_policy(identity_name)
124
+ router_policy = await mgmt_api.search_router_policy(router_policy_name)
123
125
  if router_policy:
124
126
  await mgmt_api.delete_router_policy(router_policy["id"])
125
127
  await mgmt_api.delete_identity(identity["id"])
@@ -129,7 +131,7 @@ async def enroll_proxy_identity(
129
131
  mgmt_api: ZitiManagementAPI,
130
132
  client_api: ZitiClientAPI,
131
133
  identity_name: str,
132
- tags: TagsType | None = None,
134
+ tags: Tags | None = None,
133
135
  ):
134
136
  identity = await mgmt_api.search_identity(identity_name)
135
137
  if identity:
mrok/ziti/services.py CHANGED
@@ -2,7 +2,8 @@ import logging
2
2
  from typing import Any
3
3
 
4
4
  from mrok.conf import Settings
5
- from mrok.ziti.api import TagsType, ZitiManagementAPI
5
+ from mrok.types.ziti import Tags
6
+ from mrok.ziti.api import ZitiManagementAPI
6
7
  from mrok.ziti.errors import (
7
8
  ConfigTypeNotFoundError,
8
9
  ProxyIdentityNotFoundError,
@@ -14,7 +15,7 @@ logger = logging.getLogger(__name__)
14
15
 
15
16
 
16
17
  async def register_service(
17
- settings: Settings, mgmt_api: ZitiManagementAPI, external_id: str, tags: TagsType | None
18
+ settings: Settings, mgmt_api: ZitiManagementAPI, external_id: str, tags: Tags | None
18
19
  ) -> dict[str, Any]:
19
20
  service_name = external_id.lower()
20
21
  registered = False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mrok
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: MPT Extensions OpenZiti Orchestrator
5
5
  Author: SoftwareOne AG
6
6
  License: Apache License
@@ -214,6 +214,7 @@ Requires-Dist: fastapi[standard]<0.120.0,>=0.119.0
214
214
  Requires-Dist: gunicorn<24.0.0,>=23.0.0
215
215
  Requires-Dist: hdrhistogram<0.11.0,>=0.10.3
216
216
  Requires-Dist: httpcore<2.0.0,>=1.0.9
217
+ Requires-Dist: multipart<2.0.0,>=1.3.0
217
218
  Requires-Dist: openziti<2.0.0,>=1.3.1
218
219
  Requires-Dist: psutil<8.0.0,>=7.1.3
219
220
  Requires-Dist: pydantic<3.0.0,>=2.11.7
@@ -223,7 +224,7 @@ Requires-Dist: pyyaml<7.0.0,>=6.0.2
223
224
  Requires-Dist: pyzmq<28.0.0,>=27.1.0
224
225
  Requires-Dist: rich<15.0.0,>=14.1.0
225
226
  Requires-Dist: textual-serve<2.0.0,>=1.1.3
226
- Requires-Dist: textual<7.0.0,>=6.5.0
227
+ Requires-Dist: textual[syntax]<8.0.0,>=7.2.0
227
228
  Requires-Dist: typer<0.20.0,>=0.19.2
228
229
  Requires-Dist: uvicorn-worker<0.5.0,>=0.4.0
229
230
  Description-Content-Type: text/markdown
@@ -240,6 +241,7 @@ It uses the [OpenZiti](https://openziti.io) zero-trust network overlay to create
240
241
  - **Agent** – Runs alongside an extension in two modes:
241
242
  - *Sidecar mode*: proxies traffic between the Ziti network and a local TCP or Unix socket.
242
243
  - *Embeddable mode*: integrates with ASGI servers (e.g. Uvicorn) to serve a Python application directly.
244
+ - **Frontend** - Proxies internet request to a specific extension through the OpenZiti network.
243
245
  - **CLI** – A command-line tool for administrative tasks and for running the agent in either mode.
244
246
 
245
247
  ## Key Features
@@ -247,5 +249,9 @@ It uses the [OpenZiti](https://openziti.io) zero-trust network overlay to create
247
249
  - Zero-trust networking with automatic balancing across Extension instances.
248
250
  - Simple API and CLI for managing services and identities.
249
251
 
252
+ ## Development
253
+ The included docker compose starts a local Ziti Network (controller + router) and mrok (controller and frontend).
254
+
255
+
250
256
  ## License
251
257
  [Apache 2.0](LICENSE)
@@ -1,27 +1,27 @@
1
1
  mrok/__init__.py,sha256=D1PUs3KtMCqG4bFLceVNG62L3RN53NS95uSCNXpgvzs,181
2
2
  mrok/conf.py,sha256=_5Z-A5LyojQeY8J7W8C0QidsmrPl99r9qKYEoMf4kcI,840
3
- mrok/constants.py,sha256=UTGYqs3DgEd_SN-k0JK10ekmHVWQaaARtdh1Y-0JG_s,122
3
+ mrok/constants.py,sha256=QXaMw4LuHijj_TUTCsM5uUjpgT04HBvd0wRbjvn1z9A,449
4
4
  mrok/errors.py,sha256=ruNMDFr2_0ezCGXuCG1OswCEv-bHOIzMMd02J_0ABcs,37
5
- mrok/logging.py,sha256=ZMWn0w4fJ-F_g-L37H_GM14BSXAIF2mFF_ougX5S7mg,2856
5
+ mrok/logging.py,sha256=4F5rviPK1-MWWMZuHfzNNQmGxg-emAPRdKz0PsWDSww,2261
6
6
  mrok/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- mrok/agent/ziticorn.py,sha256=iENhronSKhPIhXhTMj7pElaLZgeEsgEVTKp_1yMa3Dk,907
7
+ mrok/agent/ziticorn.py,sha256=eHUYs9QaSp35rBzYHRV-SrYxF5ySyECaQg7U-XbdINE,1025
8
8
  mrok/agent/devtools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- mrok/agent/devtools/__main__.py,sha256=R8ezbW7hCik5r45U3w2TgiTubg9SlbVsWA-bapILJXU,781
10
9
  mrok/agent/devtools/inspector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- mrok/agent/devtools/inspector/__main__.py,sha256=HeYcRf1bjXPji2LKMPCcTU61afrRH2P1RqnFmHClRTc,524
12
- mrok/agent/devtools/inspector/app.py,sha256=E1WKcc5k7afq6xq_efEpOk9g5CaXmYjU1kNACZrYYyg,16486
10
+ mrok/agent/devtools/inspector/__main__.py,sha256=MyaIi81D-ubdxuvLV1mCpA8cSVwtq07zc5xuArPU2Dw,73
11
+ mrok/agent/devtools/inspector/app.py,sha256=TxBBIy8lXHj6h8KmQHCeLiIM2QqMzMsCpSWFjH8cGu4,25636
13
12
  mrok/agent/devtools/inspector/server.py,sha256=C4uD6_1psSHMjJLUDCMPGvKdQYKaEwYTw27NAbwuuA0,636
13
+ mrok/agent/devtools/inspector/utils.py,sha256=K-_4rTyB54Y0faEIGgutMEHGyP1W7eOhbcuUKxNnsYA,4261
14
14
  mrok/agent/sidecar/__init__.py,sha256=DrjJGhqFyxsVODW06KI20Wpr6HsD2lD6qFCKUXc7GIE,59
15
- mrok/agent/sidecar/app.py,sha256=8gLB9tgxzC4l6CBYB9MW9A6-v2cjJHx-xVNwAnCD7hI,2506
16
- mrok/agent/sidecar/main.py,sha256=m3aKhOHwIEsXDeTMynHmv41JnBIjv-QUgQ4uw1rrsDA,1068
15
+ mrok/agent/sidecar/app.py,sha256=sPQqjnwETRQk0cj8hAxSVUDCkYqsVZCS6ixEqkcGY5A,2534
16
+ mrok/agent/sidecar/main.py,sha256=jeJzrCbltfXOYsKSCjcw8h5lxh4_bGT87kCC5dV4kYU,2190
17
17
  mrok/cli/__init__.py,sha256=mtFEa8IeS1x6Gm4dUYoSnAxyEzNqbUVSmWxtuZUMR84,61
18
- mrok/cli/main.py,sha256=DFcYPwDskXi8SKAgEsuP4GMFzaniIf_6bZaSDWvYKDk,2724
18
+ mrok/cli/main.py,sha256=T029FYxK_jDrwiA14oX-Onoqp_X14XHRAA_4bbaOgV8,3123
19
19
  mrok/cli/rich.py,sha256=P3Dyu8EArUR9_0j7DPK7LRx85TWdYdZ1SaJzD_S1ZCE,511
20
20
  mrok/cli/utils.py,sha256=m_olScdIUGks5IoC6p2F9D6CQIucWZ7LHyrvwm2bkJw,106
21
21
  mrok/cli/commands/__init__.py,sha256=-UOGzh38oWX7fPeI2nc5I9z8LylRdQAt868q4G6rNGk,140
22
22
  mrok/cli/commands/admin/__init__.py,sha256=WU49jpMF9p18UONjYywWEFzjF57zLpLKJ0qAZvrzcR4,414
23
- mrok/cli/commands/admin/bootstrap.py,sha256=iOnHctYajgcHrG_Idjn5Y7VVSaWYRIhdgqKSw9TWq9I,1680
24
- mrok/cli/commands/admin/utils.py,sha256=wQ-qQJGFyhikMJY_CWT-G6sTEIZb-LUdj1AUZisLPBw,1363
23
+ mrok/cli/commands/admin/bootstrap.py,sha256=9ADSeiVbFAZXh6GxHEf9h2g_XHGOIlMmg1rgsxMfdow,1699
24
+ mrok/cli/commands/admin/utils.py,sha256=Z7YTAFZKOi6nkw2oX4rJoGoUD41RYL3AOqEDhlV3jR0,1357
25
25
  mrok/cli/commands/admin/list/__init__.py,sha256=kjCMcpn1gopcrQaaHxfFh8Kyngldepnle8R2br5dJ_0,195
26
26
  mrok/cli/commands/admin/list/extensions.py,sha256=16fhDB5ucL8su2WQnSaQ1E6MhgC4vkP9-nuHAcPpzyE,4405
27
27
  mrok/cli/commands/admin/list/instances.py,sha256=kaqeyidwUxgYqfaHXqp2m76rm5h2ErBsYyZcNeaBRwY,5912
@@ -32,23 +32,22 @@ mrok/cli/commands/admin/unregister/__init__.py,sha256=-GjjCPX1pISbWmJK6GpKO3ijGs
32
32
  mrok/cli/commands/admin/unregister/extensions.py,sha256=GR3Iwzeksk_R0GkgmCSG7iHRcUrI7ABqDi25Gbes64Y,1016
33
33
  mrok/cli/commands/admin/unregister/instances.py,sha256=-28wL8pTXTWHVHtw93y8-dqi-Dlf0OZOnlBCKOyGo80,1138
34
34
  mrok/cli/commands/agent/__init__.py,sha256=ZAi7eTkKQtfwwV1c1mv3uvEEsyMMrhCQ_-id_0wksAQ,218
35
- mrok/cli/commands/agent/utils.py,sha256=m_olScdIUGks5IoC6p2F9D6CQIucWZ7LHyrvwm2bkJw,106
36
35
  mrok/cli/commands/agent/dev/__init__.py,sha256=ZfreyRuaLqO0AwPS8Ll1DIpsKacsu7_dTmbxV5QecOM,172
37
36
  mrok/cli/commands/agent/dev/console.py,sha256=rrKAGoKXVQQBOC75H0JSuX1sYyvc2QSrV-dfMPK49p4,673
38
37
  mrok/cli/commands/agent/dev/web.py,sha256=O9dYk-o1FV2E_sKLOezdEmLsnexwbJNDdsYL5pATZRQ,1028
39
38
  mrok/cli/commands/agent/run/__init__.py,sha256=E_IJCl3BfMffqFASe8gzJwhhQgt5bQfjhuyekVwdEBA,164
40
39
  mrok/cli/commands/agent/run/asgi.py,sha256=dCgzwJtTLv2eyEIP7v1tDfe_PrFBS02SfN5dSDw1Jzg,2054
41
- mrok/cli/commands/agent/run/sidecar.py,sha256=Tj5inAeSX1E3yCVs2q4P3sP3trvvwk2lYMSUtyFfxo8,2098
40
+ mrok/cli/commands/agent/run/sidecar.py,sha256=UOewegTLFwAZ70VFJb6_9kV0LmsvnXuq-yqgrMlTeZo,4182
42
41
  mrok/cli/commands/controller/__init__.py,sha256=2xw-YVN0akiLiuGUU3XbYyZZ0ugOjQ6XhtTkzEKSmMA,161
43
42
  mrok/cli/commands/controller/openapi.py,sha256=QLjVao9UkB2vBaGkFi_q_jrlg4Np4ldMRwDIJsrJ7A8,1175
44
43
  mrok/cli/commands/controller/run.py,sha256=yl1p7oRHhQINWWjUKlRHtMIWUCV0KsxYdyVyazhX834,2406
45
44
  mrok/cli/commands/frontend/__init__.py,sha256=0kK37yG6qs7yAa8TYlKZUA-nHrWsO4y5CjbVkXafnuk,123
46
- mrok/cli/commands/frontend/run.py,sha256=4w9B662_7ASWuN_skWWWXXQyTcp0G4I-FzvfjL7Yiu0,1305
45
+ mrok/cli/commands/frontend/run.py,sha256=_X1ylMe4-YCTghsu0XY-PB4nk3PL-PQq9YIgbkgJok8,2796
47
46
  mrok/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
47
  mrok/controller/app.py,sha256=XxCIB7N1YE52vSYfvGW2UPgEEOZ9jxDMe2l9D2SfXi8,1866
49
48
  mrok/controller/auth.py,sha256=hYa0OPJ5X0beGxRP6qbxwJOVXj5TmzHjmam2OjTBKn4,2704
50
49
  mrok/controller/pagination.py,sha256=raYpYa34q8Ckl4BXBOEdpWlKkFj6z7e6QLWr2HT7dzI,2187
51
- mrok/controller/schemas.py,sha256=AaF8_bEwZTHM02apVEBAzlUb2t71zoxYaG-VHtPNeMk,1705
50
+ mrok/controller/schemas.py,sha256=PZPEsSJNrGSuplfjCPF_E-VJ721AzgR1Jj8P-Shw1cg,1699
52
51
  mrok/controller/dependencies/__init__.py,sha256=voewk6gjkA0OarL6HFmfT_RLqBns0Fpl-VIqK5xVAEI,202
53
52
  mrok/controller/dependencies/conf.py,sha256=2Pa8fxJHkZ29q6UL-w6hUP_wr7WnNELfw5LlzWg1Tec,162
54
53
  mrok/controller/dependencies/ziti.py,sha256=fYoxeJb4s6p2_3gxbExbFSRabjpvp_gZMBb3ocXZV3Y,702
@@ -59,34 +58,34 @@ mrok/controller/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
59
58
  mrok/controller/routes/extensions.py,sha256=zoY4sNz_BIZcbly6WXM7Rbpn2jmB89njS_0xdJkoKfs,9192
60
59
  mrok/controller/routes/instances.py,sha256=v-fn_F6JHbDZ4YUNCIZzClgHp6aC1Eu5HB7k7qBG5pk,2202
61
60
  mrok/frontend/__init__.py,sha256=SN3LoFwAye18lfJ8OKNNS-7kLc2A9OxPGIEIEYYtAOA,54
62
- mrok/frontend/app.py,sha256=We7z5xrbxvOuLsmWgsqfoECZ8FTWOtlw80a14g_8p9M,2632
63
- mrok/frontend/main.py,sha256=kaje2kfS902TNQwwKn12WEr4N7hKHPg_NwczXAdplwY,1445
61
+ mrok/frontend/app.py,sha256=I2cvEI2ZGhbeazFhF6LavxBYywsv-4QkuNxCDo6-dkA,2627
62
+ mrok/frontend/main.py,sha256=0KtchIGLn70A_Oxekmhr_qSYUg5QqIMfrdYcyFdpj9s,1717
64
63
  mrok/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
- mrok/proxy/app.py,sha256=mqb07evKlGUzgqEy-LMzjyeIg1VjUFu83pZeBA4zVyM,5976
66
- mrok/proxy/backend.py,sha256=T8DDA733CqbFWp5lrf_tKQK_VDgcERKTfesvxofl3AY,1493
67
- mrok/proxy/config.py,sha256=aUTx0-dNAT7U0UEp5bX7-IO7p3HS082QUocAVq2NUWk,2053
68
- mrok/proxy/constants.py,sha256=ao5gI2HFBWmrdd2Yc6XFK_RGaHk-omxI4AqvfIiGes8,409
69
- mrok/proxy/datastructures.py,sha256=SDwhWpJTJrwK9hamHb_Og5PxKXG6VGOwVeoPxtaQLnU,5173
64
+ mrok/proxy/app.py,sha256=flnVPoUO3pSF3b0nYFBhKjZ9jp5ljijo2a-5e37gACs,6016
65
+ mrok/proxy/asgi.py,sha256=2uw5bLquyUsiYlNwq8RhJd8OqVvSJDvYjzOVGLLB3Cs,3528
66
+ mrok/proxy/backend.py,sha256=dRmIUJin2DM3PUxrVX0j4t1oB6DOX7N9JV2lIcopE38,1649
67
+ mrok/proxy/event_publisher.py,sha256=TAuwEqIhRYxgazJFgC3DekwUAXlJ2UFjbdx_A9vwA1g,2511
70
68
  mrok/proxy/exceptions.py,sha256=61OhdihQNdnBUqAI9mbBkXD1yWg-6Eftk7EhWCU1VF0,642
71
- mrok/proxy/lifespan.py,sha256=9qevhD_5Y0f8fGTh2axdfWx7v1K4vnWtiUNyJLesOHE,262
72
- mrok/proxy/master.py,sha256=Houudf2eYZkP5Ri8JtmFeIlWtMuTvybpPaMeIPNyLRg,8484
73
- mrok/proxy/metrics.py,sha256=NPhEbHoRdZ7YLKJPxmLc-sCFmos_L0iZwO0ufUs4SNg,3654
74
- mrok/proxy/middlewares.py,sha256=XHOSQPCXAqUWU2lg1iNkIfTWcfCOJrhEJ_bhVpX-ToQ,5504
75
- mrok/proxy/protocol.py,sha256=ap8jbLUvgbAH81ZJZCBkQiYR7mkV_eL3rpfwEkoE8sU,392
76
- mrok/proxy/server.py,sha256=Mj7C85fc-DXp-WTBWaOd7ag808oliLmFBH5bf-G2FHg,370
77
- mrok/proxy/streams.py,sha256=KxiEFiyAWlFQ7t-t8PZHfDveysBk4Wjo2La-aL7XghQ,1371
78
- mrok/proxy/types.py,sha256=oET5CXqcBvk4kf_giNojZ9kfF5wygy3Z-MvcDd38LMU,555
79
- mrok/proxy/utils.py,sha256=OxX6pJv_Wh_KgWx95YeJ3YeuSgwm2tsd00897P3fxys,2126
69
+ mrok/proxy/master.py,sha256=HB2q_nPLim23z0mGDGKs_RshhGVAO8VgOYP4hA__zC4,6891
70
+ mrok/proxy/metrics.py,sha256=Sg2aIiaj9fzkyu190YCsJvNn5P-XLun3BcvuVBsdWbA,3640
71
+ mrok/proxy/middleware.py,sha256=So024RvtNgMliClKz4pzau2Wb6tlfZGspmHBzzEeF4U,4208
72
+ mrok/proxy/models.py,sha256=VDou3LGDi9zCpzpOwihP4Og1oRvXl7gb2mgczf6_Z14,6029
73
+ mrok/proxy/stream.py,sha256=7V-bSAF9uNV1yVHKaEhHo95WxafSGWkyHPVABZX0djY,2134
74
+ mrok/proxy/worker.py,sha256=uEUC2Hbx0YQiDMFNZfwkHMDnijN96b6iRoIErfI21Tg,1921
75
+ mrok/proxy/ziticorn.py,sha256=qiHKIB7ZRR9S9f-zXTxkzBWW3qlP9CqPOc0QQr-lgvc,2437
76
+ mrok/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
+ mrok/types/proxy.py,sha256=40Yds4tUykMpzsoQbMtHG85r8xtm5Q3fQZ17bp7cDiM,818
78
+ mrok/types/ziti.py,sha256=EeQnTbDEJ-Y-KMS6zu1Xjxb58Up2VxUwqzUwy3H28JY,36
80
79
  mrok/ziti/__init__.py,sha256=20OWMiexRhOovZOX19zlX87-V78QyWnEnSZfyAftUdE,263
81
- mrok/ziti/api.py,sha256=KvGiT9d4oSgC3JbFWLDQyuHcLX2HuZJoJ8nHmWtCDkY,16154
82
- mrok/ziti/bootstrap.py,sha256=QIDhlkIxPW2QRuumFq2D1WDbD003P5f3z24pAUsyeBI,2696
80
+ mrok/ziti/api.py,sha256=CRblQUyfX_421cppA9D-LRnjh4N9P7aYVK4fG7UzQE4,16102
81
+ mrok/ziti/bootstrap.py,sha256=RSL8nZfI-MZ_z6h0F-rNevQoE6g9oGKLr6HlZF696_c,2499
83
82
  mrok/ziti/constants.py,sha256=Urq1X3bCBQZfw8NbnEa1pqmY4oq1wmzkwPfzam3kbTw,339
84
83
  mrok/ziti/errors.py,sha256=yYCbVDwktnR0AYduqtynIjo73K3HOhIrwA_vQimvEd4,368
85
- mrok/ziti/identities.py,sha256=1BcwfqAJHMBhc3vRaf0aLaIkoHskj5Xe2Lsq2lO9Vs8,6735
84
+ mrok/ziti/identities.py,sha256=5-7Iof5a8SfkAYsy-SPirDEJKE68ZSn1Kw1wXYQbK9Q,6880
86
85
  mrok/ziti/pki.py,sha256=o2tySqHC8-7bvFuI2Tqxg9vX6H6ZSxWxfP_9x29e19M,1954
87
- mrok/ziti/services.py,sha256=zR1PEBYwXVou20iJK4euh0ZZFAo9UB8PZk8f6SDmiUE,3194
88
- mrok-0.5.0.dist-info/METADATA,sha256=-rLLRvaOAveuVDJR_ZLNWohgU9EdIM1jgrnH6LoqgHc,15705
89
- mrok-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
90
- mrok-0.5.0.dist-info/entry_points.txt,sha256=tloXwvU1uJicBJR2h-8HoVclPgwJWDwuREMHN8Zq-nU,38
91
- mrok-0.5.0.dist-info/licenses/LICENSE.txt,sha256=6PaICaoA3yNsZKLv5G6OKqSfLSoX7MakYqTDgJoTCBs,11346
92
- mrok-0.5.0.dist-info/RECORD,,
86
+ mrok/ziti/services.py,sha256=TukG0vAZxgjbS8OLiyg7u1GwuVeGTco-rb9ne6a4PUA,3213
87
+ mrok-0.7.0.dist-info/METADATA,sha256=bswj6K1HG4vnUbkCpqQfuH6BoAgcyrMKY3U6XIotlnI,15979
88
+ mrok-0.7.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
89
+ mrok-0.7.0.dist-info/entry_points.txt,sha256=tloXwvU1uJicBJR2h-8HoVclPgwJWDwuREMHN8Zq-nU,38
90
+ mrok-0.7.0.dist-info/licenses/LICENSE.txt,sha256=6PaICaoA3yNsZKLv5G6OKqSfLSoX7MakYqTDgJoTCBs,11346
91
+ mrok-0.7.0.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env python3
2
- """mrok agent devtools CLI entrypoint.
3
-
4
- Provides a small CLI that accepts an optional subscriber port and
5
- invokes the `run` function with that port.
6
- """
7
-
8
- import argparse
9
- from typing import Any
10
-
11
-
12
- def run(port: int) -> None:
13
- """Run the devtools agent using the given subscriber port.
14
-
15
- This is a stub for the runtime function. Implementation goes here.
16
- """
17
- pass
18
-
19
-
20
- def main(argv: Any = None) -> None:
21
- parser = argparse.ArgumentParser(description="mrok devtools agent")
22
- parser.add_argument(
23
- "-p",
24
- "--subscriber-port",
25
- type=int,
26
- default=50001,
27
- help="Port for subscriber (default: 50001)",
28
- )
29
- args = parser.parse_args(argv)
30
- run(args.subscriber_port)
31
-
32
-
33
- if __name__ == "__main__":
34
- main()
@@ -1,5 +0,0 @@
1
- import multiprocessing
2
-
3
-
4
- def number_of_workers() -> int:
5
- return (multiprocessing.cpu_count() * 2) + 1
mrok/proxy/config.py DELETED
@@ -1,62 +0,0 @@
1
- import json
2
- import logging
3
- import socket
4
- from collections.abc import Callable
5
- from pathlib import Path
6
- from typing import Any
7
-
8
- import openziti
9
- from uvicorn import config
10
-
11
- from mrok.proxy.protocol import MrokHttpToolsProtocol
12
- from mrok.proxy.types import ASGIApp
13
-
14
- logger = logging.getLogger("mrok.proxy")
15
-
16
- config.LIFESPAN["auto"] = "mrok.proxy.lifespan:MrokLifespan"
17
-
18
-
19
- class MrokBackendConfig(config.Config):
20
- def __init__(
21
- self,
22
- app: ASGIApp | Callable[..., Any] | str,
23
- identity_file: str | Path,
24
- ziti_load_timeout_ms: int = 5000,
25
- backlog: int = 2048,
26
- ):
27
- self.identity_file = identity_file
28
- self.ziti_load_timeout_ms = ziti_load_timeout_ms
29
- self.service_name, self.identity_name, self.instance_id = self.get_identity_info(
30
- identity_file
31
- )
32
- super().__init__(
33
- app,
34
- loop="asyncio",
35
- http=MrokHttpToolsProtocol,
36
- backlog=backlog,
37
- )
38
-
39
- def get_identity_info(self, identity_file: str | Path):
40
- with open(identity_file) as f:
41
- identity_data = json.load(f)
42
- try:
43
- identity_name = identity_data["mrok"]["identity"]
44
- instance_id, service_name = identity_name.split(".", 1)
45
- return service_name, identity_name, instance_id
46
- except KeyError:
47
- raise ValueError("Invalid identity file: identity file is not mrok compatible.")
48
-
49
- def bind_socket(self) -> socket.socket:
50
- logger.info(f"Connect to Ziti service '{self.service_name} ({self.instance_id})'")
51
-
52
- ctx, err = openziti.load(str(self.identity_file), timeout=self.ziti_load_timeout_ms)
53
- if err != 0:
54
- raise RuntimeError(f"Failed to load Ziti identity from {self.identity_file}: {err}")
55
-
56
- sock = ctx.bind(self.service_name)
57
- sock.listen(self.backlog)
58
- logger.info(f"listening on ziti service {self.service_name} for connections")
59
- return sock
60
-
61
- def configure_logging(self) -> None:
62
- return