diff --git a/packages/syft/src/syft/client/client.py b/packages/syft/src/syft/client/client.py index e2a95c416cb..7f4accfe75a 100644 --- a/packages/syft/src/syft/client/client.py +++ b/packages/syft/src/syft/client/client.py @@ -440,6 +440,9 @@ def __init__( self.post_init() + def get_env(self) -> str: + return self.api.services.metadata.get_env() + def post_init(self) -> None: if self.metadata is None: self._fetch_node_metadata(self.credentials) diff --git a/packages/syft/src/syft/node/node.py b/packages/syft/src/syft/node/node.py index 81c6095eaea..2241e8f3b69 100644 --- a/packages/syft/src/syft/node/node.py +++ b/packages/syft/src/syft/node/node.py @@ -9,6 +9,7 @@ import hashlib from multiprocessing import current_process import os +import subprocess # nosec import traceback from typing import Any from typing import Callable @@ -52,6 +53,7 @@ from ..service.data_subject.data_subject_service import DataSubjectService from ..service.dataset.dataset_service import DatasetService from ..service.enclave.enclave_service import EnclaveService +from ..service.metadata.metadata_service import MetadataService from ..service.metadata.node_metadata import NodeMetadata from ..service.network.network_service import NetworkService from ..service.notification.notification_service import NotificationService @@ -147,6 +149,13 @@ def get_dev_mode() -> bool: return str_to_bool(get_env("DEV_MODE", "False")) +def get_venv_packages() -> str: + res = subprocess.getoutput( + "pip list --format=freeze", + ) + return res + + dev_mode = get_dev_mode() signing_key_env = get_private_key_env() @@ -160,6 +169,7 @@ def get_dev_mode() -> bool: class Node(AbstractNode): signing_key: Optional[SyftSigningKey] required_signed_calls: bool = True + packages: str def __init__( self, @@ -187,6 +197,7 @@ def __init__( if id is None: id = UID() self.id = id + self.packages = get_venv_packages() self.signing_key = None if signing_key_env is not None: @@ -217,6 +228,7 @@ def __init__( DataSubjectMemberService, ProjectService, EnclaveService, + MetadataService, ] if services is None else services @@ -253,7 +265,7 @@ def __init__( self.node_type = node_type self.post_init() - self.create_initial_settings() + self.create_initial_settings(admin_email=root_email) if not (self.is_subprocess or self.processes == 0): self.init_queue_manager(queue_config=queue_config) @@ -462,6 +474,7 @@ def _construct_services(self): DataSubjectMemberService, ProjectService, EnclaveService, + MetadataService, ] if OBLV: @@ -508,6 +521,7 @@ def metadata(self) -> NodeMetadata: on_board = False description = "" signup_enabled = False + admin_email = "" settings_stash = SettingsStash(store=self.document_store) settings = settings_stash.get_all(self.signing_key.verify_key) @@ -519,6 +533,7 @@ def metadata(self) -> NodeMetadata: on_board = settings_data.on_board description = settings_data.description signup_enabled = settings_data.signup_enabled + admin_email = settings_data.admin_email return NodeMetadata( name=name, @@ -533,6 +548,7 @@ def metadata(self) -> NodeMetadata: on_board=on_board, node_type=self.node_type.value, signup_enabled=signup_enabled, + admin_email=admin_email, ) @property @@ -707,7 +723,7 @@ def get_unauthed_context( ) -> NodeServiceContext: return UnauthedServiceContext(node=self, login_credentials=login_credentials) - def create_initial_settings(self) -> Optional[NodeSettings]: + def create_initial_settings(self, admin_email: str) -> Optional[NodeSettings]: if self.name is None: self.name = random_name() try: @@ -725,6 +741,7 @@ def create_initial_settings(self) -> Optional[NodeSettings]: name=self.name, deployed_on=datetime.now().date().strftime("%m/%d/%Y"), signup_enabled=flags.CAN_REGISTER, + admin_email=admin_email, ) result = settings_stash.set( credentials=self.signing_key.verify_key, settings=new_settings diff --git a/packages/syft/src/syft/service/metadata/metadata_service.py b/packages/syft/src/syft/service/metadata/metadata_service.py new file mode 100644 index 00000000000..b053a7d7626 --- /dev/null +++ b/packages/syft/src/syft/service/metadata/metadata_service.py @@ -0,0 +1,33 @@ +# third party + +# relative +from ...serde.serializable import serializable +from ...store.document_store import DocumentStore +from ...util.telemetry import instrument +from ..context import AuthedServiceContext +from ..service import AbstractService +from ..service import service_method +from ..user.user_roles import GUEST_ROLE_LEVEL + + +@instrument +@serializable() +class MetadataService(AbstractService): + def __init__(self, store: DocumentStore) -> None: + self.store = store + + @service_method( + path="metadata.get_metadata", name="get_metadata", roles=GUEST_ROLE_LEVEL + ) + def get_metadata(self, context: AuthedServiceContext): + return context.node.metadata + + # @service_method(path="metadata.get_admin", name="get_admin", roles=GUEST_ROLE_LEVEL) + # def get_admin(self, context: AuthedServiceContext): + # user_service = context.node.get_service("userservice") + # admin_user = user_service.get_all(context=context)[0] + # return admin_user + + @service_method(path="metadata.get_env", name="get_env", roles=GUEST_ROLE_LEVEL) + def get_env(self, context: AuthedServiceContext): + return context.node.packages diff --git a/packages/syft/src/syft/service/metadata/node_metadata.py b/packages/syft/src/syft/service/metadata/node_metadata.py index ea6603f5d14..7f1f4644bb7 100644 --- a/packages/syft/src/syft/service/metadata/node_metadata.py +++ b/packages/syft/src/syft/service/metadata/node_metadata.py @@ -56,6 +56,7 @@ class NodeMetadataUpdate(SyftObject): highest_object_version: Optional[int] lowest_object_version: Optional[int] syft_version: Optional[str] + admin_email: Optional[str] @serializable() @@ -75,6 +76,7 @@ class NodeMetadata(SyftObject): on_board: bool = False description: str = "Text" signup_enabled: bool + admin_email: str def check_version(self, client_version: str) -> bool: return check_version( @@ -99,6 +101,7 @@ class NodeMetadataJSON(BaseModel, StorableObjectType): on_board: bool = False description: str = "My cool domain" signup_enabled: bool + admin_email: str def check_version(self, client_version: str) -> bool: return check_version( diff --git a/packages/syft/src/syft/service/network/network_service.py b/packages/syft/src/syft/service/network/network_service.py index 60341972e2b..123621dd194 100644 --- a/packages/syft/src/syft/service/network/network_service.py +++ b/packages/syft/src/syft/service/network/network_service.py @@ -530,5 +530,5 @@ def node_route_to_http_connection( @transform(NodeMetadata, NodePeer) def metadata_to_peer() -> List[Callable]: return [ - keep(["id", "name", "verify_key", "node_type"]), + keep(["id", "name", "verify_key", "node_type", "admin_email"]), ] diff --git a/packages/syft/src/syft/service/network/node_peer.py b/packages/syft/src/syft/service/network/node_peer.py index 646f1889a76..956f5b50160 100644 --- a/packages/syft/src/syft/service/network/node_peer.py +++ b/packages/syft/src/syft/service/network/node_peer.py @@ -31,7 +31,7 @@ class NodePeer(SyftObject): __attr_searchable__ = ["name", "node_type"] __attr_unique__ = ["verify_key"] - __repr_attrs__ = ["name", "node_type"] + __repr_attrs__ = ["name", "node_type", "admin_email"] id: Optional[UID] name: str @@ -40,6 +40,7 @@ class NodePeer(SyftObject): vpn_auth_key: Optional[str] = None node_routes: List[NodeRouteType] = [] node_type: NodeType + admin_email: str def update_routes(self, new_routes: List[NodeRoute]) -> None: add_routes = [] diff --git a/packages/syft/src/syft/service/request/request.py b/packages/syft/src/syft/service/request/request.py index bf634075647..fe89eac8821 100644 --- a/packages/syft/src/syft/service/request/request.py +++ b/packages/syft/src/syft/service/request/request.py @@ -189,7 +189,9 @@ def _repr_html_(self) -> Any: self.node_uid, self.syft_client_verify_key, ) - + metadata = api.services.metadata.get_metadata() + admin_email = metadata.admin_email + node_name = api.node_name.capitalize() if api.node_name is not None else "" return f"""