{
  "schema_version": 1,
  "ansible_source": "348a2d7124645431ff8bc546c8eb5339f4f0f6e7",
  "pipeline_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/pipelines/29267",
  "same_candidate": true,
  "selected_acceptance_passed": true,
  "problems": [],
  "features": [
    {
      "feature": "auth",
      "behavior": "Authentication and API authorization",
      "status": "passed",
      "scope": "One operator; issuer, missing/invalid token and App Provider role checks.",
      "tests": [
        "test_fm_internal_api_is_not_public",
        "test_keycloak_issuer_is_the_public_url[federation]",
        "test_keycloak_issuer_is_the_public_url[oop]",
        "test_oeg_keeps_app_apis_to_app_providers",
        "test_oeg_keeps_federation_to_operators",
        "test_oeg_refuses_calls_without_a_valid_token"
      ],
      "observed_tests": 6,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "device-ti",
      "behavior": "Device Traffic Influence uses the deployed application endpoint",
      "status": "passed",
      "scope": "One device and observed application host IPv4; provider subscription lifecycle. No port/protocol filters, actual packet steering or automatic notification claim.",
      "tests": [
        "test_device_ti_uses_the_deployed_application_endpoint"
      ],
      "observed_tests": 1,
      "variant": "network",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263650",
      "transaction_passed": true
    },
    {
      "feature": "endpoints",
      "behavior": "OEG returns the observed application endpoint",
      "status": "passed",
      "scope": "One observed external HTTP NodePort; no Ingress, LoadBalancer or multi-interface claim.",
      "tests": [
        "test_progressive_oeg_returns_the_observed_endpoint"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "failures",
      "behavior": "Invalid and conflicting public requests are rejected",
      "status": "passed",
      "scope": "Missing name (400), unsupported QCOW2 package (501), duplicate onboarding (409), unknown app (400) and instance (404); owned catalogue cleanup verified.",
      "tests": [
        "test_duplicate_onboarding_preserves_the_registered_application",
        "test_invalid_application_is_not_registered[missing-name]",
        "test_invalid_application_is_not_registered[unsupported-package]",
        "test_unknown_application_cannot_be_instantiated",
        "test_unknown_instance_cannot_be_terminated"
      ],
      "observed_tests": 5,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "federation",
      "behavior": "federation",
      "status": "not_run",
      "scope": "Federation requires multiple operator platforms and agreed partners.",
      "tests": [],
      "observed_tests": 0,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "health",
      "behavior": "OEG and FM HTTP health",
      "status": "passed",
      "scope": "Public OEG/FM HTTP health; other API behavior has separate checks.",
      "tests": [
        "test_oeg_and_fm_answer"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "helm",
      "behavior": "HELM application lifecycle",
      "status": "passed",
      "scope": "One HTTP-served Helm archive, NodePort and termination; no CAMARA compute-to-values mapping or arbitrary chart support claim.",
      "tests": [
        "test_progressive_endpoint_reaches_the_deployed_application",
        "test_progressive_oeg_request_creates_a_ready_workload",
        "test_progressive_oeg_returns_the_application_instance",
        "test_progressive_oeg_returns_the_observed_endpoint",
        "test_progressive_oeg_termination_removes_the_workload"
      ],
      "observed_tests": 5,
      "variant": "helm",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263649",
      "transaction_passed": true
    },
    {
      "feature": "instance",
      "behavior": "OEG returns the deployed application identity",
      "status": "passed",
      "scope": "Expected app/zone identity and ready state for the selected instance.",
      "tests": [
        "test_progressive_oeg_returns_the_application_instance"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "location",
      "behavior": "Known-device location and missing-device rejection",
      "status": "passed",
      "scope": "One simulated IPv4 device, geographic area/time, missing-device rejection; no real location accuracy or handset compatibility claim.",
      "tests": [
        "test_known_device_returns_geographic_location",
        "test_location_without_device_is_rejected"
      ],
      "observed_tests": 2,
      "variant": "network",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263650",
      "transaction_passed": true
    },
    {
      "feature": "multi-cluster",
      "behavior": "multi-cluster",
      "status": "not_run",
      "scope": "Control-path isolation needs separate two-cluster execution evidence.",
      "tests": [],
      "observed_tests": 0,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "onboarding",
      "behavior": "Cloud application catalogue onboarding",
      "status": "passed",
      "scope": "Supported application manifest read/list/delete; no complete optional-field round trip.",
      "tests": [
        "test_app_provider_lists_its_apps",
        "test_app_provider_registers_reads_and_deletes_an_app"
      ],
      "observed_tests": 2,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "qod",
      "behavior": "OEG QoD profiles, provider readback, refusals and cleanup",
      "status": "passed",
      "scope": "EURECOM/CoreSim: four configured profiles, exact IPv4 flow and notification URL, SDK/backend refusal and public/provider cleanup. No real QoS enforcement or callback delivery claim.",
      "tests": [
        "test_qod_backend_refusal_retains_diagnostics",
        "test_qod_profile_lifecycle[qos-e]",
        "test_qod_profile_lifecycle[qos2]",
        "test_qod_profile_lifecycle[qos3]",
        "test_qod_profile_lifecycle[qos4]",
        "test_qod_unsupported_profile_is_rejected"
      ],
      "observed_tests": 6,
      "variant": "network",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263650",
      "transaction_passed": true
    },
    {
      "feature": "reachable",
      "behavior": "Returned endpoint reaches the deployed application",
      "status": "passed",
      "scope": "Controller-to-application HTTP with Pod identity; no WAN or data-plane policy claim.",
      "tests": [
        "test_progressive_endpoint_reaches_the_deployed_application"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "resources",
      "behavior": "Requested CPU and memory applied to Deployment and Pod",
      "status": "passed",
      "scope": "Container CPU and decimal-MB memory requests; no limits, storage or accelerators.",
      "tests": [
        "test_progressive_workload_applies_requested_resources"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "terminated",
      "behavior": "OEG termination removes the owned workload",
      "status": "passed",
      "scope": "Public instance and owned Deployment/Pod/Service removal.",
      "tests": [
        "test_progressive_oeg_termination_removes_the_workload"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "updates",
      "behavior": "updates",
      "status": "not_run",
      "scope": "Scaling, updates and recovery require their own lifecycle assertions.",
      "tests": [],
      "observed_tests": 0,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "workload",
      "behavior": "OEG request creates a ready Kubernetes workload",
      "status": "passed",
      "scope": "One application, one zone and one ready Deployment/Pod/NodePort Service.",
      "tests": [
        "test_progressive_oeg_request_creates_a_ready_workload"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    },
    {
      "feature": "zones",
      "behavior": "Configured workload zones exposed by OEG",
      "status": "passed",
      "scope": "Configured lab workload zones and public identities; no dynamic backend health claim.",
      "tests": [
        "test_cloud_zones_match_configured_workload_targets"
      ],
      "observed_tests": 1,
      "variant": "container",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "transaction_passed": true
    }
  ],
  "variants": {
    "container": {
      "checkpoint": "terminated",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263648",
      "candidate_run_passed": true,
      "lab_cleanup": "passed",
      "wrapper_cleanup_passed": true,
      "checks": [
        {
          "test": "test_oeg_and_fm_answer",
          "status": "passed",
          "seconds": "0.006",
          "description": "Call public OEG and FM health endpoints and require HTTP 200 from both deployed services.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 17
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[oop]",
          "status": "passed",
          "seconds": "0.005",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[federation]",
          "status": "passed",
          "seconds": "0.004",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_oeg_refuses_calls_without_a_valid_token",
          "status": "passed",
          "seconds": "0.013",
          "description": "Require HTTP 401 for missing or invalid bearer tokens on application and federation routes.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 14
        },
        {
          "test": "test_oeg_keeps_app_apis_to_app_providers",
          "status": "passed",
          "seconds": "1.737",
          "description": "Reject the operator role on application routes and let an App Provider reach the application lookup.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 37
        },
        {
          "test": "test_oeg_keeps_federation_to_operators",
          "status": "passed",
          "seconds": "0.003",
          "description": "Require HTTP 403 when an App Provider calls an operator-only federation route.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 30
        },
        {
          "test": "test_fm_internal_api_is_not_public",
          "status": "passed",
          "seconds": "0.002",
          "description": "FM serves /internal/* only on its cluster-internal port, never on the EWBI one.",
          "file": "ansible/tests/r2_e2e/test_exposure.py",
          "line": 6
        },
        {
          "test": "test_app_provider_registers_reads_and_deletes_an_app",
          "status": "passed",
          "seconds": "0.183",
          "description": "Onboard an application through OEG, read its stored manifest and list entry, then verify catalogue removal.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 63
        },
        {
          "test": "test_app_provider_lists_its_apps",
          "status": "passed",
          "seconds": "0.072",
          "description": "Verify the application registered by this test client appears in its catalogue list.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 81
        },
        {
          "test": "test_invalid_application_is_not_registered[missing-name]",
          "status": "passed",
          "seconds": "0.037",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_invalid_application_is_not_registered[unsupported-package]",
          "status": "passed",
          "seconds": "0.039",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_duplicate_onboarding_preserves_the_registered_application",
          "status": "passed",
          "seconds": "0.085",
          "description": "Require HTTP 409 for duplicate onboarding and prove the original application was preserved.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 41
        },
        {
          "test": "test_unknown_application_cannot_be_instantiated",
          "status": "passed",
          "seconds": "0.009",
          "description": "Reject instantiation of an unknown application and prove no instance was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 55
        },
        {
          "test": "test_unknown_instance_cannot_be_terminated",
          "status": "passed",
          "seconds": "0.134",
          "description": "Require HTTP 404 for deletion of a nonexistent application instance.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 69
        },
        {
          "test": "test_cloud_zones_match_configured_workload_targets",
          "status": "passed",
          "seconds": "0.031",
          "description": "Compare public zone names and unique identities with the workload zones configured in this lab.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 96
        },
        {
          "test": "test_progressive_oeg_request_creates_a_ready_workload",
          "status": "passed",
          "seconds": "5.697",
          "description": "Instantiate through OEG and independently require the owned Kubernetes Deployment, ready Pod and NodePort Service.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 114
        },
        {
          "test": "test_progressive_workload_applies_requested_resources",
          "status": "passed",
          "seconds": "0.438",
          "description": "Compare requested CPU and decimal-MB memory with the actual Kubernetes Deployment and Pod resource requests.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 120
        },
        {
          "test": "test_progressive_oeg_returns_the_application_instance",
          "status": "passed",
          "seconds": "0.037",
          "description": "Poll the public instance until ready and verify its application and zone identities.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 128
        },
        {
          "test": "test_progressive_oeg_returns_the_observed_endpoint",
          "status": "passed",
          "seconds": "0.000",
          "description": "Compare the public application endpoint with the actual owned Kubernetes Service and cluster node.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 134
        },
        {
          "test": "test_progressive_endpoint_reaches_the_deployed_application",
          "status": "passed",
          "seconds": "0.001",
          "description": "Call the returned HTTP endpoint and verify the response identifies the deployed application Pod.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 140
        },
        {
          "test": "test_progressive_oeg_termination_removes_the_workload",
          "status": "passed",
          "seconds": "4.940",
          "description": "Terminate through OEG and verify the public instance and owned Deployment, Pod and Service disappear.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 148
        }
      ],
      "step_results": [
        {
          "name": "Validate lab inputs and ownership",
          "status": "passed",
          "seconds": 3.020355
        },
        {
          "name": "Kubernetes cluster ready",
          "status": "passed",
          "seconds": 10.674293
        },
        {
          "name": "Candidate images loaded",
          "status": "passed",
          "seconds": 27.829702
        },
        {
          "name": "OpenOP deployed and ready",
          "status": "passed",
          "seconds": 68.394547
        },
        {
          "name": "Running component images verified",
          "status": "passed",
          "seconds": 0.672272
        },
        {
          "name": "OEG and FM HTTP health",
          "status": "passed",
          "seconds": 0.006
        },
        {
          "name": "Authentication and API authorization",
          "status": "passed",
          "seconds": 1.764
        },
        {
          "name": "Cloud application catalogue onboarding",
          "status": "passed",
          "seconds": 0.255
        },
        {
          "name": "Invalid and conflicting public requests are rejected",
          "status": "passed",
          "seconds": 0.304
        },
        {
          "name": "Configured workload zones exposed by OEG",
          "status": "passed",
          "seconds": 0.031
        },
        {
          "name": "OEG request creates a ready Kubernetes workload",
          "status": "passed",
          "seconds": 5.697
        },
        {
          "name": "Requested CPU and memory applied to Deployment and Pod",
          "status": "passed",
          "seconds": 0.438
        },
        {
          "name": "OEG returns the deployed application identity",
          "status": "passed",
          "seconds": 0.037
        },
        {
          "name": "OEG returns the observed application endpoint",
          "status": "passed",
          "seconds": 0.0
        },
        {
          "name": "Returned endpoint reaches the deployed application",
          "status": "passed",
          "seconds": 0.001
        },
        {
          "name": "OEG termination removes the owned workload",
          "status": "passed",
          "seconds": 4.94
        },
        {
          "name": "Remove owned cluster and imported images",
          "status": "passed",
          "seconds": 2.490875
        }
      ]
    },
    "helm": {
      "checkpoint": "helm-terminated",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263649",
      "candidate_run_passed": true,
      "lab_cleanup": "passed",
      "wrapper_cleanup_passed": true,
      "checks": [
        {
          "test": "test_oeg_and_fm_answer",
          "status": "passed",
          "seconds": "0.007",
          "description": "Call public OEG and FM health endpoints and require HTTP 200 from both deployed services.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 17
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[oop]",
          "status": "passed",
          "seconds": "0.005",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[federation]",
          "status": "passed",
          "seconds": "0.003",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_oeg_refuses_calls_without_a_valid_token",
          "status": "passed",
          "seconds": "0.015",
          "description": "Require HTTP 401 for missing or invalid bearer tokens on application and federation routes.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 14
        },
        {
          "test": "test_oeg_keeps_app_apis_to_app_providers",
          "status": "passed",
          "seconds": "1.605",
          "description": "Reject the operator role on application routes and let an App Provider reach the application lookup.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 37
        },
        {
          "test": "test_oeg_keeps_federation_to_operators",
          "status": "passed",
          "seconds": "0.002",
          "description": "Require HTTP 403 when an App Provider calls an operator-only federation route.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 30
        },
        {
          "test": "test_fm_internal_api_is_not_public",
          "status": "passed",
          "seconds": "0.002",
          "description": "FM serves /internal/* only on its cluster-internal port, never on the EWBI one.",
          "file": "ansible/tests/r2_e2e/test_exposure.py",
          "line": 6
        },
        {
          "test": "test_app_provider_registers_reads_and_deletes_an_app",
          "status": "passed",
          "seconds": "0.184",
          "description": "Onboard an application through OEG, read its stored manifest and list entry, then verify catalogue removal.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 63
        },
        {
          "test": "test_app_provider_lists_its_apps",
          "status": "passed",
          "seconds": "0.080",
          "description": "Verify the application registered by this test client appears in its catalogue list.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 81
        },
        {
          "test": "test_invalid_application_is_not_registered[missing-name]",
          "status": "passed",
          "seconds": "0.040",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_invalid_application_is_not_registered[unsupported-package]",
          "status": "passed",
          "seconds": "0.038",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_duplicate_onboarding_preserves_the_registered_application",
          "status": "passed",
          "seconds": "0.076",
          "description": "Require HTTP 409 for duplicate onboarding and prove the original application was preserved.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 41
        },
        {
          "test": "test_unknown_application_cannot_be_instantiated",
          "status": "passed",
          "seconds": "0.009",
          "description": "Reject instantiation of an unknown application and prove no instance was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 55
        },
        {
          "test": "test_unknown_instance_cannot_be_terminated",
          "status": "passed",
          "seconds": "0.131",
          "description": "Require HTTP 404 for deletion of a nonexistent application instance.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 69
        },
        {
          "test": "test_cloud_zones_match_configured_workload_targets",
          "status": "passed",
          "seconds": "0.030",
          "description": "Compare public zone names and unique identities with the workload zones configured in this lab.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 96
        },
        {
          "test": "test_progressive_oeg_request_creates_a_ready_workload",
          "status": "passed",
          "seconds": "5.604",
          "description": "Instantiate through OEG and independently require the owned Kubernetes Deployment, ready Pod and NodePort Service.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 114
        },
        {
          "test": "test_progressive_oeg_returns_the_application_instance",
          "status": "passed",
          "seconds": "2.059",
          "description": "Poll the public instance until ready and verify its application and zone identities.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 128
        },
        {
          "test": "test_progressive_oeg_returns_the_observed_endpoint",
          "status": "passed",
          "seconds": "0.000",
          "description": "Compare the public application endpoint with the actual owned Kubernetes Service and cluster node.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 134
        },
        {
          "test": "test_progressive_endpoint_reaches_the_deployed_application",
          "status": "passed",
          "seconds": "0.002",
          "description": "Call the returned HTTP endpoint and verify the response identifies the deployed application Pod.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 140
        },
        {
          "test": "test_progressive_oeg_termination_removes_the_workload",
          "status": "passed",
          "seconds": "2.880",
          "description": "Terminate through OEG and verify the public instance and owned Deployment, Pod and Service disappear.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 148
        }
      ],
      "step_results": [
        {
          "name": "Validate lab inputs and ownership",
          "status": "passed",
          "seconds": 2.467347
        },
        {
          "name": "Kubernetes cluster ready",
          "status": "passed",
          "seconds": 10.422073
        },
        {
          "name": "Candidate images loaded",
          "status": "passed",
          "seconds": 28.804969
        },
        {
          "name": "OpenOP deployed and ready",
          "status": "passed",
          "seconds": 108.1994
        },
        {
          "name": "Running component images verified",
          "status": "passed",
          "seconds": 0.456098
        },
        {
          "name": "OEG and FM HTTP health",
          "status": "passed",
          "seconds": 0.007
        },
        {
          "name": "Authentication and API authorization",
          "status": "passed",
          "seconds": 1.632
        },
        {
          "name": "Cloud application catalogue onboarding",
          "status": "passed",
          "seconds": 0.264
        },
        {
          "name": "Invalid and conflicting public requests are rejected",
          "status": "passed",
          "seconds": 0.294
        },
        {
          "name": "Configured workload zones exposed by OEG",
          "status": "passed",
          "seconds": 0.03
        },
        {
          "name": "OEG request creates a ready Kubernetes workload",
          "status": "passed",
          "seconds": 5.604
        },
        {
          "name": "OEG returns the deployed application identity",
          "status": "passed",
          "seconds": 2.059
        },
        {
          "name": "OEG returns the observed application endpoint",
          "status": "passed",
          "seconds": 0.0
        },
        {
          "name": "Returned endpoint reaches the deployed application",
          "status": "passed",
          "seconds": 0.002
        },
        {
          "name": "OEG termination removes the owned workload",
          "status": "passed",
          "seconds": 2.88
        },
        {
          "name": "Remove owned cluster and imported images",
          "status": "passed",
          "seconds": 2.237311
        }
      ]
    },
    "network": {
      "checkpoint": "network",
      "job_url": "https://labs.etsi.org/rep/oop/deploy/ansible/-/jobs/263650",
      "candidate_run_passed": true,
      "lab_cleanup": "passed",
      "wrapper_cleanup_passed": true,
      "checks": [
        {
          "test": "test_oeg_and_fm_answer",
          "status": "passed",
          "seconds": "0.007",
          "description": "Call public OEG and FM health endpoints and require HTTP 200 from both deployed services.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 17
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[oop]",
          "status": "passed",
          "seconds": "0.005",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_keycloak_issuer_is_the_public_url[federation]",
          "status": "passed",
          "seconds": "0.003",
          "description": "Discover the configured realm through its public URL and verify the advertised issuer matches it.",
          "file": "ansible/tests/r2_e2e/test_platform.py",
          "line": 9
        },
        {
          "test": "test_oeg_refuses_calls_without_a_valid_token",
          "status": "passed",
          "seconds": "0.011",
          "description": "Require HTTP 401 for missing or invalid bearer tokens on application and federation routes.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 14
        },
        {
          "test": "test_oeg_keeps_app_apis_to_app_providers",
          "status": "passed",
          "seconds": "1.715",
          "description": "Reject the operator role on application routes and let an App Provider reach the application lookup.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 37
        },
        {
          "test": "test_oeg_keeps_federation_to_operators",
          "status": "passed",
          "seconds": "0.003",
          "description": "Require HTTP 403 when an App Provider calls an operator-only federation route.",
          "file": "ansible/tests/r2_e2e/test_auth.py",
          "line": 30
        },
        {
          "test": "test_fm_internal_api_is_not_public",
          "status": "passed",
          "seconds": "0.002",
          "description": "FM serves /internal/* only on its cluster-internal port, never on the EWBI one.",
          "file": "ansible/tests/r2_e2e/test_exposure.py",
          "line": 6
        },
        {
          "test": "test_app_provider_registers_reads_and_deletes_an_app",
          "status": "passed",
          "seconds": "0.177",
          "description": "Onboard an application through OEG, read its stored manifest and list entry, then verify catalogue removal.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 63
        },
        {
          "test": "test_app_provider_lists_its_apps",
          "status": "passed",
          "seconds": "0.071",
          "description": "Verify the application registered by this test client appears in its catalogue list.",
          "file": "ansible/tests/r2_e2e/test_apps.py",
          "line": 81
        },
        {
          "test": "test_invalid_application_is_not_registered[missing-name]",
          "status": "passed",
          "seconds": "0.037",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_invalid_application_is_not_registered[unsupported-package]",
          "status": "passed",
          "seconds": "0.036",
          "description": "Reject a missing application name or unsupported package and prove no catalogue record was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 19
        },
        {
          "test": "test_duplicate_onboarding_preserves_the_registered_application",
          "status": "passed",
          "seconds": "0.075",
          "description": "Require HTTP 409 for duplicate onboarding and prove the original application was preserved.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 41
        },
        {
          "test": "test_unknown_application_cannot_be_instantiated",
          "status": "passed",
          "seconds": "0.008",
          "description": "Reject instantiation of an unknown application and prove no instance was created.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 55
        },
        {
          "test": "test_unknown_instance_cannot_be_terminated",
          "status": "passed",
          "seconds": "0.127",
          "description": "Require HTTP 404 for deletion of a nonexistent application instance.",
          "file": "ansible/tests/r2_e2e/test_release_failures.py",
          "line": 69
        },
        {
          "test": "test_cloud_zones_match_configured_workload_targets",
          "status": "passed",
          "seconds": "0.030",
          "description": "Compare public zone names and unique identities with the workload zones configured in this lab.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 96
        },
        {
          "test": "test_progressive_oeg_request_creates_a_ready_workload",
          "status": "passed",
          "seconds": "5.870",
          "description": "Instantiate through OEG and independently require the owned Kubernetes Deployment, ready Pod and NodePort Service.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 114
        },
        {
          "test": "test_progressive_workload_applies_requested_resources",
          "status": "passed",
          "seconds": "0.417",
          "description": "Compare requested CPU and decimal-MB memory with the actual Kubernetes Deployment and Pod resource requests.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 120
        },
        {
          "test": "test_progressive_oeg_returns_the_application_instance",
          "status": "passed",
          "seconds": "0.043",
          "description": "Poll the public instance until ready and verify its application and zone identities.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 128
        },
        {
          "test": "test_progressive_oeg_returns_the_observed_endpoint",
          "status": "passed",
          "seconds": "0.000",
          "description": "Compare the public application endpoint with the actual owned Kubernetes Service and cluster node.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 134
        },
        {
          "test": "test_progressive_endpoint_reaches_the_deployed_application",
          "status": "passed",
          "seconds": "0.002",
          "description": "Call the returned HTTP endpoint and verify the response identifies the deployed application Pod.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 140
        },
        {
          "test": "test_qod_profile_lifecycle[qos-e]",
          "status": "passed",
          "seconds": "4.204",
          "description": "Create and read QoD through OEG, inspect the real NEF resource and flow, then verify public and provider deletion.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 218
        },
        {
          "test": "test_qod_profile_lifecycle[qos2]",
          "status": "passed",
          "seconds": "4.012",
          "description": "Create and read QoD through OEG, inspect the real NEF resource and flow, then verify public and provider deletion.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 218
        },
        {
          "test": "test_qod_profile_lifecycle[qos3]",
          "status": "passed",
          "seconds": "4.001",
          "description": "Create and read QoD through OEG, inspect the real NEF resource and flow, then verify public and provider deletion.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 218
        },
        {
          "test": "test_qod_profile_lifecycle[qos4]",
          "status": "passed",
          "seconds": "4.001",
          "description": "Create and read QoD through OEG, inspect the real NEF resource and flow, then verify public and provider deletion.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 218
        },
        {
          "test": "test_qod_unsupported_profile_is_rejected",
          "status": "passed",
          "seconds": "4.054",
          "description": "Request a disallowed QoD profile, wait for UNAVAILABLE and verify no provider subscription was created.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 224
        },
        {
          "test": "test_qod_backend_refusal_retains_diagnostics",
          "status": "passed",
          "seconds": "4.063",
          "description": "Request a profile refused by the NEF, wait for UNAVAILABLE and check safe HTTP 400 diagnostics and cleanup.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 230
        },
        {
          "test": "test_known_device_returns_geographic_location",
          "status": "passed",
          "seconds": "1.833",
          "description": "Retrieve the simulated device location through OEG and verify geographic coordinates and freshness.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 236
        },
        {
          "test": "test_location_without_device_is_rejected",
          "status": "passed",
          "seconds": "1.721",
          "description": "Require the public missing-identifier error when location retrieval has no device.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 258
        },
        {
          "test": "test_device_ti_uses_the_deployed_application_endpoint",
          "status": "passed",
          "seconds": "4.117",
          "description": "Activate device TI through OEG, verify real device/application IPs and notification URL in the NEF, then verify deletion.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 266
        },
        {
          "test": "test_progressive_oeg_termination_removes_the_workload",
          "status": "passed",
          "seconds": "2.741",
          "description": "Terminate through OEG and verify the public instance and owned Deployment, Pod and Service disappear.",
          "file": "ansible/tests/r2_e2e/test_deploy_to_ti.py",
          "line": 148
        }
      ],
      "step_results": [
        {
          "name": "Validate lab inputs and ownership",
          "status": "passed",
          "seconds": 3.019902
        },
        {
          "name": "Kubernetes cluster ready",
          "status": "passed",
          "seconds": 10.427645
        },
        {
          "name": "Candidate images loaded",
          "status": "passed",
          "seconds": 26.764168
        },
        {
          "name": "Start EURECOM NEF/CoreSim and prepare the simulated device",
          "status": "passed",
          "seconds": 59.559914
        },
        {
          "name": "OpenOP deployed and ready",
          "status": "passed",
          "seconds": 109.504018
        },
        {
          "name": "Running component images verified",
          "status": "passed",
          "seconds": 0.746931
        },
        {
          "name": "OEG and FM HTTP health",
          "status": "passed",
          "seconds": 0.007
        },
        {
          "name": "Authentication and API authorization",
          "status": "passed",
          "seconds": 1.739
        },
        {
          "name": "Cloud application catalogue onboarding",
          "status": "passed",
          "seconds": 0.248
        },
        {
          "name": "Invalid and conflicting public requests are rejected",
          "status": "passed",
          "seconds": 0.283
        },
        {
          "name": "Configured workload zones exposed by OEG",
          "status": "passed",
          "seconds": 0.03
        },
        {
          "name": "OEG request creates a ready Kubernetes workload",
          "status": "passed",
          "seconds": 5.87
        },
        {
          "name": "Requested CPU and memory applied to Deployment and Pod",
          "status": "passed",
          "seconds": 0.417
        },
        {
          "name": "OEG returns the deployed application identity",
          "status": "passed",
          "seconds": 0.043
        },
        {
          "name": "OEG returns the observed application endpoint",
          "status": "passed",
          "seconds": 0.0
        },
        {
          "name": "Returned endpoint reaches the deployed application",
          "status": "passed",
          "seconds": 0.002
        },
        {
          "name": "OEG QoD profiles, provider readback, refusals and cleanup",
          "status": "passed",
          "seconds": 24.335
        },
        {
          "name": "Known-device location and missing-device rejection",
          "status": "passed",
          "seconds": 3.5540000000000003
        },
        {
          "name": "Device Traffic Influence uses the deployed application endpoint",
          "status": "passed",
          "seconds": 4.117
        },
        {
          "name": "OEG termination removes the owned workload",
          "status": "passed",
          "seconds": 2.741
        },
        {
          "name": "Remove owned cluster and imported images",
          "status": "passed",
          "seconds": 2.604627
        }
      ]
    }
  },
  "artifact_selection": {
    "ref": "main",
    "source_heads": {
      "oeg": "c93984d49b928210c876b23d18a6a6d4d883840b",
      "fm": "67b8e299de5b863071580ac6589f491ec56579e2",
      "srm": "0f525c977b0870b0c33f8f11bc5b75d264bb60ca",
      "sdk": "41db8de823167088063cc562ae976449fa560688",
      "helm": "e10361c16f13e13dfbdeb45d61f6ee5abfafd33d"
    },
    "components": {
      "oeg": {
        "source_sha": "c93984d49b928210c876b23d18a6a6d4d883840b",
        "pipeline_id": 29253,
        "pipeline_url": "https://labs.etsi.org/rep/oop/code/open-exposure-gateway/-/pipelines/29253",
        "build_job_id": 263562,
        "image": "labs.etsi.org:5050/oop/code/open-exposure-gateway:ci-main-c93984d4@sha256:bf7014787282aefb27e66c6bc1a0101a819e623743c492e91a20b9969b27fbf7"
      },
      "fm": {
        "source_sha": "67b8e299de5b863071580ac6589f491ec56579e2",
        "pipeline_id": 29241,
        "pipeline_url": "https://labs.etsi.org/rep/oop/code/federation-manager/-/pipelines/29241",
        "build_job_id": 263203,
        "image": "labs.etsi.org:5050/oop/code/federation-manager:ci-main-67b8e299@sha256:8d2bbf0d97623bcef91b488f69d3f9b6ede44509bccf4d3f138069c5f8660e1a"
      },
      "srm": {
        "source_sha": "0f525c977b0870b0c33f8f11bc5b75d264bb60ca",
        "pipeline_id": 29259,
        "pipeline_url": "https://labs.etsi.org/rep/oop/code/service-resource-manager/-/pipelines/29259",
        "build_job_id": 263596,
        "image": "labs.etsi.org:5050/oop/code/service-resource-manager:ci-main-0f525c97@sha256:cc881d783c71605ff18707c471b97705d526355c4dffaa86d562eb95722ab8f4"
      },
      "sdk": {
        "source_sha": "41db8de823167088063cc562ae976449fa560688",
        "pipeline_id": 29232,
        "pipeline_url": "https://labs.etsi.org/rep/oop/code/tf-sdk/-/pipelines/29232",
        "build_job_id": 263072,
        "wheel_sha256": "6431c6da12b664e69a7a27ea3b35c84520c17ec42acba7caa8fdde5f6899da55",
        "consumer": {
          "id": 29235,
          "iid": 280,
          "project_id": 377,
          "sha": "e43aa6ef4dce8a7281baf46ec9c635b87dfd1f84",
          "ref": "test/tfsdk-consumer-qualification",
          "status": "success",
          "source": "pipeline",
          "created_at": "2026-10-23T14:02:25.968Z",
          "updated_at": "2026-10-23T14:05:58.948Z",
          "web_url": "https://labs.etsi.org/rep/oop/code/service-resource-manager/-/pipelines/29235"
        }
      }
    },
    "sdk": {
      "installed_expected": {
        "version": "2.0.0",
        "files": 127,
        "sha256": "14b39b677963f8fc335f2e3d690017507afb5bea951392b86b9785586ab7b8c1"
      },
      "locked_source": "41db8de823167088063cc562ae976449fa560688",
      "latest_build": {
        "version": "2.0.0",
        "files": 127,
        "sha256": "14b39b677963f8fc335f2e3d690017507afb5bea951392b86b9785586ab7b8c1"
      },
      "runtime_matches_current_source": true,
      "version_matches_latest_build": true
    },
    "resolved_profile": {
      "candidate_ref": "main",
      "chart_revision": "e10361c16f13e13dfbdeb45d61f6ee5abfafd33d",
      "images": {
        "oeg": "labs.etsi.org:5050/oop/code/open-exposure-gateway:ci-main-c93984d4@sha256:bf7014787282aefb27e66c6bc1a0101a819e623743c492e91a20b9969b27fbf7",
        "fm": "labs.etsi.org:5050/oop/code/federation-manager:ci-main-67b8e299@sha256:8d2bbf0d97623bcef91b488f69d3f9b6ede44509bccf4d3f138069c5f8660e1a",
        "srm": "labs.etsi.org:5050/oop/code/service-resource-manager:ci-main-0f525c97@sha256:cc881d783c71605ff18707c471b97705d526355c4dffaa86d562eb95722ab8f4"
      },
      "local_images": [],
      "checkpoint": "terminated",
      "acceptance": {
        "connection_mode": "in_cluster",
        "workload_namespace": "oop-e2e-workloads",
        "application_image": "traefik/whoami@sha256:200689790a0a0ea48ca45992e0450bc26ccab5307375b41c84dfc4f2475937ab",
        "http_response_contains": "Hostname:",
        "timeout_seconds": 180,
        "resource_requests": {
          "cpu": 2,
          "memory_mb": 257
        },
        "sdk": {
          "revision": "41db8de823167088063cc562ae976449fa560688",
          "version": "2.0.0",
          "sha256": "14b39b677963f8fc335f2e3d690017507afb5bea951392b86b9785586ab7b8c1"
        }
      }
    }
  },
  "compatibility": [
    {
      "provider": {
        "provider": "EURECOM open-exposure NEF + CoreSim",
        "cleanup": "passed",
        "images": {
          "openexposure/core-simulator:develop": "openexposure/core-simulator@sha256:fda2456eb123e068743841d88d4404efb5e2f08605f51c684a336f8bcd2c906b",
          "openexposure/as-session-with-qos:develop": "openexposure/as-session-with-qos@sha256:4751cac7d65f7957a4126b392fb8dc48dd7840f19757ee072311d89b52438c2d",
          "openexposure/traffic-influence:develop": "openexposure/traffic-influence@sha256:adef8616f3c4ab33a4ff1037d7701c7d4b24c267d3cd477e3f84770d2c82f21a",
          "openexposure/monitoring-event:develop": "openexposure/monitoring-event@sha256:a2e04f326a9e022ce414730469eac95d4d4c46456ded1923776d8e4c287bbab6",
          "openexposure/core-network-service:develop": "openexposure/core-network-service@sha256:8f302cadfcd090431ac796f2e3da2efbf610b9909c9c23d6e71e542e71c14ab1",
          "openexposure/ue-identity-service:develop": "openexposure/ue-identity-service@sha256:957a3cf569222f5f3754adc2334eac71b99a3aced38196fcd367579dacb3cad7",
          "openexposure/ue-profile-service:develop": "openexposure/ue-profile-service@sha256:1f08531fc7fbff11f25bd98f0ebb7e50d944e31f2c43093195f70b618be1ce9a",
          "openexposure/ue-address:develop": "openexposure/ue-address@sha256:6d0131500bf642ea02c8805a414410caa6b0080d7a64e2d0ecdb436473f4e6fe",
          "openexposure/ue-id:develop": "openexposure/ue-id@sha256:5e0e55589ff05155f7c7f8d62cc7af390da6ff79bb5e4f8be5b5d6878296b2cb",
          "redis/redis-stack-server:latest": "redis/redis-stack-server@sha256:798ab84d9f266936b034ab11c4d04a2b8e4b441884c5aa7d17ac951eefdf742a",
          "nginx:latest": "nginx@sha256:47928bf67eb62a1863cb08d9ecb52d3e704304ba614eaee17884204677702951"
        },
        "deployment_revision": "888673aa2dd32a8e3bf1357f424ebc0ca7cbfb5e",
        "source_revision_limit": "Published image digests are verified; these images expose no source revision labels. Guide/source commits are not asserted as image provenance.",
        "deployment_archive_sha256": "3068906fa57d58a5077dcbd1a0d7a302ba15c44983c9255a82ff24931fad5763",
        "instrumentation": "Ingress records method/path/status/Location only; no headers or payloads",
        "qod_collection_read": "unsupported-http501",
        "ti_initial_collection": "AF-not-created-http404",
        "startup": "passed",
        "device_ipv4": "12.1.0.1",
        "base_url": "http://172.19.0.14"
      },
      "selected_transaction_passed": true,
      "features": {
        "qod": "passed",
        "location": "passed",
        "device-ti": "passed"
      }
    }
  ]
}
