Commit 0a3ee432 authored by George Papathanail's avatar George Papathanail
Browse files

fix: return the submitted appProvider on GET /apps instead of the caller's sub

parent 768ae78c
Loading
Loading
Loading
Loading
+6 −1
Changes for src/open_exposure_gateway/application/mappers/edge_application_mapper.py: 6 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -101,6 +101,10 @@ _CALLBACK_EVENT_SOURCE = "https://api.example.com/edge-application-management/v1

_VISIBILITY_REVERSE_MAP: dict[str, str] = {v: k for k, v in _VISIBILITY_MAP.items()}

# Returned as `appProvider` for apps registered before the submitted name was stored in the
# spec descriptor. Must itself satisfy CAMARA's AppProvider pattern.
UNKNOWN_APP_PROVIDER = "unknown_provider"

_SRM_STATE_TO_APP_INSTANCE_STATUS: dict[str, AppInstanceStatus] = {
    "creating": AppInstanceStatus.INSTANTIATING,
    "active": AppInstanceStatus.READY,
@@ -358,7 +362,7 @@ def build_app_manifest(catalog: SRMCatalogPayload) -> AppManifest:
    return AppManifest(
        appId=app_id,
        name=spec.name,
        appProvider=spec.app_provider_id,
        appProvider=spec.descriptor.app_provider or UNKNOWN_APP_PROVIDER,
        version=spec.version,
        packageType=package_type,  # type: ignore[arg-type]
        operatingSystem=None,
@@ -689,6 +693,7 @@ def build_catalog_payload(translation: AppRegistrationTranslation) -> SRMCatalog
            app_provider_id=translation.app_provider_id,
            descriptor=SRMServiceSpecDescriptor(
                artifact_type=runtime_kind,
                app_provider=translation.app_provider or None,
            ),
        ),
        service_deployment_units=[deployment_unit],
+3 −0
Changes for src/open_exposure_gateway/domain/edge_application_management.py: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -179,6 +179,9 @@ class SRMComputeIntent(BaseModel):
class SRMServiceSpecDescriptor(BaseModel):
    artifact_type: str | None = None
    source_api: str = "edge-application-management"
    # The CAMARA `appProvider` name submitted on POST /apps. Kept here because the spec's
    # app_provider_id is the caller's identity (token `sub`), not this display name.
    app_provider: str | None = None


class SRMServiceSpecEntry(BaseModel):
+37 −2
Changes for tests/unit/test_eam_mapper.py: 37 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ from open_exposure_gateway.api.camara.edge_application_management.v0_1_0_alpha_1
    VmResources,
)
from open_exposure_gateway.application.mappers.edge_application_mapper import (
    UNKNOWN_APP_PROVIDER,
    build_app_deployment_info,
    build_app_deployment_translation,
    build_app_instance_info,
@@ -66,6 +67,8 @@ INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc")
OP_ID = UUID("dddddddd-dddd-dddd-dddd-dddddddddddd")
APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff")
DEPLOYMENT_ID = UUID("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee")
# The caller's Keycloak `sub`: what OEG stores as the spec's app_provider_id.
CALLER_SUB = "393d5cd6-0a8a-47cd-8c13-33eaa04201d1"


def _make_srm_catalog(
@@ -76,6 +79,7 @@ def _make_srm_catalog(
    memory_mb: int = 4096,
    interfaces: list[SRMNetworkInterface] | None = None,
    standalone: bool = False,
    app_provider: str | None = "VideoAppsCo",
) -> SRMCatalogPayload:
    return SRMCatalogPayload(
        service_specification=SRMServiceSpecEntry(
@@ -83,8 +87,10 @@ def _make_srm_catalog(
            ref=str(APP_ID),
            name="myvideoapp",
            version="1.0.0",
            app_provider_id="VideoAppsCo",
            descriptor=SRMServiceSpecDescriptor(artifact_type=runtime_kind),
            app_provider_id=CALLER_SUB,
            descriptor=SRMServiceSpecDescriptor(
                artifact_type=runtime_kind, app_provider=app_provider
            ),
        ),
        service_deployment_units=[
            SRMDeploymentUnit(
@@ -242,6 +248,16 @@ class TestBuildAppManifest:
        assert result.appProvider == "VideoAppsCo"
        assert result.packageType == "HELM"

    def test_app_provider_is_the_submitted_name_not_the_caller_id(self) -> None:
        # the caller's `sub` is a UUID, which CAMARA's AppProvider pattern rejects
        result = build_app_manifest(_make_srm_catalog())
        assert result.appProvider == "VideoAppsCo"
        assert result.appProvider != CALLER_SUB

    def test_app_provider_falls_back_when_spec_predates_the_stored_name(self) -> None:
        result = build_app_manifest(_make_srm_catalog(app_provider=None))
        assert result.appProvider == UNKNOWN_APP_PROVIDER

    def test_helm_produces_kubernetes_resources(self) -> None:
        catalog = _make_srm_catalog(cpu_millicores=2000, memory_mb=4096)
        result = build_app_manifest(catalog)
@@ -652,6 +668,25 @@ class TestBuildAppRegistrationTranslation:


class TestBuildCatalogPayload:
    def test_submitted_app_provider_stored_in_descriptor(self) -> None:
        manifest = _make_helm_manifest()
        translation = build_app_registration_translation(
            manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB
        )
        spec = build_catalog_payload(translation).service_specification
        assert spec.descriptor.app_provider == manifest.appProvider
        assert spec.app_provider_id == CALLER_SUB

    def test_app_provider_round_trips_through_catalog(self) -> None:
        manifest = _make_helm_manifest()
        translation = build_app_registration_translation(
            manifest, APP_ID, APP_REGISTRATION_ID, "t", CALLER_SUB
        )
        assert (
            build_app_manifest(build_catalog_payload(translation)).appProvider
            == manifest.appProvider
        )

    def test_runtime_kind_from_package_type(self) -> None:
        manifest = _make_helm_manifest()
        translation = build_app_registration_translation(