diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index ba40eec..9c2fc2f 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -10,7 +10,8 @@ jobs: with: channel: 1.28-strict/stable modules: '["test_charm.py"]' - juju-channel: 3.1/stable + juju-channel: 3.4/stable self-hosted-runner: true self-hosted-runner-label: "xlarge" microk8s-addons: "dns ingress rbac storage metallb:10.15.119.2-10.15.119.4 registry" + trivy-severity-config: CRITICAL diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 0000000..0b2f2f3 --- /dev/null +++ b/.trivyignore @@ -0,0 +1,6 @@ +# stdlib CVEs +CVE-2024-24790 +CVE-2023-24538 +CVE-2023-24540 + +CVE-2024-21534 diff --git a/airbyte_ui_rock/.trivyignore b/airbyte_ui_rock/.trivyignore new file mode 100644 index 0000000..dadc8e9 --- /dev/null +++ b/airbyte_ui_rock/.trivyignore @@ -0,0 +1,4 @@ +# Ignore vulnerabilities on stdlib +CVE-2024-24790 +CVE-2023-24538 +CVE-2023-24540 diff --git a/airbyte_ui_rock/patches/vite-config-http.patch b/airbyte_ui_rock/patches/vite-config-http.patch new file mode 100644 index 0000000..82e97ed --- /dev/null +++ b/airbyte_ui_rock/patches/vite-config-http.patch @@ -0,0 +1,15 @@ +# Copyright 2024 Canonical Ltd. +# See LICENSE file for licensing details. + +diff --git a/airbyte-webapp/vite.config.mts b/airbyte-webapp/vite.config.mts +index 4cf29fa0de..6359ab2a55 100644 +--- a/airbyte-webapp/vite.config.mts ++++ b/airbyte-webapp/vite.config.mts +@@ -118,6 +118,7 @@ export default defineConfig(() => { + }, + }, + server: { ++ https: false, + host: true, + port: Number(process.env.PORT) || 3000, + strictPort: true, diff --git a/airbyte_ui_rock/rockcraft.yaml b/airbyte_ui_rock/rockcraft.yaml new file mode 100644 index 0000000..e4d0078 --- /dev/null +++ b/airbyte_ui_rock/rockcraft.yaml @@ -0,0 +1,75 @@ +# Copyright 2024 Canonical Ltd. +# See LICENSE file for licensing details. + +name: airbyte-ui +summary: Airbyte UI rock +description: Airbyte UI OCI image for the Airbyte UI charm +version: "1.0" +base: ubuntu@22.04 +license: Apache-2.0 +platforms: + amd64: + +services: + airbyte-webapp: + override: replace + summary: "airbyte-webapp service" + startup: disabled + command: "/usr/bin/pnpm -C airbyte-webapp start" + environment: + PORT: "8080" + +parts: + patches: + plugin: dump + source: ./patches + organize: + vite-config-http.patch: patches/vite-config-http.patch + stage: + - patches/vite-config-http.patch + prime: + - "-*" + + airbyte-webapp: + after: [patches] + plugin: dump + source: https://github.com/airbytehq/airbyte-platform.git # yamllint disable-line + source-type: git + source-tag: v0.63.8 + build-packages: + - jq + - curl + - nodejs + - npm + - coreutils + - bash + override-build: | + git apply ${CRAFT_STAGE}/patches/*.patch + + curl https://raw.githubusercontent.com/creationix/nvm/v0.40.1/install.sh | bash + source ~/.bashrc + cd airbyte-webapp + nvm install 20.11.0 + nvm alias default 20.11.0 + npm install -g pnpm@8.6.12 --force + + pnpm install + pnpm run build + + mkdir -p ${CRAFT_PART_INSTALL}/bin ${CRAFT_PART_INSTALL}/lib + + # Copy build directory files to app + cp -r . ${CRAFT_PART_INSTALL}/airbyte-webapp + cp -r ../airbyte-connector-builder-resources/ ${CRAFT_PART_INSTALL}/airbyte-connector-builder-resources + cp -r /root/.nvm/versions/node/v20.11.0/bin/node ${CRAFT_PART_INSTALL}/node + cp -r /root/.nvm/versions/node/v20.11.0/bin/pnpm ${CRAFT_PART_INSTALL}/pnpm + cp -r /root/.nvm/versions/node/v20.11.0/lib ${CRAFT_PART_INSTALL}/ + organize: + node: bin/node + pnpm: bin/pnpm + stage: + - airbyte-webapp + - airbyte-connector-builder-resources + - bin/node + - bin/pnpm + - lib diff --git a/charmcraft.yaml b/charmcraft.yaml index 3439acf..0689965 100644 --- a/charmcraft.yaml +++ b/charmcraft.yaml @@ -88,4 +88,3 @@ resources: airbyte-webapp: type: oci-image description: OCI image for Airbyte web UI - upstream-source: airbyte/webapp:0.60.0 diff --git a/src/charm.py b/src/charm.py index 8210255..be31333 100755 --- a/src/charm.py +++ b/src/charm.py @@ -194,6 +194,7 @@ def _update(self, event): "CONNECTOR_BUILDER_API_HOST": f"{server_svc}:{CONNECTOR_BUILDER_API_PORT}", "CONNECTOR_BUILDER_API_URL": "/connector-builder-api", "KEYCLOAK_INTERNAL_HOST": "localhost", + "PORT": WEB_UI_PORT, } self.model.unit.set_ports(WEB_UI_PORT) @@ -207,7 +208,7 @@ def _update(self, event): "services": { self.name: { "summary": self.name, - "command": "./docker-entrypoint.sh nginx", + "command": "/usr/bin/pnpm -C airbyte-webapp start", "startup": "enabled", "override": "replace", # Including config values here so that a change in the diff --git a/tests/conftest.py b/tests/conftest.py index 04df5c6..f6cdd0e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,3 +14,5 @@ def pytest_addoption(parser: pytest.Parser): """ # The prebuilt charm file. parser.addoption("--charm-file", action="append", default=[]) + # The charm image name:tag. + parser.addoption("--airbyte-ui-image", action="store", default="") diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 2b116cb..c7d23fc 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -5,28 +5,48 @@ import asyncio import logging +from pathlib import Path +import pytest import pytest_asyncio from helpers import ( APP_NAME_AIRBYTE_SERVER, APP_NAME_AIRBYTE_UI, APP_NAME_TEMPORAL_ADMIN, APP_NAME_TEMPORAL_SERVER, - METADATA, create_default_namespace, perform_airbyte_integrations, perform_temporal_integrations, ) +from pytest import FixtureRequest from pytest_operator.plugin import OpsTest logger = logging.getLogger(__name__) +@pytest.fixture(scope="module", name="charm_image") +def charm_image_fixture(request: FixtureRequest) -> str: + """The OCI image for charm.""" + charm_image = request.config.getoption("--airbyte-ui-image") + assert charm_image, "--airbyte-ui-image argument is required which should contain the name of the OCI image." + return charm_image + + +@pytest_asyncio.fixture(scope="module", name="charm") +async def charm_fixture(request: FixtureRequest, ops_test: OpsTest) -> str | Path: + """The path to charm.""" + charms = request.config.getoption("--charm-file") + if not charms: + charm = await ops_test.build_charm(".") + assert charm, "Charm not built" + return charm + return charms[0] + + @pytest_asyncio.fixture(name="deploy", scope="module") -async def deploy(ops_test: OpsTest): +async def deploy(ops_test: OpsTest, charm: str, charm_image: str): """Test the app is up and running.""" - charm = await ops_test.build_charm(".") - resources = {"airbyte-webapp": METADATA["resources"]["airbyte-webapp"]["upstream-source"]} + resources = {"airbyte-webapp": charm_image} asyncio.gather( ops_test.model.deploy(charm, resources=resources, application_name=APP_NAME_AIRBYTE_UI), diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index ef641d4..8932673 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -159,7 +159,7 @@ async def perform_airbyte_integrations(ops_test: OpsTest): apps=[APP_NAME_AIRBYTE_SERVER, APP_NAME_AIRBYTE_UI, "nginx-ingress-integrator"], status="active", raise_on_blocked=False, - timeout=600, + timeout=240, ) assert ops_test.model.applications[APP_NAME_AIRBYTE_SERVER].units[0].workload_status == "active" diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index aea0e2f..180a102 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -130,7 +130,7 @@ def test_ready(self): "services": { APP_NAME: { "summary": APP_NAME, - "command": "./docker-entrypoint.sh nginx", + "command": "/usr/bin/pnpm -C airbyte-webapp start", "startup": "enabled", "override": "replace", "environment": { @@ -141,6 +141,7 @@ def test_ready(self): "INTERNAL_API_HOST": f"airbyte-k8s:{INTERNAL_API_PORT}", "CONNECTOR_BUILDER_API_HOST": f"airbyte-k8s:{CONNECTOR_BUILDER_API_PORT}", "KEYCLOAK_INTERNAL_HOST": "localhost", + "PORT": 8080, }, "on-check-failure": {"up": "ignore"}, } diff --git a/tox.ini b/tox.ini index 8077a1c..b806486 100644 --- a/tox.ini +++ b/tox.ini @@ -100,7 +100,7 @@ commands = description = Run integration tests deps = ipdb==0.13.9 - juju==3.2.0.1 + juju==3.5.2.0 pytest==7.1.3 pytest-operator==0.35.0 temporalio==1.1.0