Repository: apache/camel-k
Pull request #4232 (2023-04-05 12:03:17)

fix(#3476) Add tests for enabling traits at IntegrationPlatform
<!-- Description -->




<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
NONE
```


bouskaJ: > I think this test needs to go under the `commonwithcustominstall` suite, as it would change a common resource used by other tests. See https://camel.apache.org/camel-k/next/contributing/e2e.html#testing-e2e-structure

yes, I wanted to avoid the `commonwithcustominstall` to make the test more universal but I did not know that multiple tests run in the same namespace.  I will move it.

Patch:
diff --git a/.github/workflows/nightly-coverage.yml b/.github/workflows/nightly-coverage.yml
new file mode 100644
index 000000000..a6a0632aa
--- /dev/null
+++ b/.github/workflows/nightly-coverage.yml
@@ -0,0 +1,93 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+
+name: coverage
+
+on:
+  schedule:
+    - cron:  '45 1 * * *'
+  workflow_dispatch: 
+
+jobs:
+  test:
+    runs-on: ubuntu-20.04
+    name: Update Coverage Badge
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          persist-credentials: false 
+          fetch-depth: 0
+      
+      - name: Setup go
+        uses: actions/setup-go@v3
+        with:
+          go-version: '1.18'
+          check-latest: true
+
+      - uses: actions/cache@v3
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-go-
+
+      - name: Run Test
+        run: |
+          go test -v ./... -covermode=count -coverprofile=coverage.out
+          go tool cover -func=coverage.out -o=coverage.out
+          touch badge.out
+
+      - name: Go Coverage Badge
+
+        uses: tj-actions/coverage-badge-go@v2
+        with:
+          filename: coverage.out
+          target: badge.out
+
+      - name: Convert Badge to adoc
+        run: |
+          replacement=$(grep -o 'https://[^)]*' badge.out)
+          target="(?:https:\/\/img\.shields\.io\/badge\/Coverage).*?(?=\.svg)"
+          perl -i -pe "s|${target}|${replacement}|g" README.adoc
+          
+          
+      - name: Verify Changed files
+        uses: tj-actions/verify-changed-files@v12
+        id: verify-changed-files
+        with:
+          files: README.adoc
+
+      - name: Commit changes
+        shell: bash
+        env:
+          CI_USER: "github-actions[bot]"
+          CI_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"
+        run: |
+          git config --local user.email "$CI_EMAIL"
+          git config --local user.name "$CI_USER"
+          git add -A && git commit -m 'chore: nightly coverage badge' && echo "refresh=1" >> $GITHUB_ENV || echo "No changes to make update-docs"
+      
+      - name: Push changes
+        shell: bash
+        if: env.changelog == 1 || env.refresh == 1
+        env:
+          CI_USER: "github-actions[bot]"
+          CI_EMAIL: "41898282+github-actions[bot]@users.noreply.github.com"
+          CI_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          git push "https://$CI_USER:$CI_TOKEN@github.com/$GITHUB_REPOSITORY.git" '${{ github.ref_name }}'
\ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
index bfba2ec93..768b46cc5 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -52,11 +52,15 @@ linters:
     - nlreturn
     - nosnakecase
     - paralleltest
+    - rowserrcheck
     - scopelint
+    - structcheck
+    - sqlclosecheck
     - tagliatelle
     - tenv
     - testpackage
     - varnamelen
+    - wastedassign
     - whitespace
     - wrapcheck
     - wsl
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1c4f4ddc..8ee1d84b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@
 
 **Closed issues:**
 
+- unable to access the URL and unable to expose port after the integration build is successfully deployed. [\#4256](https://github.com/apache/camel-k/issues/4256)
+- unable to execute "kamel run" in secure mode [\#4249](https://github.com/apache/camel-k/issues/4249)
+- Builder pod that hit timeout is not terminated [\#4241](https://github.com/apache/camel-k/issues/4241)
+- Introduce Code Coverage badge [\#4227](https://github.com/apache/camel-k/issues/4227)
 - CamelCatalog reconciliation fail [\#4226](https://github.com/apache/camel-k/issues/4226)
 - duplicate routeId issue [\#4225](https://github.com/apache/camel-k/issues/4225)
 - `KameletBinding` should own the related `Integration` [\#4219](https://github.com/apache/camel-k/issues/4219)
@@ -13,8 +17,10 @@
 - Local file in unit test leftover [\#4217](https://github.com/apache/camel-k/issues/4217)
 - Validate error [\#4214](https://github.com/apache/camel-k/issues/4214)
 - `kamel rebuild` does not rebuild KameletBindings [\#4208](https://github.com/apache/camel-k/issues/4208)
+- Allow E2E suite test to run against a remote cluster [\#4207](https://github.com/apache/camel-k/issues/4207)
 - Cannot copy local runtime dependencies [\#4198](https://github.com/apache/camel-k/issues/4198)
 - Creation of monitoring resources fail in a new GKE cluster [\#4191](https://github.com/apache/camel-k/issues/4191)
+- Unable to produce and consume in camel-k to apache kafka, getting error like "Connection to node -1 \(localhost/127.0.0.1:9092\) could not be established. Broker may not be available." [\#4186](https://github.com/apache/camel-k/issues/4186)
 - Remove additional custom labels utility [\#4183](https://github.com/apache/camel-k/issues/4183)
 - Makefile not working on Mac [\#4175](https://github.com/apache/camel-k/issues/4175)
 - Kamelet development using Camel DSL instead of YAML DSL [\#4174](https://github.com/apache/camel-k/issues/4174)
@@ -26,8 +32,11 @@
 - Kamel run sample integration is failing to run [\#4150](https://github.com/apache/camel-k/issues/4150)
 - Bring an option to force an image build to the kamel run command [\#4126](https://github.com/apache/camel-k/issues/4126)
 - How to use JVM classpaths in Native mode? [\#4124](https://github.com/apache/camel-k/issues/4124)
+- Expose runtime details in `kamel version -a -v` [\#3836](https://github.com/apache/camel-k/issues/3836)
+- Remove KEP cryptic message when installing [\#3829](https://github.com/apache/camel-k/issues/3829)
 - Improve error reporting in case of knative is required but not installed [\#3803](https://github.com/apache/camel-k/issues/3803)
 - Private Registry With TLS  Can Not Work [\#3672](https://github.com/apache/camel-k/issues/3672)
+- Wrong KameletBinding definition leads to operator panic [\#3586](https://github.com/apache/camel-k/issues/3586)
 - Move from release nightly to Continuous Delivery [\#3260](https://github.com/apache/camel-k/issues/3260)
 - OLM basic installation integration test [\#3180](https://github.com/apache/camel-k/issues/3180)
 - Default to using Micrometer for integration monitoring [\#1773](https://github.com/apache/camel-k/issues/1773)
diff --git a/README.adoc b/README.adoc
index 4e501fa38..d07ad3186 100644
--- a/README.adoc
+++ b/README.adoc
@@ -11,6 +11,7 @@ image:https://github.com/apache/camel-k/workflows/kubernetes/badge.svg["Kubernet
 image:https://github.com/apache/camel-k/workflows/knative/badge.svg["Knative", link="https://github.com/apache/camel-k/actions/workflows/knative.yml"]
 image:https://github.com/apache/camel-k/actions/workflows/nightly-release.yml/badge.svg["Nightly releases", link="https://github.com/apache/camel-k/actions/workflows/nightly-release.yml"]
 image:https://github.com/apache/camel-k/actions/workflows/nightly-native-test.yml/badge.svg["Quarkus native", link="https://github.com/apache/camel-k/actions/workflows/nightly-native-test.yml"]
+image:https://img.shields.io/badge/Coverage-39.6%25-yellow.svg["Go coverage", link="https://github.com/apache/camel-k/actions/workflows/nightly-coverage.yml"]
 image:https://img.shields.io/badge/zulip-join_chat-brightgreen.svg["Chat on Zulip", link="https://camel.zulipchat.com"]
 
 Apache Camel K is a lightweight integration framework built from **Apache Camel** that runs natively on Kubernetes and is specifically designed for serverless and microservice architectures. Users of `Camel K` can instantly run integration code written in Camel DSL on their preferred **Cloud** provider.
diff --git a/docs/modules/ROOT/nav-end.adoc b/docs/modules/ROOT/nav-end.adoc
index 06a882fe4..311dee8d1 100644
--- a/docs/modules/ROOT/nav-end.adoc
+++ b/docs/modules/ROOT/nav-end.adoc
@@ -17,7 +17,6 @@
 * API
 ** xref:apis/camel-k.adoc[Camel K API]
 ** xref:apis/kamelets.adoc[Kamelets API]
-* xref:uninstalling.adoc[Uninstalling]
 * xref:contributing/developers.adoc[Contributing]
 ** xref:contributing/local-development.adoc[Local development]
 ** xref:contributing/local-deployment-olm.adoc[Local OLM deployment]
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index 5615c3d8c..7786bcdc9 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -23,6 +23,8 @@
 *** xref:installation/advanced/http-proxy.adoc[HTTP Proxy]
 *** xref:installation/advanced/maven.adoc[Maven]
 *** xref:installation/advanced/multi-architecture.adoc[Multi Architecture]
+** xref:contributing/upgrade.adoc[Upgrade]
+** xref:contributing/uninstalling.adoc[Uninstalling]
 * Command Line Interface
 ** xref:cli/cli.adoc[Kamel CLI]
 ** xref:cli/file-based-config.adoc[File-based Config]
diff --git a/docs/modules/ROOT/pages/uninstalling.adoc b/docs/modules/ROOT/pages/contributing/uninstalling.adoc
similarity index 92%
rename from docs/modules/ROOT/pages/uninstalling.adoc
rename to docs/modules/ROOT/pages/contributing/uninstalling.adoc
index 105e39e8a..88f376f39 100644
--- a/docs/modules/ROOT/pages/uninstalling.adoc
+++ b/docs/modules/ROOT/pages/contributing/uninstalling.adoc
@@ -1,7 +1,7 @@
 [[uninstalling]]
 = Uninstalling Camel K
 
-If you really need to, it is possible to completely uninstall Camel K from OpenShift or Kubernetes with the following command:
+We're sad to see you go, but If you really need to, it is possible to completely uninstall Camel K from OpenShift or Kubernetes with the following command:
 
 [source]
 ----
diff --git a/docs/modules/ROOT/pages/contributing/upgrade.adoc b/docs/modules/ROOT/pages/contributing/upgrade.adoc
new file mode 100644
index 000000000..ee46d25bd
--- /dev/null
+++ b/docs/modules/ROOT/pages/contributing/upgrade.adoc
@@ -0,0 +1,33 @@
+[[upgrade]]
+= Upgrading Camel K
+
+Camel K is delivering new features with each new release, so, you'll be probably running the upgrade process quite often. OLM installation method gives you the possibility to even perform this operation automatically, selecting the auto-upgrade feature when installing. Here we're providing the steps required for non-OLM installation procedure. This is working when using CLI but it can be adapted to any other installation methodology.
+
+When a new release is available, you need to perform a forcefully installation on top of the existing installation. This is required in order to upgrade the CRDs and any other configuration required by the new operator. You need to replace your `kamel` CLI binary with the new one released. Once you have replaced your `kamel` you can proceed with the installation:
+
+[source]
+----
+kamel install --force --olm=false
+----
+
+This operation will install all the required configuration for the new operator version, replacing the previous one. Mind that the `Integration` resources running won't be affected, so they will keep running with the default runtime details provided in the previous operator version.
+
+[[refresh-integrations]]
+== Refresh integrations
+
+Once the operator is up to date, you may want to refresh the `Integration` resources with the new default configuration provided by the upgraded operator (for instance, the default runtime). In such case you'll need to run a `kamel rebuild` operation for each integration you want to update, or `kamel rebuild --all` if you want to upgrade all the Integrations at once.
+
+NOTE: we suggest a controlled approach and rebuild one integration after another.
+
+[[maintain-runtime-integrations]]
+== Stick runtime version
+
+Since Camel K version 2, we're able to run any Camel K runtime version from the same operator. However, if you upgrade and you rebuild an Integration, this one will be rebuilt using the default runtime version of the new operator. In order to stick to a runtime fixed version you need to use the `Camel` trait and the `runtime-version` property, which pin the exact runtime version to use, regardless the default one used by the operator:
+
+----
+kamel run /tmp/Test.java -t camel.runtime-version=1.17.0
+kamel install --force //ie, version 2.0.0
+kamel rebuild test
+kamel logs test
+[1] 2023-04-13 13:38:43,648 INFO  [org.apa.cam.k.Runtime] (main) Apache Camel K Runtime 1.17.0
+----
diff --git a/go.mod b/go.mod
index bf4f24b91..8e5c51233 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/apache/camel-k/v2/pkg/apis/camel v0.0.0
 	github.com/apache/camel-k/v2/pkg/client/camel v0.0.0
 	github.com/apache/camel-k/v2/pkg/kamelet/repository v0.0.0
-	github.com/container-tools/spectrum v0.6.8
+	github.com/container-tools/spectrum v0.6.9
 	github.com/evanphx/json-patch v4.12.0+incompatible
 	github.com/fatih/camelcase v1.0.0
 	github.com/fatih/structs v1.1.0
@@ -27,12 +27,12 @@ require (
 	github.com/otiai10/copy v1.9.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.60.0
-	github.com/prometheus/client_golang v1.14.0
+	github.com/prometheus/client_golang v1.15.0
 	github.com/prometheus/client_model v0.3.0
 	github.com/prometheus/common v0.42.0
 	github.com/radovskyb/watcher v1.0.7
 	github.com/redhat-developer/service-binding-operator v1.3.4
-	github.com/rs/xid v1.4.0
+	github.com/rs/xid v1.5.0
 	github.com/scylladb/go-set v1.0.2
 	github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
 	github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
@@ -87,13 +87,13 @@ require (
 	github.com/blang/semver/v4 v4.0.0 // indirect
 	github.com/blendle/zapdriver v1.3.1 // indirect
 	github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
-	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cloudevents/sdk-go/sql/v2 v2.0.0-20220930150014-52b12276cc4a // indirect
 	github.com/cloudevents/sdk-go/v2 v2.12.0 // indirect
 	github.com/containerd/continuity v0.1.0 // indirect
 	github.com/containerd/stargz-snapshotter/estargz v0.14.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/docker/cli v23.0.3+incompatible // indirect
+	github.com/docker/cli v23.0.4+incompatible // indirect
 	github.com/docker/distribution v2.8.1+incompatible // indirect
 	github.com/docker/docker v23.0.3+incompatible // indirect
 	github.com/docker/docker-credential-helpers v0.7.0 // indirect
@@ -137,7 +137,7 @@ require (
 	github.com/opencontainers/runc v1.0.2 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/prometheus/procfs v0.8.0 // indirect
+	github.com/prometheus/procfs v0.9.0 // indirect
 	github.com/prometheus/statsd_exporter v0.21.0 // indirect
 	github.com/rickb777/date v1.13.0 // indirect
 	github.com/rickb777/plural v1.2.1 // indirect
@@ -159,7 +159,7 @@ require (
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef // indirect
 	google.golang.org/grpc v1.52.0 // indirect
-	google.golang.org/protobuf v1.28.1 // indirect
+	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/component-base v0.25.6 // indirect
diff --git a/go.sum b/go.sum
index d432e2a90..749477fb8 100644
--- a/go.sum
+++ b/go.sum
@@ -201,8 +201,8 @@ github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6
 github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
 github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU=
 github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
@@ -234,8 +234,8 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC
 github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
 github.com/container-tools/go-containerregistry v0.7.1-0.20211124090132-40ccc94a466b h1:PnXGj/WjUnNI7O3AAjXIYs+8QXVRzgoxurEgVgsItrU=
 github.com/container-tools/go-containerregistry v0.7.1-0.20211124090132-40ccc94a466b/go.mod h1:6cMIl1RfryEiPzBE67OgtZdEiLWz4myqCQIiBMy3CsM=
-github.com/container-tools/spectrum v0.6.8 h1:Hl3eB5TYBU8J2/mYNQeXvEf8xAyCMpmyyegcqZP0r28=
-github.com/container-tools/spectrum v0.6.8/go.mod h1:MuWMuWA+Ye9Um34aJWtn/a6z9OaoTKQE9Ms3qSL/87w=
+github.com/container-tools/spectrum v0.6.9 h1:b3kVGM7Z+ZNgj3i4v1u0sSfR/Kq6XJNe4TwZFuQ6iL8=
+github.com/container-tools/spectrum v0.6.9/go.mod h1:dGbIq03rtRodtkC5wq0OeygkUL53dhAhurB90c870c0=
 github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
 github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
 github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@@ -367,8 +367,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
 github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v23.0.3+incompatible h1:Zcse1DuDqBdgI7OQDV8Go7b83xLgfhW1eza4HfEdxpY=
-github.com/docker/cli v23.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v23.0.4+incompatible h1:xClB7PsiATttDHj8ce5qvJcikiApNy7teRR1XkoBZGs=
+github.com/docker/cli v23.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
 github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -793,7 +793,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -1030,8 +1030,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
 github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
-github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
+github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
+github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -1060,8 +1060,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
-github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
+github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
 github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8=
 github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
@@ -1091,8 +1091,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
 github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
 github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
-github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -1914,8 +1914,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/pkg/apis/camel/v1alpha1/error_handler_types_support.go b/pkg/apis/camel/v1alpha1/error_handler_types_support.go
index dfda4c713..79f473a70 100644
--- a/pkg/apis/camel/v1alpha1/error_handler_types_support.go
+++ b/pkg/apis/camel/v1alpha1/error_handler_types_support.go
@@ -19,6 +19,7 @@ package v1alpha1
 
 import (
 	"encoding/json"
+	"fmt"
 )
 
 // +kubebuilder:object:generate=false
@@ -28,6 +29,7 @@ type ErrorHandler interface {
 	Type() ErrorHandlerType
 	Endpoint() *Endpoint
 	Configuration() (map[string]interface{}, error)
+	Validate() error
 }
 
 // baseErrorHandler is the base used for the Error Handler hierarchy
@@ -49,6 +51,11 @@ func (e baseErrorHandler) Configuration() (map[string]interface{}, error) {
 	return nil, nil
 }
 
+// Validate --
+func (e baseErrorHandler) Validate() error {
+	return nil
+}
+
 // ErrorHandlerNone --
 type ErrorHandlerNone struct {
 	baseErrorHandler
@@ -126,3 +133,11 @@ func (e ErrorHandlerSink) Configuration() (map[string]interface{}, error) {
 
 	return properties, err
 }
+
+// Validate --
+func (e ErrorHandlerSink) Validate() error {
+	if e.DLCEndpoint == nil {
+		return fmt.Errorf("Missing endpoint in Error Handler Sink")
+	}
+	return nil
+}
diff --git a/pkg/cmd/uninstall.go b/pkg/cmd/uninstall.go
index 56157b9d7..f7bf20e5d 100644
--- a/pkg/cmd/uninstall.go
+++ b/pkg/cmd/uninstall.go
@@ -239,6 +239,12 @@ func (o *uninstallCmdOptions) uninstallNamespaceRoles(ctx context.Context, cmd *
 			return err
 		}
 		fmt.Fprintln(cmd.OutOrStdout(), "Camel K Role Bindings removed from namespace", o.Namespace)
+
+		KEP1755Namespace := "kube-public"
+		if err := o.uninstallKEP1755RoleBindings(ctx, c, KEP1755Namespace); err != nil {
+			return err
+		}
+		fmt.Fprintln(cmd.OutOrStdout(), "Camel K Role Bindings removed from namespace", KEP1755Namespace)
 	}
 
 	if !o.SkipRoles {
@@ -347,6 +353,24 @@ func (o *uninstallCmdOptions) uninstallRoleBindings(ctx context.Context, c clien
 	return nil
 }
 
+func (o *uninstallCmdOptions) uninstallKEP1755RoleBindings(ctx context.Context, c client.Client, namespace string) error {
+	api := c.RbacV1()
+
+	roleBindings, err := api.RoleBindings(namespace).List(ctx, defaultListOptions)
+	if err != nil {
+		return err
+	}
+
+	for _, roleBinding := range roleBindings.Items {
+		err := api.RoleBindings(namespace).Delete(ctx, roleBinding.Name, metav1.DeleteOptions{})
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func (o *uninstallCmdOptions) uninstallClusterRoles(ctx context.Context, c client.Client) error {
 	api := c.RbacV1()
 
diff --git a/pkg/cmd/version.go b/pkg/cmd/version.go
index 0dfabbc08..3314e1274 100644
--- a/pkg/cmd/version.go
+++ b/pkg/cmd/version.go
@@ -20,8 +20,12 @@ package cmd
 import (
 	"context"
 	"fmt"
+	"regexp"
 	"strings"
 
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/util/camel"
+
 	"golang.org/x/text/cases"
 	"golang.org/x/text/language"
 
@@ -44,6 +48,8 @@ const (
 	infoVersion = "Version"
 )
 
+var replaceRegexp = regexp.MustCompile(`(\s+\.\s*)|(\s+-\s*)`)
+
 func newCmdVersion(rootCmdOptions *RootCmdOptions) (*cobra.Command, *versionCmdOptions) {
 	options := versionCmdOptions{
 		RootCmdOptions: rootCmdOptions,
@@ -119,7 +125,6 @@ func (o *versionCmdOptions) displayOperatorVersion(cmd *cobra.Command, c client.
 			fmt.Fprintf(cmd.OutOrStdout(), "Unable to retrieve operator version: The IntegrationPlatform resource hasn't been reconciled yet!")
 		} else {
 			fmt.Fprintf(cmd.OutOrStdout(), "Camel K Operator %s\n", operatorInfo[infoVersion])
-
 			if o.Verbose {
 				for k, v := range operatorInfo {
 					if k != infoVersion {
@@ -133,7 +138,6 @@ func (o *versionCmdOptions) displayOperatorVersion(cmd *cobra.Command, c client.
 
 func operatorInfo(ctx context.Context, c client.Client, namespace string) (map[string]string, error) {
 	infos := make(map[string]string)
-
 	platform, err := platformutil.GetOrFindLocal(ctx, c, namespace)
 	if err != nil && k8serrors.IsNotFound(err) {
 		// find default operator platform in any namespace
@@ -159,6 +163,17 @@ func operatorInfo(ctx context.Context, c client.Client, namespace string) (map[s
 		}
 	}
 
+	catalog, err := camel.LoadCatalog(ctx, c, namespace, v1.RuntimeSpec{Version: platform.Status.Build.RuntimeVersion, Provider: platform.Status.Build.RuntimeProvider})
+	if err != nil {
+		return nil, err
+	}
+	if catalog == nil {
+		return nil, fmt.Errorf("CamelCatalog can't be found in %s namespace", platform.Namespace)
+	}
+	for k, v := range catalog.CamelCatalogSpec.Runtime.Metadata {
+		infos[k] = v
+	}
+
 	ccInfo := fromCamelCase(infos)
 	log.Debugf("Operator Info for namespace %s: %v", namespace, ccInfo)
 	return ccInfo, nil
@@ -166,8 +181,10 @@ func operatorInfo(ctx context.Context, c client.Client, namespace string) (map[s
 
 func fromCamelCase(infos map[string]string) map[string]string {
 	textKeys := make(map[string]string)
+
 	for k, v := range infos {
 		key := cases.Title(language.English).String(strings.Join(camelcase.Split(k), " "))
+		key = replaceRegexp.ReplaceAllString(key, " ")
 		textKeys[key] = v
 	}
 
diff --git a/pkg/controller/build/monitor_pod.go b/pkg/controller/build/monitor_pod.go
index 7a3e6829b..d75353dba 100644
--- a/pkg/controller/build/monitor_pod.go
+++ b/pkg/controller/build/monitor_pod.go
@@ -216,7 +216,7 @@ func (action *monitorPodAction) sigterm(pod *corev1.Pod) error {
 
 		r.VersionedParams(&corev1.PodExecOptions{
 			Container: container.Name,
-			Command:   []string{"kill", "-SIGTERM", "1"},
+			Command:   []string{"/bin/bash", "-c", "kill -SIGTERM 1"},
 			Stdout:    true,
 			Stderr:    true,
 			TTY:       false,
diff --git a/pkg/controller/kameletbinding/error_handler.go b/pkg/controller/kameletbinding/error_handler.go
index c85829a52..231c5b49a 100644
--- a/pkg/controller/kameletbinding/error_handler.go
+++ b/pkg/controller/kameletbinding/error_handler.go
@@ -79,8 +79,10 @@ func parseErrorHandler(rawMessage v1alpha1.RawMessage) (v1alpha1.ErrorHandler, e
 			return nil, errors.Errorf("Unknown error handler type %s", errHandlType)
 		}
 
-		err := json.Unmarshal(errHandlValue, dst)
-		if err != nil {
+		if err = json.Unmarshal(errHandlValue, dst); err != nil {
+			return nil, err
+		}
+		if err = dst.Validate(); err != nil {
 			return nil, err
 		}
 
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 9f8c10d9c..96adaf885 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -345,7 +345,9 @@ func OperatorOrCollect(ctx context.Context, cmd *cobra.Command, c client.Client,
 	}
 
 	if err = installNamespacedRoleBinding(ctx, c, collection, cfg.Namespace, "/rbac/operator-role-binding-local-registry.yaml"); err != nil {
-		fmt.Fprintln(cmd.ErrOrStderr(), "Warning: the operator won't be able to detect a local image registry via KEP-1755")
+		if !k8serrors.IsAlreadyExists(err) {
+			fmt.Fprintf(cmd.ErrOrStderr(), "Warning: the operator may not be able to detect a local image registry (%s)\n", err.Error())
+		}
 	}
 
 	if cfg.Monitoring.Enabled {


Test patch:
diff --git a/docs/modules/ROOT/pages/contributing/e2e.adoc b/docs/modules/ROOT/pages/contributing/e2e.adoc
index c5e9dfa54..337f0ab86 100644
--- a/docs/modules/ROOT/pages/contributing/e2e.adoc
+++ b/docs/modules/ROOT/pages/contributing/e2e.adoc
@@ -69,6 +69,24 @@ You can also execute the following script, if by any chance you have some change
 make images [CAMEL_K_RUNTIME_DIR=/path/to/camel-k-runtime-project]
 ----
 
+[[using-remote-cluster]]
+== Using remote cluster
+
+If you don't have enough machine resources to run the test locally (a local Kubernetes cluster may require up to 32 GB of memory and several CPUs), then, you can push your operator image to some remote registry that is also reachable from your Kubernetes cluster.
+
+----
+make images CUSTOM_IMAGE=docker.io/my-org/my-ck-operator-test
+----
+
+Then, you need to use a couple of environment variables in order to let the test know the container image to use.
+
+----
+export CAMEL_K_TEST_OPERATOR_IMAGE=docker.io/my-org/my-ck-operator-test:2.0.0-SNAPSHOT
+export CAMEL_K_TEST_OPERATOR_IMAGE_PULL_POLICY=Always // this may not be required, use only if you want to change the policy
+----
+
+Make sure your local Kubernetes config settings is pointing to the right cluster (ie, `kubectl config current-context`) and run the suite of test you want to run (ie, `make test-common`).
+
 [[using-nexus]]
 == Using Nexus repository mirror with E2E testing
 
diff --git a/e2e/commonwithcustominstall/builder_test.go b/e2e/commonwithcustominstall/builder_test.go
index a55c43a56..05c6d188d 100644
--- a/e2e/commonwithcustominstall/builder_test.go
+++ b/e2e/commonwithcustominstall/builder_test.go
@@ -25,9 +25,11 @@ package commonwithcustominstall
 import (
 	"fmt"
 	"testing"
+	"time"
 
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	. "github.com/apache/camel-k/v2/e2e/support"
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
@@ -52,3 +54,43 @@ func TestBuilderPodFallback(t *testing.T) {
 		})
 	})
 }
+
+func TestBuilderTimeout(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		operatorID := fmt.Sprintf("camel-k-%s", ns)
+		Expect(KamelInstallWithID(operatorID, ns).Execute()).To(Succeed())
+		Eventually(OperatorPod(ns)).ShouldNot(BeNil())
+		Eventually(Platform(ns)).ShouldNot(BeNil())
+		Eventually(PlatformConditionStatus(ns, v1.IntegrationPlatformConditionReady), TestTimeoutShort).
+			Should(Equal(corev1.ConditionTrue))
+
+		pl := Platform(ns)()
+		// set a short timeout to simulate the build timeout
+		pl.Spec.Build.Timeout = &metav1.Duration{
+			Duration: 10 * time.Second,
+		}
+		TestClient().Update(TestContext, pl)
+		Eventually(Platform(ns)).ShouldNot(BeNil())
+		Eventually(PlatformTimeout(ns)).Should(Equal(
+			&metav1.Duration{
+				Duration: 10 * time.Second,
+			},
+		))
+
+		t.Run("run yaml", func(t *testing.T) {
+			name := "yaml"
+			Expect(KamelRunWithID(operatorID, ns, "files/yaml.yaml").Execute()).To(Succeed())
+			// As the build hits timeout, it keeps trying building
+			Eventually(IntegrationPhase(ns, name)).Should(Equal(v1.IntegrationPhaseBuildingKit))
+			integrationKitName := IntegrationKit(ns, name)()
+			builderKitName := fmt.Sprintf("camel-k-%s-builder", integrationKitName)
+			Eventually(BuilderPodPhase(ns, builderKitName)).Should(Equal(corev1.PodPending))
+			Eventually(BuildPhase(ns, integrationKitName)).Should(Equal(v1.BuildPhaseRunning))
+			// After a few minutes (5 max retries), this has to be in error state
+			Eventually(BuildPhase(ns, integrationKitName), TestTimeoutMedium).Should(Equal(v1.BuildPhaseError))
+			Eventually(IntegrationPhase(ns, name), TestTimeoutMedium).Should(Equal(v1.IntegrationPhaseError))
+			Eventually(BuildFailureRecovery(ns, integrationKitName), TestTimeoutMedium).Should(Equal(5))
+			Eventually(BuilderPodPhase(ns, builderKitName), TestTimeoutMedium).Should(Equal(corev1.PodFailed))
+		})
+	})
+}
diff --git a/e2e/commonwithcustominstall/platform_traits_test.go b/e2e/commonwithcustominstall/platform_traits_test.go
new file mode 100644
index 000000000..c8f6e13a2
--- /dev/null
+++ b/e2e/commonwithcustominstall/platform_traits_test.go
@@ -0,0 +1,77 @@
+//go:build integration
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package commonwithcustominstall
+
+import (
+	"testing"
+
+	"github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+
+	. "github.com/onsi/gomega"
+
+	corev1 "k8s.io/api/core/v1"
+
+	. "github.com/apache/camel-k/v2/e2e/support"
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+)
+
+func TestTraitOnIntegrationPlatform(t *testing.T) {
+	WithNewTestNamespace(t, func(ns string) {
+		operatorID := "camel-k-platform-trait-test"
+		Expect(KamelInstallWithID(operatorID, ns).Execute()).To(Succeed())
+
+		containerTestName := "testname"
+		ip := Platform(ns)()
+		ip.Spec.Traits = v1.Traits{Logging: &trait.LoggingTrait{Level: "DEBUG"}, Container: &trait.ContainerTrait{Name: containerTestName}}
+
+		if err := TestClient().Update(TestContext, ip); err != nil {
+			t.Fatal("Can't create IntegrationPlatform", err)
+		}
+
+		name := "java"
+		t.Run("Run integration with platform traits", func(t *testing.T) {
+			Expect(KamelRunWithID(operatorID, ns, "files/Java.java",
+				"--name", name,
+			).Execute()).To(Succeed())
+			Eventually(IntegrationPodPhase(ns, name), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+			Eventually(IntegrationConditionStatus(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+
+			Expect(IntegrationPod(ns, name)().Spec.Containers[0].Name).To(BeEquivalentTo(containerTestName))
+
+			found := false
+			for _, env := range IntegrationPod(ns, name)().Spec.Containers[0].Env {
+				if env.Name == "QUARKUS_LOG_LEVEL" {
+					Expect(env.Value).To(BeEquivalentTo("DEBUG"))
+					found = true
+					break
+				}
+			}
+			Expect(found).To(BeTrue(), "Can't find QUARKUS_LOG_LEVEL ENV variable")
+			Eventually(IntegrationLogs(ns, name), TestTimeoutShort).Should(ContainSubstring("DEBUG"))
+
+			Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+		})
+	})
+}
+
diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go
index bc058c843..277af262f 100644
--- a/e2e/support/test_support.go
+++ b/e2e/support/test_support.go
@@ -279,6 +279,17 @@ func kamelInstallWithContext(ctx context.Context, operatorID string, namespace s
 		}
 	}
 
+	opImage := os.Getenv("CAMEL_K_TEST_OPERATOR_IMAGE")
+	if opImage != "" {
+		fmt.Printf("Setting operator image to %s\n", opImage)
+		installArgs = append(installArgs, "--operator-image", opImage)
+	}
+	opImagePullPolicy := os.Getenv("CAMEL_K_TEST_OPERATOR_IMAGE_PULL_POLICY")
+	if opImagePullPolicy != "" {
+		fmt.Printf("Setting operator image pull policy to %s\n", opImagePullPolicy)
+		installArgs = append(installArgs, "--operator-image-pull-policy", opImagePullPolicy)
+	}
+
 	installArgs = append(installArgs, args...)
 	return KamelWithContext(ctx, installArgs...)
 }
@@ -1374,6 +1385,16 @@ func BuilderPod(ns string, name string) func() *corev1.Pod {
 	}
 }
 
+func BuilderPodPhase(ns string, name string) func() corev1.PodPhase {
+	return func() corev1.PodPhase {
+		pod := BuilderPod(ns, name)()
+		if pod == nil {
+			return ""
+		}
+		return pod.Status.Phase
+	}
+}
+
 func BuilderPodsCount(ns string) func() int {
 	return func() int {
 		lst := corev1.PodList{
@@ -1590,6 +1611,16 @@ func BuildPhase(ns, name string) func() v1.BuildPhase {
 	}
 }
 
+func BuildFailureRecovery(ns, name string) func() int {
+	return func() int {
+		build := Build(ns, name)()
+		if build != nil {
+			return build.Status.Failure.Recovery.Attempt
+		}
+		return 0
+	}
+}
+
 func HasPlatform(ns string) func() bool {
 	return func() bool {
 		lst := v1.NewIntegrationPlatformList()
@@ -1789,6 +1820,16 @@ func PlatformBuildCatalogToolTimeout(ns string) func() *metav1.Duration {
 	}
 }
 
+func PlatformTimeout(ns string) func() *metav1.Duration {
+	return func() *metav1.Duration {
+		p := Platform(ns)()
+		if p == nil {
+			return &metav1.Duration{}
+		}
+		return p.Status.Build.Timeout
+	}
+}
+
 func AssignPlatformToOperator(ns, operator string) error {
 	pl := Platform(ns)()
 	if pl == nil {
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index 40741eade..8fd74064e 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -63,8 +63,10 @@ func TestIntegrationNotCompatible(t *testing.T) {
 	dstPlatform.Status.Build.RuntimeVersion = "0.0.1"
 	dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
 	defaultIntegration := nominalIntegration("my-it-test")
+	srcCatalog := createCamelCatalog(srcPlatform)
+	dstCatalog := createCamelCatalog(dstPlatform)
 
-	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration)
+	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
 	_, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
 	assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
 	assert.NotNil(t, err)
@@ -84,8 +86,10 @@ func TestIntegrationDryRun(t *testing.T) {
 	dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
 	dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
 	defaultIntegration := nominalIntegration("my-it-test")
+	srcCatalog := createCamelCatalog(srcPlatform)
+	dstCatalog := createCamelCatalog(dstPlatform)
 
-	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration)
+	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultIntegration, &srcCatalog, &dstCatalog)
 	output, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-it-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
 	assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
 	assert.Nil(t, err)
@@ -121,8 +125,10 @@ func TestKameletBindingDryRun(t *testing.T) {
 	dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
 	defaultKB := nominalKameletBinding("my-kb-test")
 	defaultIntegration := nominalIntegration("my-kb-test")
+	srcCatalog := createCamelCatalog(srcPlatform)
+	dstCatalog := createCamelCatalog(dstPlatform)
 
-	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration)
+	promoteCmdOptions, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, &dstPlatform, &defaultKB, &defaultIntegration, &srcCatalog, &dstCatalog)
 	output, err := test.ExecuteCommand(promoteCmd, cmdPromote, "my-kb-test", "--to", "prod-namespace", "-o", "yaml", "-n", "default")
 	assert.Equal(t, "yaml", promoteCmdOptions.OutputFormat)
 	assert.Nil(t, err)
@@ -149,3 +155,9 @@ func nominalKameletBinding(name string) v1alpha1.KameletBinding {
 	kb.Status.Phase = v1alpha1.KameletBindingPhaseReady
 	return kb
 }
+
+func createCamelCatalog(platform v1.IntegrationPlatform) v1.CamelCatalog {
+	c := v1.NewCamelCatalog(platform.Namespace, defaults.DefaultRuntimeVersion)
+	c.Spec = v1.CamelCatalogSpec{Runtime: v1.RuntimeSpec{Provider: platform.Status.Build.RuntimeProvider, Version: platform.Status.Build.RuntimeVersion}}
+	return c
+}
diff --git a/pkg/cmd/version_test.go b/pkg/cmd/version_test.go
index 383fe9cf9..6dda7f1b6 100644
--- a/pkg/cmd/version_test.go
+++ b/pkg/cmd/version_test.go
@@ -21,6 +21,10 @@ import (
 	"fmt"
 	"testing"
 
+	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+	"github.com/apache/camel-k/v2/pkg/platform"
+	"k8s.io/apimachinery/pkg/runtime"
+
 	"github.com/apache/camel-k/v2/pkg/util/defaults"
 	"github.com/apache/camel-k/v2/pkg/util/test"
 	"github.com/spf13/cobra"
@@ -30,10 +34,12 @@ import (
 const cmdVersion = "version"
 
 // nolint: unparam
-func initializeVersionCmdOptions(t *testing.T) (*versionCmdOptions, *cobra.Command, RootCmdOptions) {
+func initializeVersionCmdOptions(t *testing.T, initObjs ...runtime.Object) (*versionCmdOptions, *cobra.Command, RootCmdOptions) {
 	t.Helper()
 
-	options, rootCmd := kamelTestPreAddCommandInit()
+	fakeClient, err := test.NewFakeClient(initObjs...)
+	assert.Nil(t, err)
+	options, rootCmd := kamelTestPreAddCommandInitWithClient(fakeClient)
 	versionCmdOptions := addTestVersionCmd(*options, rootCmd)
 	kamelTestPostAddCommandInit(t, rootCmd)
 
@@ -76,6 +82,30 @@ func TestVersionClientVerbose(t *testing.T) {
 	assert.Equal(t, fmt.Sprintf("Camel K Client %s\nGit Commit: %s\n", defaults.Version, defaults.GitCommit), output)
 }
 
+func TestOperatorVersionVerbose(t *testing.T) {
+	platform := v1.NewIntegrationPlatform("default", platform.DefaultPlatformName)
+	platform.Status.Version = defaults.Version
+	platform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
+	platform.Status.Phase = v1.IntegrationPlatformPhaseReady
+	catalog := v1.NewCamelCatalog(platform.Namespace, defaults.DefaultRuntimeVersion)
+	catalog.Spec = v1.CamelCatalogSpec{Runtime: v1.RuntimeSpec{Provider: platform.Status.Build.RuntimeProvider, Version: platform.Status.Build.RuntimeVersion}}
+	// mocked catalog versions
+	catalog.Spec.Runtime.Metadata = map[string]string{
+		"camel-quarkus.version": "2.16.0",
+		"camel.version":         "3.20.1",
+		"quarkus.version":       "2.16.0.Final",
+	}
+
+	versionCmdOptions, rootCmd, _ := initializeVersionCmdOptions(t, &platform, &catalog)
+	output, err := test.ExecuteCommand(rootCmd, cmdVersion, "-v", "--operator")
+	assert.Nil(t, err)
+	assert.Equal(t, true, versionCmdOptions.Verbose)
+	assert.Contains(t, output, fmt.Sprintf("Camel K Operator %s\n", defaults.Version))
+	assert.Contains(t, output, fmt.Sprintf("Camel Version: %s\n", catalog.Spec.Runtime.Metadata["camel.version"]))
+	assert.Contains(t, output, fmt.Sprintf("Camel Quarkus Version: %s\n", catalog.Spec.Runtime.Metadata["camel-quarkus.version"]))
+	assert.Contains(t, output, fmt.Sprintf("Quarkus Version: %s\n", catalog.Spec.Runtime.Metadata["quarkus.version"]))
+}
+
 func TestCompatibleVersions(t *testing.T) {
 	_, rootCmd, _ := initializeVersionCmdOptions(t)
 	assert.Equal(t, true, compatibleVersions("1.3.0", "1.3.0", rootCmd))
diff --git a/pkg/controller/kameletbinding/error_handler_test.go b/pkg/controller/kameletbinding/error_handler_test.go
index 6abbf2187..02607dda4 100644
--- a/pkg/controller/kameletbinding/error_handler_test.go
+++ b/pkg/controller/kameletbinding/error_handler_test.go
@@ -18,7 +18,6 @@ limitations under the License.
 package kameletbinding
 
 import (
-	"fmt"
 	"testing"
 
 	"github.com/apache/camel-k/v2/pkg/apis/camel/v1alpha1"
@@ -64,7 +63,6 @@ func TestParseErrorHandlerLogWithParametersDoesSucceed(t *testing.T) {
 }
 
 func TestParseErrorHandlerSinkDoesSucceed(t *testing.T) {
-	fmt.Println("Test")
 	sinkErrorHandler, err := parseErrorHandler(
 		[]byte(`{"sink": {"endpoint": {"uri": "someUri"}}}`),
 	)
@@ -101,3 +99,11 @@ func TestParseErrorHandlerSinkWithParametersDoesSucceed(t *testing.T) {
 	assert.Equal(t, "value1", parameters["camel.beans.defaultErrorHandler.param1"])
 	assert.Equal(t, "value2", parameters["camel.beans.defaultErrorHandler.param2"])
 }
+
+func TestParseErrorHandlerSinkFail(t *testing.T) {
+	_, err := parseErrorHandler(
+		[]byte(`{"sink": {"ref": {"uri": "someUri"}}}`),
+	)
+	assert.NotNil(t, err)
+	assert.Equal(t, "Missing endpoint in Error Handler Sink", err.Error())
+}
diff --git a/pkg/util/jvm/keystore_test.go b/pkg/util/jvm/keystore_test.go
index 0b570ae84..ffeed9621 100644
--- a/pkg/util/jvm/keystore_test.go
+++ b/pkg/util/jvm/keystore_test.go
@@ -28,18 +28,18 @@ import (
 
 func TestGenerateKeystore(t *testing.T) {
 
-	// No Data
+	// Nil Data
 	var data [][]byte
 	ctx := context.Background()
 	err := GenerateKeystore(ctx, "", "/tmp/keystore", NewKeystorePassword(), data)
 	assert.Nil(t, err)
 
-	// Correct input
+	// Non-Nil Data
 	data = [][]byte{{0}, {1}}
 	err = GenerateKeystore(ctx, "", "/tmp/keystore", NewKeystorePassword(), data)
 	assert.NotNil(t, err)
 
-	// Incorrect input format
+	// Incorrect password format
 	err = GenerateKeystore(ctx, "", "/tmp/keystore", "", data)
 	assert.NotNil(t, err)