From 3a71de50f05851349cdd22fee8057b6c7eef6db1 Mon Sep 17 00:00:00 2001 From: Nivedit Jain Date: Wed, 9 Jul 2025 20:20:39 +0530 Subject: [PATCH 1/9] 24 kubernetes setup (#5) * added dockerfile * added docker-compose file * setting up pipeline to push to ghcr * Adding Auth Module (#18) * token creation init * fixed JSON issues * fixed lint issues * token is generating * added method to get claims * added api-server * Adding project APIs and Auth APIs (#23) * token creation init * fixed JSON issues * fixed lint issues * token is generating * added method to get claims * added api-server * added more apis * fixed authentication * fixing linting issues * added dockerfile * added docker-compose file * setting up pipeline to push to ghcr * cleaned tagging * testing docker file changes * fallback versioning --- .github/workflows/deploy-api-server.yml | 52 +++++++++++++++++++++++++ api-server/.dockerignore | 26 +++++++++++++ api-server/Dockerfile | 14 +++++++ api-server/docker-compose.yml | 12 ++++++ 4 files changed, 104 insertions(+) create mode 100644 .github/workflows/deploy-api-server.yml create mode 100644 api-server/.dockerignore create mode 100644 api-server/Dockerfile create mode 100644 api-server/docker-compose.yml diff --git a/.github/workflows/deploy-api-server.yml b/.github/workflows/deploy-api-server.yml new file mode 100644 index 00000000..67968831 --- /dev/null +++ b/.github/workflows/deploy-api-server.yml @@ -0,0 +1,52 @@ +name: Publish API server image to GHCR and deploys to Kubernetes Cluster + +on: + push: + branches: [main] + paths: + - 'api-server/**' + release: + types: [published] + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository_owner }}/exosphere-api-server + +jobs: + publish-image: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + + - uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate tags & labels + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,format=short + type=ref,event=tag # v1.2.3 → v1.2.3 + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: ./api-server + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/api-server/.dockerignore b/api-server/.dockerignore new file mode 100644 index 00000000..ba4cefd6 --- /dev/null +++ b/api-server/.dockerignore @@ -0,0 +1,26 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*.pyo +*.pyd +*.so + +# C extensions +*.egg +*.egg-info +.eggs + +# Virtual environments +.venv/ + +# Git, CI and editor config +.git/ +.github/ +.vscode/ + +# Logs and temp files +*.log + +# Other +.env +Dockerfile \ No newline at end of file diff --git a/api-server/Dockerfile b/api-server/Dockerfile new file mode 100644 index 00000000..0f9cb814 --- /dev/null +++ b/api-server/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12-slim-bookworm +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /api-server + +COPY pyproject.toml uv.lock ./ + +RUN uv sync --locked + +COPY . . + +EXPOSE 8000 + +CMD ["uv", "run", "run.py", "--mode", "production", "--workers", "4"] \ No newline at end of file diff --git a/api-server/docker-compose.yml b/api-server/docker-compose.yml new file mode 100644 index 00000000..99f7664e --- /dev/null +++ b/api-server/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + api-server: + build: + context: . + dockerfile: Dockerfile + ports: + - "8000:8000" + env_file: + - .env + command: ["uv", "run", "run.py", "--mode", "production", "--workers", "2"] From 48ba4276ef10f29c8bf81095ec80ef1aed8aaae6 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Sun, 13 Jul 2025 17:26:29 +0530 Subject: [PATCH 2/9] added satellite model --- .../app/satellite/models/access_types.py | 5 + .../models/satellite_database_model.py | 47 +++++++ api-server/pyproject.toml | 1 + api-server/uv.lock | 128 ++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 api-server/app/satellite/models/access_types.py create mode 100644 api-server/app/satellite/models/satellite_database_model.py diff --git a/api-server/app/satellite/models/access_types.py b/api-server/app/satellite/models/access_types.py new file mode 100644 index 00000000..93b6aca3 --- /dev/null +++ b/api-server/app/satellite/models/access_types.py @@ -0,0 +1,5 @@ +from enum import Enum + +class AccessTypeEnum(str, Enum): + PUBLIC = "PUBLIC" + PRIVATE = "PRIVATE" diff --git a/api-server/app/satellite/models/satellite_database_model.py b/api-server/app/satellite/models/satellite_database_model.py new file mode 100644 index 00000000..be65f013 --- /dev/null +++ b/api-server/app/satellite/models/satellite_database_model.py @@ -0,0 +1,47 @@ +import jsonschema + +from beanie import Document, Indexed, before_event, Replace, Save, Link +from datetime import datetime +from pydantic import Field, Any, field_validator +from .access_types import AccessTypeEnum + +from app.project.models.project_database_model import Project + + +class Satellite(Document): + + name: Indexed(str, unique=True) = Field(..., description="Name of the satellite") + + friendly_name: str = Field(..., description="Friendly name of the satellite") + + description: str = Field(..., description="Description of the satellite") + + access_type: AccessTypeEnum = Field(..., description="Access type of the satellite") + + configs: dict[str, Any] = Field(..., description="Configurations of the satellite, a valid jsonschema object for the configs") + inputs: dict[str, Any] = Field(..., description="Input data fothe satellite, a valid jsonschema object for the inputs") + metrics: dict[str, Any] = Field(..., description="Metrics of the satellite, a valid jsonschema object for the metrics") + outputs: dict[str, Any] = Field(..., description="Outputs of the satellite, a valid jsonschema object for the outputs") + + project: Link[Project] = Field(..., description="Project of the satellite") + + created_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was created") + + updated_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was last updated") + + + @field_validator("configs", "inputs", "metrics", "outputs") + def validate_jsonschema(cls, v: dict[str, Any]) -> dict[str, Any]: + validator = jsonschema.validators.validator_for(v) + + try: + validator.check_schema(v) + except jsonschema.exceptions.SchemaError as e: + raise ValueError(f"Invalid JSON schema: {e.message}") + + return v + + + @before_event([Save, Replace]) + def update_updated_at(self): + self.updated_at = datetime.now() \ No newline at end of file diff --git a/api-server/pyproject.toml b/api-server/pyproject.toml index 0d0f1e90..3c916c62 100644 --- a/api-server/pyproject.toml +++ b/api-server/pyproject.toml @@ -8,6 +8,7 @@ dependencies = [ "bcrypt>=4.3.0", "beanie>=1.30.0", "fastapi>=0.115.14", + "jsonschema>=4.24.0", "pyjwt>=2.10.1", "python-dotenv>=1.1.1", "structlog>=25.4.0", diff --git a/api-server/uv.lock b/api-server/uv.lock index 600606c5..4572b75e 100644 --- a/api-server/uv.lock +++ b/api-server/uv.lock @@ -33,6 +33,7 @@ dependencies = [ { name = "bcrypt" }, { name = "beanie" }, { name = "fastapi" }, + { name = "jsonschema" }, { name = "pyjwt" }, { name = "python-dotenv" }, { name = "structlog" }, @@ -49,6 +50,7 @@ requires-dist = [ { name = "bcrypt", specifier = ">=4.3.0" }, { name = "beanie", specifier = ">=1.30.0" }, { name = "fastapi", specifier = ">=0.115.14" }, + { name = "jsonschema", specifier = ">=4.24.0" }, { name = "pyjwt", specifier = ">=2.10.1" }, { name = "python-dotenv", specifier = ">=1.1.1" }, { name = "structlog", specifier = ">=25.4.0" }, @@ -58,6 +60,15 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "ruff", specifier = ">=0.12.2" }] +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + [[package]] name = "bcrypt" version = "4.3.0" @@ -186,6 +197,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, ] +[[package]] +name = "jsonschema" +version = "4.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480, upload-time = "2025-05-26T18:48:10.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709, upload-time = "2025-05-26T18:48:08.417Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, +] + [[package]] name = "lazy-model" version = "0.2.0" @@ -323,6 +361,96 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, ] +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/86/90eb87c6f87085868bd077c7a9938006eb1ce19ed4d06944a90d3560fce2/rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d", size = 363933, upload-time = "2025-07-01T15:54:15.734Z" }, + { url = "https://files.pythonhosted.org/packages/63/78/4469f24d34636242c924626082b9586f064ada0b5dbb1e9d096ee7a8e0c6/rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136", size = 350447, upload-time = "2025-07-01T15:54:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/ad/91/c448ed45efdfdade82348d5e7995e15612754826ea640afc20915119734f/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582", size = 384711, upload-time = "2025-07-01T15:54:18.101Z" }, + { url = "https://files.pythonhosted.org/packages/ec/43/e5c86fef4be7f49828bdd4ecc8931f0287b1152c0bb0163049b3218740e7/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e", size = 400865, upload-time = "2025-07-01T15:54:19.295Z" }, + { url = "https://files.pythonhosted.org/packages/55/34/e00f726a4d44f22d5c5fe2e5ddd3ac3d7fd3f74a175607781fbdd06fe375/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15", size = 517763, upload-time = "2025-07-01T15:54:20.858Z" }, + { url = "https://files.pythonhosted.org/packages/52/1c/52dc20c31b147af724b16104500fba13e60123ea0334beba7b40e33354b4/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8", size = 406651, upload-time = "2025-07-01T15:54:22.508Z" }, + { url = "https://files.pythonhosted.org/packages/2e/77/87d7bfabfc4e821caa35481a2ff6ae0b73e6a391bb6b343db2c91c2b9844/rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a", size = 386079, upload-time = "2025-07-01T15:54:23.987Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d4/7f2200c2d3ee145b65b3cddc4310d51f7da6a26634f3ac87125fd789152a/rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323", size = 421379, upload-time = "2025-07-01T15:54:25.073Z" }, + { url = "https://files.pythonhosted.org/packages/ae/13/9fdd428b9c820869924ab62236b8688b122baa22d23efdd1c566938a39ba/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158", size = 562033, upload-time = "2025-07-01T15:54:26.225Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e1/b69686c3bcbe775abac3a4c1c30a164a2076d28df7926041f6c0eb5e8d28/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3", size = 591639, upload-time = "2025-07-01T15:54:27.424Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c9/1e3d8c8863c84a90197ac577bbc3d796a92502124c27092413426f670990/rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2", size = 557105, upload-time = "2025-07-01T15:54:29.93Z" }, + { url = "https://files.pythonhosted.org/packages/9f/c5/90c569649057622959f6dcc40f7b516539608a414dfd54b8d77e3b201ac0/rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44", size = 223272, upload-time = "2025-07-01T15:54:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/16/19f5d9f2a556cfed454eebe4d354c38d51c20f3db69e7b4ce6cff904905d/rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c", size = 234995, upload-time = "2025-07-01T15:54:32.195Z" }, + { url = "https://files.pythonhosted.org/packages/83/f0/7935e40b529c0e752dfaa7880224771b51175fce08b41ab4a92eb2fbdc7f/rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8", size = 223198, upload-time = "2025-07-01T15:54:33.271Z" }, + { url = "https://files.pythonhosted.org/packages/6a/67/bb62d0109493b12b1c6ab00de7a5566aa84c0e44217c2d94bee1bd370da9/rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d", size = 363917, upload-time = "2025-07-01T15:54:34.755Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f3/34e6ae1925a5706c0f002a8d2d7f172373b855768149796af87bd65dcdb9/rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1", size = 350073, upload-time = "2025-07-01T15:54:36.292Z" }, + { url = "https://files.pythonhosted.org/packages/75/83/1953a9d4f4e4de7fd0533733e041c28135f3c21485faaef56a8aadbd96b5/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e", size = 384214, upload-time = "2025-07-01T15:54:37.469Z" }, + { url = "https://files.pythonhosted.org/packages/48/0e/983ed1b792b3322ea1d065e67f4b230f3b96025f5ce3878cc40af09b7533/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1", size = 400113, upload-time = "2025-07-01T15:54:38.954Z" }, + { url = "https://files.pythonhosted.org/packages/69/7f/36c0925fff6f660a80be259c5b4f5e53a16851f946eb080351d057698528/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9", size = 515189, upload-time = "2025-07-01T15:54:40.57Z" }, + { url = "https://files.pythonhosted.org/packages/13/45/cbf07fc03ba7a9b54662c9badb58294ecfb24f828b9732970bd1a431ed5c/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7", size = 406998, upload-time = "2025-07-01T15:54:43.025Z" }, + { url = "https://files.pythonhosted.org/packages/6c/b0/8fa5e36e58657997873fd6a1cf621285ca822ca75b4b3434ead047daa307/rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04", size = 385903, upload-time = "2025-07-01T15:54:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f7/b25437772f9f57d7a9fbd73ed86d0dcd76b4c7c6998348c070d90f23e315/rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1", size = 419785, upload-time = "2025-07-01T15:54:46.043Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6b/63ffa55743dfcb4baf2e9e77a0b11f7f97ed96a54558fcb5717a4b2cd732/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9", size = 561329, upload-time = "2025-07-01T15:54:47.64Z" }, + { url = "https://files.pythonhosted.org/packages/2f/07/1f4f5e2886c480a2346b1e6759c00278b8a69e697ae952d82ae2e6ee5db0/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9", size = 590875, upload-time = "2025-07-01T15:54:48.9Z" }, + { url = "https://files.pythonhosted.org/packages/cc/bc/e6639f1b91c3a55f8c41b47d73e6307051b6e246254a827ede730624c0f8/rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba", size = 556636, upload-time = "2025-07-01T15:54:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/05/4c/b3917c45566f9f9a209d38d9b54a1833f2bb1032a3e04c66f75726f28876/rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b", size = 222663, upload-time = "2025-07-01T15:54:52.023Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0b/0851bdd6025775aaa2365bb8de0697ee2558184c800bfef8d7aef5ccde58/rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5", size = 234428, upload-time = "2025-07-01T15:54:53.692Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e8/a47c64ed53149c75fb581e14a237b7b7cd18217e969c30d474d335105622/rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256", size = 222571, upload-time = "2025-07-01T15:54:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/89/bf/3d970ba2e2bcd17d2912cb42874107390f72873e38e79267224110de5e61/rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618", size = 360475, upload-time = "2025-07-01T15:54:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/82/9f/283e7e2979fc4ec2d8ecee506d5a3675fce5ed9b4b7cb387ea5d37c2f18d/rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35", size = 346692, upload-time = "2025-07-01T15:54:58.561Z" }, + { url = "https://files.pythonhosted.org/packages/e3/03/7e50423c04d78daf391da3cc4330bdb97042fc192a58b186f2d5deb7befd/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f", size = 379415, upload-time = "2025-07-01T15:54:59.751Z" }, + { url = "https://files.pythonhosted.org/packages/57/00/d11ee60d4d3b16808432417951c63df803afb0e0fc672b5e8d07e9edaaae/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83", size = 391783, upload-time = "2025-07-01T15:55:00.898Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/1069c394d9c0d6d23c5b522e1f6546b65793a22950f6e0210adcc6f97c3e/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1", size = 512844, upload-time = "2025-07-01T15:55:02.201Z" }, + { url = "https://files.pythonhosted.org/packages/08/3b/c4fbf0926800ed70b2c245ceca99c49f066456755f5d6eb8863c2c51e6d0/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8", size = 402105, upload-time = "2025-07-01T15:55:03.698Z" }, + { url = "https://files.pythonhosted.org/packages/1c/b0/db69b52ca07413e568dae9dc674627a22297abb144c4d6022c6d78f1e5cc/rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f", size = 383440, upload-time = "2025-07-01T15:55:05.398Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e1/c65255ad5b63903e56b3bb3ff9dcc3f4f5c3badde5d08c741ee03903e951/rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed", size = 412759, upload-time = "2025-07-01T15:55:08.316Z" }, + { url = "https://files.pythonhosted.org/packages/e4/22/bb731077872377a93c6e93b8a9487d0406c70208985831034ccdeed39c8e/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632", size = 556032, upload-time = "2025-07-01T15:55:09.52Z" }, + { url = "https://files.pythonhosted.org/packages/e0/8b/393322ce7bac5c4530fb96fc79cc9ea2f83e968ff5f6e873f905c493e1c4/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c", size = 585416, upload-time = "2025-07-01T15:55:11.216Z" }, + { url = "https://files.pythonhosted.org/packages/49/ae/769dc372211835bf759319a7aae70525c6eb523e3371842c65b7ef41c9c6/rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0", size = 554049, upload-time = "2025-07-01T15:55:13.004Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f9/4c43f9cc203d6ba44ce3146246cdc38619d92c7bd7bad4946a3491bd5b70/rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9", size = 218428, upload-time = "2025-07-01T15:55:14.486Z" }, + { url = "https://files.pythonhosted.org/packages/7e/8b/9286b7e822036a4a977f2f1e851c7345c20528dbd56b687bb67ed68a8ede/rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9", size = 231524, upload-time = "2025-07-01T15:55:15.745Z" }, + { url = "https://files.pythonhosted.org/packages/55/07/029b7c45db910c74e182de626dfdae0ad489a949d84a468465cd0ca36355/rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a", size = 364292, upload-time = "2025-07-01T15:55:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/13/d1/9b3d3f986216b4d1f584878dca15ce4797aaf5d372d738974ba737bf68d6/rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf", size = 350334, upload-time = "2025-07-01T15:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/18/98/16d5e7bc9ec715fa9668731d0cf97f6b032724e61696e2db3d47aeb89214/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12", size = 384875, upload-time = "2025-07-01T15:55:20.399Z" }, + { url = "https://files.pythonhosted.org/packages/f9/13/aa5e2b1ec5ab0e86a5c464d53514c0467bec6ba2507027d35fc81818358e/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20", size = 399993, upload-time = "2025-07-01T15:55:21.729Z" }, + { url = "https://files.pythonhosted.org/packages/17/03/8021810b0e97923abdbab6474c8b77c69bcb4b2c58330777df9ff69dc559/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331", size = 516683, upload-time = "2025-07-01T15:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b1/da8e61c87c2f3d836954239fdbbfb477bb7b54d74974d8f6fcb34342d166/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f", size = 408825, upload-time = "2025-07-01T15:55:24.207Z" }, + { url = "https://files.pythonhosted.org/packages/38/bc/1fc173edaaa0e52c94b02a655db20697cb5fa954ad5a8e15a2c784c5cbdd/rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246", size = 387292, upload-time = "2025-07-01T15:55:25.554Z" }, + { url = "https://files.pythonhosted.org/packages/7c/eb/3a9bb4bd90867d21916f253caf4f0d0be7098671b6715ad1cead9fe7bab9/rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387", size = 420435, upload-time = "2025-07-01T15:55:27.798Z" }, + { url = "https://files.pythonhosted.org/packages/cd/16/e066dcdb56f5632713445271a3f8d3d0b426d51ae9c0cca387799df58b02/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af", size = 562410, upload-time = "2025-07-01T15:55:29.057Z" }, + { url = "https://files.pythonhosted.org/packages/60/22/ddbdec7eb82a0dc2e455be44c97c71c232983e21349836ce9f272e8a3c29/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33", size = 590724, upload-time = "2025-07-01T15:55:30.719Z" }, + { url = "https://files.pythonhosted.org/packages/2c/b4/95744085e65b7187d83f2fcb0bef70716a1ea0a9e5d8f7f39a86e5d83424/rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953", size = 558285, upload-time = "2025-07-01T15:55:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/37/37/6309a75e464d1da2559446f9c811aa4d16343cebe3dbb73701e63f760caa/rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9", size = 223459, upload-time = "2025-07-01T15:55:33.312Z" }, + { url = "https://files.pythonhosted.org/packages/d9/6f/8e9c11214c46098b1d1391b7e02b70bb689ab963db3b19540cba17315291/rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37", size = 236083, upload-time = "2025-07-01T15:55:34.933Z" }, + { url = "https://files.pythonhosted.org/packages/47/af/9c4638994dd623d51c39892edd9d08e8be8220a4b7e874fa02c2d6e91955/rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867", size = 223291, upload-time = "2025-07-01T15:55:36.202Z" }, + { url = "https://files.pythonhosted.org/packages/4d/db/669a241144460474aab03e254326b32c42def83eb23458a10d163cb9b5ce/rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da", size = 361445, upload-time = "2025-07-01T15:55:37.483Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2d/133f61cc5807c6c2fd086a46df0eb8f63a23f5df8306ff9f6d0fd168fecc/rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7", size = 347206, upload-time = "2025-07-01T15:55:38.828Z" }, + { url = "https://files.pythonhosted.org/packages/05/bf/0e8fb4c05f70273469eecf82f6ccf37248558526a45321644826555db31b/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad", size = 380330, upload-time = "2025-07-01T15:55:40.175Z" }, + { url = "https://files.pythonhosted.org/packages/d4/a8/060d24185d8b24d3923322f8d0ede16df4ade226a74e747b8c7c978e3dd3/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d", size = 392254, upload-time = "2025-07-01T15:55:42.015Z" }, + { url = "https://files.pythonhosted.org/packages/b9/7b/7c2e8a9ee3e6bc0bae26bf29f5219955ca2fbb761dca996a83f5d2f773fe/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca", size = 516094, upload-time = "2025-07-01T15:55:43.603Z" }, + { url = "https://files.pythonhosted.org/packages/75/d6/f61cafbed8ba1499b9af9f1777a2a199cd888f74a96133d8833ce5eaa9c5/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19", size = 402889, upload-time = "2025-07-01T15:55:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/92/19/c8ac0a8a8df2dd30cdec27f69298a5c13e9029500d6d76718130f5e5be10/rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8", size = 384301, upload-time = "2025-07-01T15:55:47.098Z" }, + { url = "https://files.pythonhosted.org/packages/41/e1/6b1859898bc292a9ce5776016c7312b672da00e25cec74d7beced1027286/rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b", size = 412891, upload-time = "2025-07-01T15:55:48.412Z" }, + { url = "https://files.pythonhosted.org/packages/ef/b9/ceb39af29913c07966a61367b3c08b4f71fad841e32c6b59a129d5974698/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a", size = 557044, upload-time = "2025-07-01T15:55:49.816Z" }, + { url = "https://files.pythonhosted.org/packages/2f/27/35637b98380731a521f8ec4f3fd94e477964f04f6b2f8f7af8a2d889a4af/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170", size = 585774, upload-time = "2025-07-01T15:55:51.192Z" }, + { url = "https://files.pythonhosted.org/packages/52/d9/3f0f105420fecd18551b678c9a6ce60bd23986098b252a56d35781b3e7e9/rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e", size = 554886, upload-time = "2025-07-01T15:55:52.541Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c5/347c056a90dc8dd9bc240a08c527315008e1b5042e7a4cf4ac027be9d38a/rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f", size = 219027, upload-time = "2025-07-01T15:55:53.874Z" }, + { url = "https://files.pythonhosted.org/packages/75/04/5302cea1aa26d886d34cadbf2dc77d90d7737e576c0065f357b96dc7a1a6/rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7", size = 232821, upload-time = "2025-07-01T15:55:55.167Z" }, +] + [[package]] name = "ruff" version = "0.12.2" From d7024735ea1e08f7fb4c0ba236ef604f77e61317 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Sun, 13 Jul 2025 17:44:00 +0530 Subject: [PATCH 3/9] added model of satellite --- .../models/satellite_database_model.py | 13 ++++- api-server/pyproject.toml | 1 + api-server/uv.lock | 52 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/api-server/app/satellite/models/satellite_database_model.py b/api-server/app/satellite/models/satellite_database_model.py index be65f013..851acb92 100644 --- a/api-server/app/satellite/models/satellite_database_model.py +++ b/api-server/app/satellite/models/satellite_database_model.py @@ -4,6 +4,7 @@ from datetime import datetime from pydantic import Field, Any, field_validator from .access_types import AccessTypeEnum +from docker_image import reference from app.project.models.project_database_model import Project @@ -29,6 +30,9 @@ class Satellite(Document): updated_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was last updated") + image_uri: str = Field(..., description="OCI/Docker image URI for the satellite") + + timeout: int = Field(..., description="Timeout of the satellite in seconds") @field_validator("configs", "inputs", "metrics", "outputs") def validate_jsonschema(cls, v: dict[str, Any]) -> dict[str, Any]: @@ -40,7 +44,14 @@ def validate_jsonschema(cls, v: dict[str, Any]) -> dict[str, Any]: raise ValueError(f"Invalid JSON schema: {e.message}") return v - + + @field_validator("image_uri") + def validate_image_uri(cls, v: str) -> str: + try: + reference.Reference.parse(v) + except Exception as e: + raise ValueError(f"Invalid image URI: {e.message}") + return v @before_event([Save, Replace]) def update_updated_at(self): diff --git a/api-server/pyproject.toml b/api-server/pyproject.toml index 3c916c62..e1b3302b 100644 --- a/api-server/pyproject.toml +++ b/api-server/pyproject.toml @@ -7,6 +7,7 @@ requires-python = ">=3.12" dependencies = [ "bcrypt>=4.3.0", "beanie>=1.30.0", + "docker-image-py>=0.1.13", "fastapi>=0.115.14", "jsonschema>=4.24.0", "pyjwt>=2.10.1", diff --git a/api-server/uv.lock b/api-server/uv.lock index 4572b75e..47b1357e 100644 --- a/api-server/uv.lock +++ b/api-server/uv.lock @@ -32,6 +32,7 @@ source = { virtual = "." } dependencies = [ { name = "bcrypt" }, { name = "beanie" }, + { name = "docker-image-py" }, { name = "fastapi" }, { name = "jsonschema" }, { name = "pyjwt" }, @@ -49,6 +50,7 @@ dev = [ requires-dist = [ { name = "bcrypt", specifier = ">=4.3.0" }, { name = "beanie", specifier = ">=1.30.0" }, + { name = "docker-image-py", specifier = ">=0.1.13" }, { name = "fastapi", specifier = ">=0.115.14" }, { name = "jsonschema", specifier = ">=4.24.0" }, { name = "pyjwt", specifier = ">=2.10.1" }, @@ -165,6 +167,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, ] +[[package]] +name = "docker-image-py" +version = "0.1.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/10/28dad68f4693a5131ff859ac9dc8eda7967fd922509c1e667e143b0760b8/docker_image_py-0.1.13.tar.gz", hash = "sha256:de2755de0a09c99ae3b4cf42cc470a83b35bfdc4bf8ad66a3d7550d622a8915a", size = 11211, upload-time = "2024-07-17T05:36:04.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/06/c8d170aeb3e9eb3d951dd37acf1b6bad2b9401d0bee3346e40295c9e15a2/docker_image_py-0.1.13-py3-none-any.whl", hash = "sha256:c217fc72e8cdf2aa2caa718c758cec1ad41c09972ec1c94e85a4bf79a8f81061", size = 8894, upload-time = "2024-07-17T05:36:02.563Z" }, +] + [[package]] name = "fastapi" version = "0.115.14" @@ -375,6 +389,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, ] +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, +] + [[package]] name = "rpds-py" version = "0.26.0" From 3f1f7bf8f8249641d84c6baf43e4fd77d9b6645c Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Sun, 13 Jul 2025 18:10:52 +0530 Subject: [PATCH 4/9] added request response models --- .../models/register_satellite_request.py | 13 +++++++++++++ .../models/register_satellite_response.py | 15 +++++++++++++++ .../models/satellite_database_model.py | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 api-server/app/satellite/models/register_satellite_request.py create mode 100644 api-server/app/satellite/models/register_satellite_response.py diff --git a/api-server/app/satellite/models/register_satellite_request.py b/api-server/app/satellite/models/register_satellite_request.py new file mode 100644 index 00000000..69af19f5 --- /dev/null +++ b/api-server/app/satellite/models/register_satellite_request.py @@ -0,0 +1,13 @@ +from pydantic import BaseModel +from .access_types import AccessTypeEnum +from typing import Any + +class RegisterSatelliteRequest(BaseModel): + name: str + friendly_name: str + description: str + access_type: AccessTypeEnum + configs: dict[str, Any] + inputs: dict[str, Any] + metrics: dict[str, Any] + outputs: dict[str, Any] \ No newline at end of file diff --git a/api-server/app/satellite/models/register_satellite_response.py b/api-server/app/satellite/models/register_satellite_response.py new file mode 100644 index 00000000..ee7ce6c3 --- /dev/null +++ b/api-server/app/satellite/models/register_satellite_response.py @@ -0,0 +1,15 @@ +from pydantic import BaseModel +from .access_types import AccessTypeEnum +from typing import Any + +class RegisterSatelliteResponse(BaseModel): + id: str + name: str + friendly_name: str + description: str + access_type: AccessTypeEnum + configs: dict[str, Any] + inputs: dict[str, Any] + metrics: dict[str, Any] + outputs: dict[str, Any] + project: str \ No newline at end of file diff --git a/api-server/app/satellite/models/satellite_database_model.py b/api-server/app/satellite/models/satellite_database_model.py index 851acb92..152ab80c 100644 --- a/api-server/app/satellite/models/satellite_database_model.py +++ b/api-server/app/satellite/models/satellite_database_model.py @@ -20,12 +20,17 @@ class Satellite(Document): access_type: AccessTypeEnum = Field(..., description="Access type of the satellite") configs: dict[str, Any] = Field(..., description="Configurations of the satellite, a valid jsonschema object for the configs") + inputs: dict[str, Any] = Field(..., description="Input data fothe satellite, a valid jsonschema object for the inputs") + metrics: dict[str, Any] = Field(..., description="Metrics of the satellite, a valid jsonschema object for the metrics") + outputs: dict[str, Any] = Field(..., description="Outputs of the satellite, a valid jsonschema object for the outputs") project: Link[Project] = Field(..., description="Project of the satellite") + project_name: str = Field(..., description="Name of the project of the satellite") + created_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was created") updated_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was last updated") @@ -52,6 +57,19 @@ def validate_image_uri(cls, v: str) -> str: except Exception as e: raise ValueError(f"Invalid image URI: {e.message}") return v + + @field_validator("name") + def validate_name(cls, v: str) -> str: + + not_allowed_chars = ["/", ".", " "] + + if not v: + raise ValueError("Name cannot be empty") + if len(v) > 100: + raise ValueError("Name cannot be longer than 100 characters") + if any(char in not_allowed_chars for char in v): + raise ValueError("Name cannot contain the following characters: /, ., or whitespace") + return v @before_event([Save, Replace]) def update_updated_at(self): From 79a8463d376b9d2a3b61efe9840b67625cb52f80 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Sun, 13 Jul 2025 18:17:45 +0530 Subject: [PATCH 5/9] deleting useless code --- .github/workflows/deploy-api-server.yml | 52 ------------------------- 1 file changed, 52 deletions(-) delete mode 100644 .github/workflows/deploy-api-server.yml diff --git a/.github/workflows/deploy-api-server.yml b/.github/workflows/deploy-api-server.yml deleted file mode 100644 index 67968831..00000000 --- a/.github/workflows/deploy-api-server.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Publish API server image to GHCR and deploys to Kubernetes Cluster - -on: - push: - branches: [main] - paths: - - 'api-server/**' - release: - types: [published] - workflow_dispatch: - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/exosphere-api-server - -jobs: - publish-image: - runs-on: ubuntu-latest - - permissions: - contents: read - packages: write - - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Generate tags & labels - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest - type=sha,format=short - type=ref,event=tag # v1.2.3 → v1.2.3 - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: ./api-server - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} From 44b1cb2fd7001bae8dc0d6c313418629a482f8d7 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Sun, 13 Jul 2025 18:23:25 +0530 Subject: [PATCH 6/9] fixed models --- .../app/satellite/models/register_satellite_request.py | 3 ++- .../app/satellite/models/register_satellite_response.py | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api-server/app/satellite/models/register_satellite_request.py b/api-server/app/satellite/models/register_satellite_request.py index 69af19f5..2896ddff 100644 --- a/api-server/app/satellite/models/register_satellite_request.py +++ b/api-server/app/satellite/models/register_satellite_request.py @@ -3,10 +3,11 @@ from typing import Any class RegisterSatelliteRequest(BaseModel): - name: str friendly_name: str description: str access_type: AccessTypeEnum + image_uri: str + timeout: int configs: dict[str, Any] inputs: dict[str, Any] metrics: dict[str, Any] diff --git a/api-server/app/satellite/models/register_satellite_response.py b/api-server/app/satellite/models/register_satellite_response.py index ee7ce6c3..e45ab26b 100644 --- a/api-server/app/satellite/models/register_satellite_response.py +++ b/api-server/app/satellite/models/register_satellite_response.py @@ -1,6 +1,8 @@ from pydantic import BaseModel from .access_types import AccessTypeEnum from typing import Any +from datetime import datetime + class RegisterSatelliteResponse(BaseModel): id: str @@ -12,4 +14,9 @@ class RegisterSatelliteResponse(BaseModel): inputs: dict[str, Any] metrics: dict[str, Any] outputs: dict[str, Any] - project: str \ No newline at end of file + project: str + project_name: str + created_at: datetime + updated_at: datetime + image_uri: str + timeout: int \ No newline at end of file From 150a0ac1529050ac761149a71136e7cdf465fc6e Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 14 Jul 2025 09:51:09 +0530 Subject: [PATCH 7/9] added project checking --- .../app/auth/controllers/create_token.py | 34 +++++++++++++++++-- api-server/app/auth/models/token_claims.py | 4 +++ api-server/app/auth/models/token_request.py | 8 ++++- .../auth/{ => services}/get_token_claims.py | 2 +- api-server/app/project/routes.py | 2 +- 5 files changed, 45 insertions(+), 5 deletions(-) rename api-server/app/auth/{ => services}/get_token_claims.py (95%) diff --git a/api-server/app/auth/controllers/create_token.py b/api-server/app/auth/controllers/create_token.py index bebd151b..67283824 100644 --- a/api-server/app/auth/controllers/create_token.py +++ b/api-server/app/auth/controllers/create_token.py @@ -2,6 +2,7 @@ import jwt from datetime import datetime, timedelta from starlette.responses import JSONResponse +from bson import ObjectId from ..models.token_request import TokenRequest from ..models.token_response import TokenResponse @@ -10,6 +11,8 @@ from app.singletons.logs_manager import LogsManager from app.user.models.user_database_model import User +from app.project.models.project_database_model import Project + logger = LogsManager().get_logger() @@ -37,17 +40,44 @@ async def create_token(request: TokenRequest, x_exosphere_request_id: str) -> To logger.info("User found and credential verified", x_exosphere_request_id=x_exosphere_request_id) - logger.info("User is a super admin", x_exosphere_request_id=x_exosphere_request_id) - + previlage = None + + if request.project: + + project = await Project.get(ObjectId(request.project)) + + if not project: + logger.error("Project not found", x_exosphere_request_id=x_exosphere_request_id) + return JSONResponse(status_code=404, content={"success": False, "detail": "Project not found"}) + + logger.info("Project found", x_exosphere_request_id=x_exosphere_request_id) + + if project.super_admin.ref.id == user.id: + previlage = "super_admin" + + for user in project.users: + if user.user.ref.id == user.id: + previlage = user.permission.value + break + + if not previlage: + logger.error("User does not have access to the project", x_exosphere_request_id=x_exosphere_request_id) + return JSONResponse(status_code=403, content={"success": False, "detail": "User does not have access to the project"}) + + token_claims = TokenClaims( user_id=str(user.id), user_name=user.name, user_type=user.type, verification_status=user.verification_status, status=user.status, + project=request.project, + previlage=previlage, + satellites=request.satellites, exp=int((datetime.now() + timedelta(seconds=JWT_EXPIRES_IN)).timestamp()) ) + return TokenResponse( access_token=jwt.encode(token_claims.model_dump(), JWT_SECRET_KEY, algorithm=JWT_ALGORITHM) ) diff --git a/api-server/app/auth/models/token_claims.py b/api-server/app/auth/models/token_claims.py index 3283ea65..9b657d88 100644 --- a/api-server/app/auth/models/token_claims.py +++ b/api-server/app/auth/models/token_claims.py @@ -1,4 +1,5 @@ from pydantic import BaseModel +from typing import Optional class TokenClaims(BaseModel): user_id: str @@ -6,4 +7,7 @@ class TokenClaims(BaseModel): user_type: str verification_status: str status: str + project: Optional[str] = None + previlage: Optional[str] = None + satellites: Optional[list[str]] = None exp: int \ No newline at end of file diff --git a/api-server/app/auth/models/token_request.py b/api-server/app/auth/models/token_request.py index bc6deda0..3f049701 100644 --- a/api-server/app/auth/models/token_request.py +++ b/api-server/app/auth/models/token_request.py @@ -1,5 +1,11 @@ from pydantic import BaseModel, Field +from typing import Optional class TokenRequest(BaseModel): identifier: str = Field(..., description="Identifier of the user, could be an email, phone, username, etc.") - credential: str = Field(..., description="Credential of the user, could be a password, api secret, etc.") \ No newline at end of file + + credential: str = Field(..., description="Credential of the user, could be a password, api secret, etc.") + + project: Optional[str] = Field(None, description="Project id against which the token is being requested.") + + satellites: Optional[list[str]] = Field(None, description="Satellites against which the token is being requested.") \ No newline at end of file diff --git a/api-server/app/auth/get_token_claims.py b/api-server/app/auth/services/get_token_claims.py similarity index 95% rename from api-server/app/auth/get_token_claims.py rename to api-server/app/auth/services/get_token_claims.py index ef9a1858..719dbdf7 100644 --- a/api-server/app/auth/get_token_claims.py +++ b/api-server/app/auth/services/get_token_claims.py @@ -4,7 +4,7 @@ from app.singletons.logs_manager import LogsManager -from .models.token_claims import TokenClaims +from ..models.token_claims import TokenClaims logger = LogsManager().get_logger() diff --git a/api-server/app/project/routes.py b/api-server/app/project/routes.py index 480a4964..b7415fa4 100644 --- a/api-server/app/project/routes.py +++ b/api-server/app/project/routes.py @@ -7,7 +7,7 @@ from .models.create_project_request import CreateProjectRequest from .models.create_project_response import CreateProjectResponse -from app.auth.get_token_claims import get_token_claims +from app.auth.services.get_token_claims import get_token_claims router = APIRouter(prefix="/v0/project", tags=["project"]) From 0e4c7d9de61fe23fdcda4a05e18d1ea0374cbbd4 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 14 Jul 2025 15:12:08 +0530 Subject: [PATCH 8/9] fixed registration process --- .../app/auth/services/get_token_claims.py | 3 +- api-server/app/main.py | 5 +- .../controllers/register_satellite.py | 62 +++++++++++++++++++ .../models/register_satellite_request.py | 7 ++- .../models/register_satellite_response.py | 6 +- .../models/satellite_database_model.py | 18 ++++-- api-server/app/satellite/routes.py | 27 ++++++++ 7 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 api-server/app/satellite/controllers/register_satellite.py create mode 100644 api-server/app/satellite/routes.py diff --git a/api-server/app/auth/services/get_token_claims.py b/api-server/app/auth/services/get_token_claims.py index 719dbdf7..dbfba230 100644 --- a/api-server/app/auth/services/get_token_claims.py +++ b/api-server/app/auth/services/get_token_claims.py @@ -1,6 +1,7 @@ import jwt import os import time +from typing import Optional from app.singletons.logs_manager import LogsManager @@ -14,7 +15,7 @@ JWT_ALGORITHM = "HS256" -async def get_token_claims(token: str, x_exosphere_request_id: str): +async def get_token_claims(token: str, x_exosphere_request_id: str) -> Optional[TokenClaims]: try: claims = TokenClaims(**jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])) logger.info("Token claims decoded", x_exosphere_request_id=x_exosphere_request_id, user_id=claims.user_id) diff --git a/api-server/app/main.py b/api-server/app/main.py index 0a416849..9f0756e3 100644 --- a/api-server/app/main.py +++ b/api-server/app/main.py @@ -21,11 +21,13 @@ # injecting databases from .user.models.user_database_model import User from .project.models.project_database_model import Project +from .satellite.models.satellite_database_model import Satellite # injecting routers from .user.routes import router as user_router from .auth.routes import router as auth_router from .project.routes import router as project_router +from .satellite.routes import router as satellite_router load_dotenv() @@ -39,7 +41,7 @@ async def lifespan(app: FastAPI): # initializing beanie client = AsyncIOMotorClient(os.getenv("MONGO_URI")) db = client[os.getenv("MONGO_DATABASE_NAME")] - await init_beanie(db, document_models=[User, Project]) + await init_beanie(db, document_models=[User, Project, Satellite]) logger.info("beanie dbs initialized") # main logic of the server @@ -80,3 +82,4 @@ def health() -> dict: app.include_router(user_router) app.include_router(auth_router) app.include_router(project_router) +app.include_router(satellite_router) diff --git a/api-server/app/satellite/controllers/register_satellite.py b/api-server/app/satellite/controllers/register_satellite.py new file mode 100644 index 00000000..07aa3ae1 --- /dev/null +++ b/api-server/app/satellite/controllers/register_satellite.py @@ -0,0 +1,62 @@ +from beanie import Link +from bson import ObjectId +from pymongo.errors import DuplicateKeyError +from fastapi.responses import JSONResponse + +from ..models.register_satellite_request import RegisterSatelliteRequest +from ..models.register_satellite_response import RegisterSatelliteResponse +from ..models.satellite_database_model import Satellite + +from app.auth.models.token_claims import TokenClaims +from app.project.models.project_database_model import Project +from app.singletons.logs_manager import LogsManager + +logger = LogsManager().get_logger() + + +async def register_satellite(request: RegisterSatelliteRequest, project_id: str, claims: TokenClaims, x_exosphere_request_id: str) -> RegisterSatelliteResponse: + + try: + logger.info("Registering satellite", x_exosphere_request_id=x_exosphere_request_id, project_id=project_id, name=request.name) + + satellite = Satellite( + name=request.name, + friendly_name=request.friendly_name, + description=request.description, + access_type=request.access_type, + configs=request.configs, + inputs=request.inputs, + metrics=request.metrics, + outputs=request.outputs, + project=Link(ObjectId(project_id), Project), + project_name=project_id, + image_uri=request.image_uri, + timeout=request.timeout + ) + await satellite.insert() + logger.info("Satellite registered", x_exosphere_request_id=x_exosphere_request_id, project_id=project_id, name=request.name) + + return RegisterSatelliteResponse( + id=str(satellite.id), + name=satellite.name, + friendly_name=satellite.friendly_name, + description=satellite.description, + access_type=satellite.access_type, + configs=satellite.configs, + inputs=satellite.inputs, + metrics=satellite.metrics, + outputs=satellite.outputs, + project=project_id, + project_name=satellite.project_name, + image_uri=satellite.image_uri, + timeout=satellite.timeout, + created_at=satellite.created_at, + updated_at=satellite.updated_at + ) + except DuplicateKeyError as e: + logger.error("Error registering satellite", x_exosphere_request_id=x_exosphere_request_id, project_id=project_id, name=request.name, error=e) + return JSONResponse(status_code=400, content={"message": "Satellite already exists", "success": False}) + + except Exception as e: + logger.error("Error registering satellite", x_exosphere_request_id=x_exosphere_request_id, project_id=project_id, name=request.name, error=e) + raise e \ No newline at end of file diff --git a/api-server/app/satellite/models/register_satellite_request.py b/api-server/app/satellite/models/register_satellite_request.py index 2896ddff..9618250f 100644 --- a/api-server/app/satellite/models/register_satellite_request.py +++ b/api-server/app/satellite/models/register_satellite_request.py @@ -1,13 +1,14 @@ from pydantic import BaseModel from .access_types import AccessTypeEnum -from typing import Any +from typing import Any, Optional class RegisterSatelliteRequest(BaseModel): + name: str friendly_name: str description: str access_type: AccessTypeEnum - image_uri: str - timeout: int + image_uri: Optional[str] = None + timeout: Optional[int] = None configs: dict[str, Any] inputs: dict[str, Any] metrics: dict[str, Any] diff --git a/api-server/app/satellite/models/register_satellite_response.py b/api-server/app/satellite/models/register_satellite_response.py index e45ab26b..c8d71ec7 100644 --- a/api-server/app/satellite/models/register_satellite_response.py +++ b/api-server/app/satellite/models/register_satellite_response.py @@ -1,6 +1,6 @@ from pydantic import BaseModel from .access_types import AccessTypeEnum -from typing import Any +from typing import Any, Optional from datetime import datetime @@ -18,5 +18,5 @@ class RegisterSatelliteResponse(BaseModel): project_name: str created_at: datetime updated_at: datetime - image_uri: str - timeout: int \ No newline at end of file + image_uri: Optional[str] = None + timeout: Optional[int] = None \ No newline at end of file diff --git a/api-server/app/satellite/models/satellite_database_model.py b/api-server/app/satellite/models/satellite_database_model.py index 152ab80c..1e99467a 100644 --- a/api-server/app/satellite/models/satellite_database_model.py +++ b/api-server/app/satellite/models/satellite_database_model.py @@ -2,16 +2,18 @@ from beanie import Document, Indexed, before_event, Replace, Save, Link from datetime import datetime -from pydantic import Field, Any, field_validator +from pydantic import Field, field_validator from .access_types import AccessTypeEnum from docker_image import reference +from typing import Optional, Any +from pymongo import IndexModel, ASCENDING from app.project.models.project_database_model import Project class Satellite(Document): - name: Indexed(str, unique=True) = Field(..., description="Name of the satellite") + name: str = Field(..., description="Name of the satellite") friendly_name: str = Field(..., description="Friendly name of the satellite") @@ -35,9 +37,9 @@ class Satellite(Document): updated_at: datetime = Field(default_factory=datetime.now, description="Date and time when the satellite was last updated") - image_uri: str = Field(..., description="OCI/Docker image URI for the satellite") + image_uri: Optional[str] = Field(None, description="OCI/Docker image URI for the satellite, if not provided autoscalling and dynamic scaling would not be available") - timeout: int = Field(..., description="Timeout of the satellite in seconds") + timeout: Optional[int] = Field(None, description="Timeout of the satellite in seconds") @field_validator("configs", "inputs", "metrics", "outputs") def validate_jsonschema(cls, v: dict[str, Any]) -> dict[str, Any]: @@ -52,6 +54,8 @@ def validate_jsonschema(cls, v: dict[str, Any]) -> dict[str, Any]: @field_validator("image_uri") def validate_image_uri(cls, v: str) -> str: + if not v: + return v try: reference.Reference.parse(v) except Exception as e: @@ -71,6 +75,12 @@ def validate_name(cls, v: str) -> str: raise ValueError("Name cannot contain the following characters: /, ., or whitespace") return v + class Settings: + name = "Satellites" + indexes = [ + IndexModel([("name", ASCENDING), ("project", ASCENDING)], unique=True) + ] + @before_event([Save, Replace]) def update_updated_at(self): self.updated_at = datetime.now() \ No newline at end of file diff --git a/api-server/app/satellite/routes.py b/api-server/app/satellite/routes.py new file mode 100644 index 00000000..546590c9 --- /dev/null +++ b/api-server/app/satellite/routes.py @@ -0,0 +1,27 @@ +from fastapi import APIRouter, status, Request, Depends +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials +from typing import Annotated +from fastapi.responses import JSONResponse + +from app.auth.services.get_token_claims import get_token_claims +from .controllers.register_satellite import register_satellite + +from .models.register_satellite_request import RegisterSatelliteRequest +from .models.register_satellite_response import RegisterSatelliteResponse + +router = APIRouter(prefix="/v0/project/{project_id}/satellite", tags=["satellite"]) + +@router.post( + "/", + response_model=RegisterSatelliteResponse, + status_code=status.HTTP_201_CREATED, + response_description="Satellite registered successfully" +) +async def register_satellite_route(project_id: str, body: RegisterSatelliteRequest, request: Request, token: Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer())]): + x_exosphere_request_id = getattr(request.state, "x_exosphere_request_id", None) + claims = await get_token_claims(token.credentials, x_exosphere_request_id) + + if claims is None or claims.project != project_id: + return JSONResponse(status_code=401, content={"message": "Invalid token", "success": False}) + + return await register_satellite(body, project_id, claims, x_exosphere_request_id) \ No newline at end of file From 0fc18df11025eed40e34c33895988e3d573897d6 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 14 Jul 2025 15:13:44 +0530 Subject: [PATCH 9/9] fixed RUFF checks --- api-server/app/satellite/models/satellite_database_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-server/app/satellite/models/satellite_database_model.py b/api-server/app/satellite/models/satellite_database_model.py index 1e99467a..a889a119 100644 --- a/api-server/app/satellite/models/satellite_database_model.py +++ b/api-server/app/satellite/models/satellite_database_model.py @@ -1,6 +1,6 @@ import jsonschema -from beanie import Document, Indexed, before_event, Replace, Save, Link +from beanie import Document, before_event, Replace, Save, Link from datetime import datetime from pydantic import Field, field_validator from .access_types import AccessTypeEnum