Loading .env.example 0 → 100644 +42 −0 Changes for .env.example: 42 added lines, 0 removed lines. Original line number Diff line number Diff line # Copy this file to .env and adjust as needed. Every value below is optional # -- src/open_exposure_gateway/core/config.py already has a working default # for each one, shown here. Uncomment and edit only what you need to change. # APP_NAME="Open Exposure Gateway" # APP_VERSION="1.0.0" # DEBUG=false # HOST="0.0.0.0" # PORT=8080 # PUBLIC_BASE_URL="http://localhost:8080" # SRM_SETTINGS__BASE_URL="http://localhost:8081" # SRM_SETTINGS__TIMEOUT=10.0 # POSTGRESQL_SETTINGS__URL="postgresql+asyncpg://postgres:postgres@localhost:5432/oeg" # POSTGRESQL_SETTINGS__ECHO=false # POSTGRESQL_SETTINGS__CREATE_SCHEMA_ON_STARTUP=false # NATS_SETTINGS__URL="nats://localhost:4222" # NATS_SETTINGS__CONNECT_TIMEOUT=10 # NATS_SETTINGS__MAX_RECONNECT_ATTEMPTS=3 # OBSERVABILITY_SETTINGS__LOG_LEVEL="INFO" # CALLBACK_SETTINGS__TIMEOUT=10.0 # Encrypts the callback tokens clients send (EAM sinkCredential, QoD # notificationAuthToken) before they are stored. Must be base64url of exactly # 32 bytes; generate one with: # python -c "import os,base64;print(base64.urlsafe_b64encode(os.urandom(32)).decode())" # Unset (the default) means OEG rejects any request carrying such a token with 501. # Changing it makes every token already stored unreadable, so keep it stable. # CALLBACK_SETTINGS__SECRET_KEY="" # QOD_SETTINGS__SERVICE_SPECIFICATION_ID="7608e902-b927-559f-b448-e7e9061dfa5c" # LOCATION_RETRIEVAL_SETTINGS__SERVICE_SPECIFICATION_ID="0129e7ce-8e02-5dfd-bae1-0303bcc7676e" # TI_SETTINGS__SERVICE_SPECIFICATION_ID="baba6a12-c7b6-507b-9805-5755d38131ee" # KEYCLOAK_SETTINGS__* default to a deliberately-unreachable `.invalid` host so a # misconfigured deployment fails loudly instead of silently trusting the wrong # Keycloak. Point these at your actual realm, e.g. (matches the oop-platform-chart): # KEYCLOAK_SETTINGS__ISSUER="http://localhost:8080/realms/oop" # KEYCLOAK_SETTINGS__JWKS_URL="http://localhost:8080/realms/oop/protocol/openid-connect/certs" # KEYCLOAK_SETTINGS__AUDIENCE="oeg" .gitignore +12 −1 Changes for .gitignore: 12 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,13 +15,24 @@ wheels/ # code editors .vscode/ # AI software tools .claude CLAUDE.md .tox/ htmlcov/ .mypy_cache/ .pytest_cache/ .ruff_cache/ .cache/ .hypothesis/ .idea/ .coverage .python_version coverage.xml uv.lock # Runtime scratch files .tmp/ # Cursor editor config .cursor/ .gitlab-ci.yml +72 −25 Changes for .gitlab-ci.yml: 72 added lines, 25 removed lines. Original line number Diff line number Diff line default: image: python:3.12-slim cache: paths: - .cache/uv before_script: - cd "$CI_PROJECT_DIR/${BACKEND_DIR:-.}" - pip install uv - export UV_SYSTEM_CERTS=1 - uv sync --locked --extra dev - . .venv/bin/activate stages: - build - push - type - architecture - lint - format - test - build-and-push before_script: - docker info variables: UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv" build: stage: build tags: - shell type: stage: type script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -t $CI_REGISTRY_IMAGE:latest . rules: - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ push: stage: push tags: - shell needs: - build - mypy src/ tests/ architecture: stage: architecture script: - lint-imports lint: stage: lint script: - ruff check src/ tests/ format: stage: format script: - ruff format --check src/ tests/ test: stage: test variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" services: - docker:dind script: - pytest tests/unit tests/integration --cov=src/open_exposure_gateway --cov-branch --cov-report=term-missing || [ $? -eq 5 ] #bypass no tests found error. coverage: '/TOTAL.+ ([0-9]{1,3}(?:\.[0-9]+)?%)/' conformance: stage: test allow_failure: true script: - pytest tests/conformance build-and-push: stage: build-and-push image: docker:cli variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" services: - docker:dind before_script: - docker info script: - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" $CI_REGISTRY --password-stdin - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG - docker push $CI_REGISTRY_IMAGE:latest - docker logout $CI_REGISTRY - export TEST_IMAGE_TAG="ci-${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}" - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin - docker buildx build --provenance=false --network=host -t "$CI_REGISTRY_IMAGE:$TEST_IMAGE_TAG" --push . - docker logout "$CI_REGISTRY" rules: - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ No newline at end of file - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"' .pre-commit-config.yaml 0 → 100644 +26 −0 Changes for .pre-commit-config.yaml: 26 added lines, 0 removed lines. Original line number Diff line number Diff line repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: check-yaml - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.15.6 hooks: # Run the linter. - id: ruff-check # Run the formatter. - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.19.1 # Use the sha / tag you want to point at hooks: - id: mypy files: ^src/open_exposure_gateway/|^tests/ args: [--strict, --ignore-missing-imports, --cache-dir, .cache/mypy] additional_dependencies: ["fastapi[standard]>=0.135.1", "pydantic>=2.0", "pydantic-settings>=2.0", "httpx>=0.27", "pytest>=9.0.2", "sqlalchemy>=2.0.48", "pytest-asyncio>=0.24", "testcontainers>=4.0.0", "types-PyYAML>=6.0.1", "pyjwt[crypto]>=2.10.1"] Dockerfile +32 −9 Changes for Dockerfile: 32 added lines, 9 removed lines. Original line number Diff line number Diff line FROM python:3.12-alpine FROM ghcr.io/astral-sh/uv:0.12.19 AS uv RUN mkdir -p /usr/src/app WORKDIR /usr/src/app FROM python:3.12-slim AS builder COPY requirements.txt /usr/src/app/ COPY --from=uv /uv /bin/uv RUN pip install --no-cache-dir --trusted-host pypi.org --trusted-host files.pythonhosted.org -r requirements.txt WORKDIR /app COPY . /usr/src/app # Install exactly what uv.lock pins (same as CI), so a new upstream release # can't change the image without a lockfile change. uv verifies every package # against the hashes in uv.lock, so the trusted hosts only relax TLS checks for # networks that intercept HTTPS, not package integrity. ENV UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy \ UV_PYTHON_DOWNLOADS=never \ UV_HTTP_TIMEOUT=120 \ UV_INSECURE_HOST="pypi.org files.pythonhosted.org" EXPOSE 8080 # Dependencies first, so this layer is cached until uv.lock changes. COPY pyproject.toml uv.lock ./ RUN uv sync --locked --no-install-project COPY README.md ./ COPY src/ ./src/ RUN uv sync --locked --no-editable FROM python:3.12-slim AS runtime WORKDIR /app ENTRYPOINT ["python"] COPY --from=builder /app/.venv /app/.venv ENV PATH="/app/.venv/bin:$PATH" ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 EXPOSE 8080 CMD ["-m", "edge_cloud_management_api"] CMD ["uvicorn", "open_exposure_gateway.main:app", "--host", "0.0.0.0", "--port", "8080"] Loading
.env.example 0 → 100644 +42 −0 Changes for .env.example: 42 added lines, 0 removed lines. Original line number Diff line number Diff line # Copy this file to .env and adjust as needed. Every value below is optional # -- src/open_exposure_gateway/core/config.py already has a working default # for each one, shown here. Uncomment and edit only what you need to change. # APP_NAME="Open Exposure Gateway" # APP_VERSION="1.0.0" # DEBUG=false # HOST="0.0.0.0" # PORT=8080 # PUBLIC_BASE_URL="http://localhost:8080" # SRM_SETTINGS__BASE_URL="http://localhost:8081" # SRM_SETTINGS__TIMEOUT=10.0 # POSTGRESQL_SETTINGS__URL="postgresql+asyncpg://postgres:postgres@localhost:5432/oeg" # POSTGRESQL_SETTINGS__ECHO=false # POSTGRESQL_SETTINGS__CREATE_SCHEMA_ON_STARTUP=false # NATS_SETTINGS__URL="nats://localhost:4222" # NATS_SETTINGS__CONNECT_TIMEOUT=10 # NATS_SETTINGS__MAX_RECONNECT_ATTEMPTS=3 # OBSERVABILITY_SETTINGS__LOG_LEVEL="INFO" # CALLBACK_SETTINGS__TIMEOUT=10.0 # Encrypts the callback tokens clients send (EAM sinkCredential, QoD # notificationAuthToken) before they are stored. Must be base64url of exactly # 32 bytes; generate one with: # python -c "import os,base64;print(base64.urlsafe_b64encode(os.urandom(32)).decode())" # Unset (the default) means OEG rejects any request carrying such a token with 501. # Changing it makes every token already stored unreadable, so keep it stable. # CALLBACK_SETTINGS__SECRET_KEY="" # QOD_SETTINGS__SERVICE_SPECIFICATION_ID="7608e902-b927-559f-b448-e7e9061dfa5c" # LOCATION_RETRIEVAL_SETTINGS__SERVICE_SPECIFICATION_ID="0129e7ce-8e02-5dfd-bae1-0303bcc7676e" # TI_SETTINGS__SERVICE_SPECIFICATION_ID="baba6a12-c7b6-507b-9805-5755d38131ee" # KEYCLOAK_SETTINGS__* default to a deliberately-unreachable `.invalid` host so a # misconfigured deployment fails loudly instead of silently trusting the wrong # Keycloak. Point these at your actual realm, e.g. (matches the oop-platform-chart): # KEYCLOAK_SETTINGS__ISSUER="http://localhost:8080/realms/oop" # KEYCLOAK_SETTINGS__JWKS_URL="http://localhost:8080/realms/oop/protocol/openid-connect/certs" # KEYCLOAK_SETTINGS__AUDIENCE="oeg"
.gitignore +12 −1 Changes for .gitignore: 12 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,13 +15,24 @@ wheels/ # code editors .vscode/ # AI software tools .claude CLAUDE.md .tox/ htmlcov/ .mypy_cache/ .pytest_cache/ .ruff_cache/ .cache/ .hypothesis/ .idea/ .coverage .python_version coverage.xml uv.lock # Runtime scratch files .tmp/ # Cursor editor config .cursor/
.gitlab-ci.yml +72 −25 Changes for .gitlab-ci.yml: 72 added lines, 25 removed lines. Original line number Diff line number Diff line default: image: python:3.12-slim cache: paths: - .cache/uv before_script: - cd "$CI_PROJECT_DIR/${BACKEND_DIR:-.}" - pip install uv - export UV_SYSTEM_CERTS=1 - uv sync --locked --extra dev - . .venv/bin/activate stages: - build - push - type - architecture - lint - format - test - build-and-push before_script: - docker info variables: UV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/uv" build: stage: build tags: - shell type: stage: type script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -t $CI_REGISTRY_IMAGE:latest . rules: - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ push: stage: push tags: - shell needs: - build - mypy src/ tests/ architecture: stage: architecture script: - lint-imports lint: stage: lint script: - ruff check src/ tests/ format: stage: format script: - ruff format --check src/ tests/ test: stage: test variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" services: - docker:dind script: - pytest tests/unit tests/integration --cov=src/open_exposure_gateway --cov-branch --cov-report=term-missing || [ $? -eq 5 ] #bypass no tests found error. coverage: '/TOTAL.+ ([0-9]{1,3}(?:\.[0-9]+)?%)/' conformance: stage: test allow_failure: true script: - pytest tests/conformance build-and-push: stage: build-and-push image: docker:cli variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" services: - docker:dind before_script: - docker info script: - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" $CI_REGISTRY --password-stdin - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG - docker push $CI_REGISTRY_IMAGE:latest - docker logout $CI_REGISTRY - export TEST_IMAGE_TAG="ci-${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}" - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin - docker buildx build --provenance=false --network=host -t "$CI_REGISTRY_IMAGE:$TEST_IMAGE_TAG" --push . - docker logout "$CI_REGISTRY" rules: - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ No newline at end of file - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
.pre-commit-config.yaml 0 → 100644 +26 −0 Changes for .pre-commit-config.yaml: 26 added lines, 0 removed lines. Original line number Diff line number Diff line repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: check-yaml - id: check-toml - id: end-of-file-fixer - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.15.6 hooks: # Run the linter. - id: ruff-check # Run the formatter. - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.19.1 # Use the sha / tag you want to point at hooks: - id: mypy files: ^src/open_exposure_gateway/|^tests/ args: [--strict, --ignore-missing-imports, --cache-dir, .cache/mypy] additional_dependencies: ["fastapi[standard]>=0.135.1", "pydantic>=2.0", "pydantic-settings>=2.0", "httpx>=0.27", "pytest>=9.0.2", "sqlalchemy>=2.0.48", "pytest-asyncio>=0.24", "testcontainers>=4.0.0", "types-PyYAML>=6.0.1", "pyjwt[crypto]>=2.10.1"]
Dockerfile +32 −9 Changes for Dockerfile: 32 added lines, 9 removed lines. Original line number Diff line number Diff line FROM python:3.12-alpine FROM ghcr.io/astral-sh/uv:0.12.19 AS uv RUN mkdir -p /usr/src/app WORKDIR /usr/src/app FROM python:3.12-slim AS builder COPY requirements.txt /usr/src/app/ COPY --from=uv /uv /bin/uv RUN pip install --no-cache-dir --trusted-host pypi.org --trusted-host files.pythonhosted.org -r requirements.txt WORKDIR /app COPY . /usr/src/app # Install exactly what uv.lock pins (same as CI), so a new upstream release # can't change the image without a lockfile change. uv verifies every package # against the hashes in uv.lock, so the trusted hosts only relax TLS checks for # networks that intercept HTTPS, not package integrity. ENV UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy \ UV_PYTHON_DOWNLOADS=never \ UV_HTTP_TIMEOUT=120 \ UV_INSECURE_HOST="pypi.org files.pythonhosted.org" EXPOSE 8080 # Dependencies first, so this layer is cached until uv.lock changes. COPY pyproject.toml uv.lock ./ RUN uv sync --locked --no-install-project COPY README.md ./ COPY src/ ./src/ RUN uv sync --locked --no-editable FROM python:3.12-slim AS runtime WORKDIR /app ENTRYPOINT ["python"] COPY --from=builder /app/.venv /app/.venv ENV PATH="/app/.venv/bin:$PATH" ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 EXPOSE 8080 CMD ["-m", "edge_cloud_management_api"] CMD ["uvicorn", "open_exposure_gateway.main:app", "--host", "0.0.0.0", "--port", "8080"]