Repository: kubevela/kubevela

Issue:
Bug: Incorrect namespace existence check in `generateSecretFromTerraformOutput`
**Describe the bug**
The function `generateSecretFromTerraformOutput` in `references/appfile/addon.go` contains a bug in its logic for checking if a namespace exists. It incorrectly uses a `Create` operation, which leads to contradictory behavior. If a namespace doesn't exist, the function creates it and then incorrectly returns an error stating the namespace *doesn't* exist.

**To Reproduce**
This bug was identified through code review and unit testing. It can be reproduced in a test environment by calling `generateSecretFromTerraformOutput` with a valid namespace that does not yet exist on the cluster.

**Expected behavior**
The function should correctly check for a namespace's existence using a `Get` call. It should only return a "namespace doesn't exist" error if the `Get` call fails with a `NotFound` error.

**KubeVela Version**
This bug was identified in the current `master` branch.

**Cluster information**
Not applicable, as this is a code-level logic bug independent of a specific cluster version.

**Additional context**

### Problematic Code

The current implementation attempts to create the namespace and returns a confusing error if the creation succeeds.

```go
// generateSecretFromTerraformOutput generates secret from Terraform output
func generateSecretFromTerraformOutput(k8sClient client.Client, outputList []string, name, namespace string) error {
	ctx := context.TODO()
	err := k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})
	if err == nil {
		return fmt.Errorf("namespace %s doesn't exist", namespace)
	}
    // ... rest of the function
}
```

### Suggested Fix

The logic should be changed to use `k8sClient.Get` and check for a `NotFound` error.

```go
import (
    "k8s.io/apimachinery/pkg/api/errors"
    "sigs.k8s.io/controller-runtime/pkg/client"
)

// generateSecretFromTerraformOutput generates secret from Terraform output
func generateSecretFromTerraformOutput(k8sClient client.Client, outputList []string, name, namespace string) error {
	ctx := context.TODO()
	// Check if namespace exists
	var ns v1.Namespace
	if err := k8sClient.Get(ctx, client.ObjectKey{Name: namespace}, &ns); err != nil {
		if errors.IsNotFound(err) {
			return fmt.Errorf("namespace %s doesn't exist", namespace)
		}
		return fmt.Errorf("failed to get namespace %s: %w", namespace, err)
	}
    // ... rest of the function
}
```

Discussion:

Solution patch:
diff --git a/.github/actions/deploy-current-branch/README.md b/.github/actions/deploy-current-branch/README.md
new file mode 100644
index 00000000..6f97c762
--- /dev/null
+++ b/.github/actions/deploy-current-branch/README.md
@@ -0,0 +1,35 @@
+# Deploy Current Branch Action
+
+This GitHub composite action builds a Docker image from the current branch commit and deploys it to a KubeVela cluster for development testing.
+
+## What it does
+
+- Generates a unique image tag from the latest commit hash
+- Builds and loads the Docker image into a KinD cluster
+- Applies KubeVela CRDs for upgrade safety
+- Upgrades the KubeVela Helm release to use the local development image
+- Verifies deployment status and the running image version
+
+## Usage
+
+```yaml
+- name: Deploy Current Branch
+  uses: ./path/to/this/action
+```
+
+## Requirements
+
+- Docker, Helm, kubectl, and KinD must be available in your runner environment
+- Kubernetes cluster access
+- `charts/vela-core/crds` directory with CRDs
+- Valid Helm chart at `charts/vela-core`
+
+## Steps performed
+
+1. **Generate commit hash for image tag**
+2. **Build & load Docker image into KinD**
+3. **Pre-apply chart CRDs**
+4. **Upgrade KubeVela using local image**
+5. **Verify deployment and image version**
+
+---
\ No newline at end of file
diff --git a/.github/actions/deploy-current-branch/action.yaml b/.github/actions/deploy-current-branch/action.yaml
new file mode 100644
index 00000000..5e296cd4
--- /dev/null
+++ b/.github/actions/deploy-current-branch/action.yaml
@@ -0,0 +1,89 @@
+name: 'Deploy Current Branch'
+description: 'Builds Docker image from current branch commit and deploys it to KubeVela cluster for development testing'
+
+runs:
+  using: "composite"
+  steps:
+    # ========================================================================
+    # Git Commit Hash Generation
+    # Generate unique image tag from current branch's latest commit
+    # ========================================================================
+    - name: Get commit hash
+      id: commit_hash
+      shell: bash
+      run: |
+        COMMIT_HASH="git-$(git rev-parse --short HEAD)"
+        echo "Using commit hash: $COMMIT_HASH"
+        echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_ENV
+
+    # ========================================================================
+    # Docker Image Build and Cluster Loading
+    # Build development image from current code and load into KinD cluster
+    # ========================================================================
+    - name: Build and load Docker image
+      shell: bash
+      run: |
+        echo "Building development image: vela-core-test:${{ env.COMMIT_HASH }}"
+
+        mkdir -p $HOME/tmp/
+
+        docker build --no-cache \
+          -t vela-core-test:${{ env.COMMIT_HASH }} \
+          -f Dockerfile .
+
+        echo "Loading image into KinD cluster..."
+        TMPDIR=$HOME/tmp/ kind load docker-image vela-core-test:${{ env.COMMIT_HASH }}
+
+    # ========================================================================
+    # Custom Resource Definitions Application
+    # Pre-apply CRDs to ensure upgrade compatibility and prevent conflicts
+    # ========================================================================
+    - name: Pre-apply CRDs from target chart (upgrade-safe)
+      shell: bash
+      run: |
+        CRD_DIR="charts/vela-core/crds"
+
+        echo "Applying CRDs idempotently..."
+        kubectl apply -f "${CRD_DIR}"
+
+    # ========================================================================
+    # KubeVela Helm Chart Upgrade
+    # Upgrade existing installation to use locally built development image
+    # ========================================================================
+    - name: Upgrade KubeVela to development image
+      shell: bash
+      run: |
+        echo "Upgrading KubeVela to development version..."
+        helm upgrade kubevela ./charts/vela-core \
+          --namespace vela-system \
+          --set image.repository=vela-core-test \
+          --set image.tag=${{ env.COMMIT_HASH }} \
+          --set image.pullPolicy=IfNotPresent \
+          --timeout 5m \
+          --wait \
+          --debug
+
+    # ========================================================================
+    # Deployment Status Verification
+    # Verify successful upgrade and confirm correct image deployment
+    # ========================================================================
+    - name: Verify deployment status
+      shell: bash
+      run: |
+        echo "=== DEPLOYMENT VERIFICATION ==="
+        echo "Verifying upgrade to local development image..."
+
+        echo "--- Pod Status ---"
+        kubectl get pods -n vela-system
+
+        echo "--- Deployment Rollout ---"
+        kubectl rollout status deployment/kubevela-vela-core \
+          -n vela-system \
+          --timeout=300s
+
+        echo "--- Deployed Image Version ---"
+        kubectl get deployment kubevela-vela-core \
+          -n vela-system \
+          -o yaml | grep "image:" | head -1
+
+        echo "Deployment verification completed successfully!"
\ No newline at end of file
diff --git a/.github/actions/deploy-latest-release/README.md b/.github/actions/deploy-latest-release/README.md
new file mode 100644
index 00000000..4eabbc39
--- /dev/null
+++ b/.github/actions/deploy-latest-release/README.md
@@ -0,0 +1,32 @@
+# Install Latest KubeVela Release Action
+
+This GitHub composite action installs the latest stable KubeVela release from the official Helm repository and verifies its deployment status.
+
+## What it does
+
+- Discovers the latest stable KubeVela release tag from GitHub
+- Adds and updates the official KubeVela Helm chart repository
+- Installs KubeVela into the `vela-system` namespace (using Helm)
+- Verifies pod status and deployment rollout for successful installation
+
+## Usage
+
+```yaml
+- name: Install Latest KubeVela Release
+  uses: ./path/to/this/action
+```
+
+## Requirements
+
+- Helm, kubectl, jq, and curl must be available in your runner environment
+- Kubernetes cluster access
+
+## Steps performed
+
+1. **Release Tag Discovery:** Fetches latest stable tag (without `v` prefix)
+2. **Helm Repo Setup:** Adds/updates KubeVela Helm chart repo
+3. **Install KubeVela:** Installs latest release in the `vela-system` namespace
+4. **Status Verification:** Checks pod status and rollout for readiness
+
+---
+
diff --git a/.github/actions/deploy-latest-release/action.yaml b/.github/actions/deploy-latest-release/action.yaml
new file mode 100644
index 00000000..05e0115e
--- /dev/null
+++ b/.github/actions/deploy-latest-release/action.yaml
@@ -0,0 +1,68 @@
+name: 'Install Latest KubeVela Release'
+description: 'Installs the latest stable KubeVela release from official Helm repository with status verification'
+
+runs:
+  using: "composite"
+  steps:
+    # ========================================================================
+    # Latest Release Tag Discovery
+    # Fetch current stable release version from GitHub API
+    # ========================================================================
+    - name: Get latest KubeVela release tag (no v prefix)
+      id: get_latest_tag
+      shell: bash
+      run: |
+        TAG=$(curl -s https://api.github.com/repos/kubevela/kubevela/releases/latest | \
+              jq -r ".tag_name" | \
+              awk '{sub(/^v/, ""); print}')
+        echo "LATEST_TAG=$TAG" >> $GITHUB_ENV
+        echo "Discovered latest release: $TAG"
+
+    # ========================================================================
+    # Helm Repository Configuration
+    # Add and update official KubeVela chart repository
+    # ========================================================================
+    - name: Add KubeVela Helm repo
+      shell: bash
+      run: |
+        echo "Adding KubeVela Helm repository..."
+        helm repo add kubevela https://kubevela.github.io/charts
+        helm repo update
+        echo "Helm repository configuration completed"
+
+    # ========================================================================
+    # KubeVela Stable Release Installation
+    # Deploy latest stable version to vela-system namespace
+    # ========================================================================
+    - name: Install KubeVela ${{ env.LATEST_TAG }}
+      shell: bash
+      run: |
+        echo "Installing KubeVela version: ${{ env.LATEST_TAG }}"
+        helm install \
+          --create-namespace \
+          -n vela-system \
+          kubevela kubevela/vela-core \
+          --version ${{ env.LATEST_TAG }} \
+          --timeout 10m \
+          --wait
+        echo "KubeVela installation completed"
+
+    # ========================================================================
+    # Installation Status Verification
+    # Verify successful deployment and readiness of KubeVela components
+    # ========================================================================
+    - name: Post-install status
+      shell: bash
+      run: |
+        echo "=== INSTALLATION VERIFICATION ==="
+        echo "Verifying KubeVela deployment status..."
+
+        echo "--- Pod Status ---"
+        kubectl get pods -n vela-system
+
+        echo "--- Deployment Rollout ---"
+        kubectl rollout status deployment/kubevela-vela-core \
+          -n vela-system \
+          --timeout=300s
+
+        echo "KubeVela installation verification completed successfully!"
\ No newline at end of file
diff --git a/.github/actions/env-setup/README.md b/.github/actions/env-setup/README.md
new file mode 100644
index 00000000..a4cd04d2
--- /dev/null
+++ b/.github/actions/env-setup/README.md
@@ -0,0 +1,67 @@
+# Kubevela Test Environment Setup Action
+
+A GitHub Actions composite action that sets up a complete testing environment for Kubevela projects with Go, Kubernetes tools, and the Ginkgo testing framework.
+
+## Features
+
+- 🛠️ **System Dependencies**: Installs essential build tools (make, gcc, jq, curl, etc.)
+- ☸️ **Kubernetes Tools**: Sets up kubectl and Helm for cluster operations
+- 🐹 **Go Environment**: Configurable Go version with module caching
+- 📦 **Dependency Management**: Downloads and verifies Go module dependencies
+- 🧪 **Testing Framework**: Installs Ginkgo v2 for BDD-style testing
+
+## Usage
+
+```yaml
+- name: Setup Kubevela Test Environment
+  uses: ./path/to/this/action
+  with:
+    go-version: '1.23.8'      # Optional: Go version (default: 1.23.8)
+```
+
+### Example Workflow
+
+```yaml
+name: Kubevela Tests
+on: [push, pull_request]
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      
+      - name: Setup Test Environment
+        uses: ./path/to/this/action
+        with:
+          go-version: '1.21'
+          
+      - name: Run Tests
+        run: |
+          ginkgo -r ./tests/e2e/
+```
+
+## Inputs
+
+| Input | Description | Required | Default | Usage |
+|-------|-------------|----------|---------|-------|
+| `go-version` | Go version to install and use | No | `1.23.8` | Specify Go version for your project |
+
+## What This Action Installs
+
+### System Tools
+- **make**: Build automation tool
+- **gcc**: GNU Compiler Collection
+- **jq**: JSON processor for shell scripts
+- **ca-certificates**: SSL/TLS certificates
+- **curl**: HTTP client for downloads
+- **gnupg**: GNU Privacy Guard for security
+
+### Kubernetes Ecosystem
+- **kubectl**: Kubernetes command-line tool (latest stable)
+- **helm**: Kubernetes package manager (latest stable)
+
+### Go Development
+- **Go Runtime**: Specified version with module caching enabled
+- **Go Modules**: Downloaded and verified dependencies
+- **Ginkgo v2.14.0**: BDD testing framework for Go
\ No newline at end of file
diff --git a/.github/actions/env-setup/action.yaml b/.github/actions/env-setup/action.yaml
new file mode 100644
index 00000000..c41a6158
--- /dev/null
+++ b/.github/actions/env-setup/action.yaml
@@ -0,0 +1,72 @@
+name: 'Kubevela Test Environment Setup'
+description: 'Sets up complete testing environment for Kubevela with Go, Kubernetes tools, and Ginkgo framework for E2E testing.'
+
+inputs:
+  go-version:
+    description: 'Go version to use for testing'
+    required: false
+    default: '1.23.8'
+
+
+runs:
+  using: 'composite'
+  steps:
+    # ========================================================================
+    # Environment Setup
+    # ========================================================================
+    - name: Install system dependencies
+      shell: bash
+      run: |
+        # Update package manager and install essential tools
+        sudo apt-get update
+        sudo apt-get install -y \
+          make \
+          gcc \
+          jq \
+          ca-certificates \
+          curl \
+          gnupg
+
+    - name: Install kubectl and helm
+      shell: bash
+      run: |
+        # Detect architecture
+        ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
+        
+        # Install kubectl
+        echo "Installing kubectl for architecture: $ARCH"
+        curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl"
+        chmod +x kubectl
+        sudo mv kubectl /usr/local/bin/
+        
+        # Install helm using the official script (more reliable)
+        echo "Installing Helm using official script..."
+        curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
+        chmod 700 get_helm.sh
+        ./get_helm.sh
+        rm get_helm.sh
+        
+        # Verify installations
+        echo "Verifying installations..."
+        kubectl version --client
+        helm version
+    
+
+    - name: Setup Go environment
+      uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
+      with:
+        go-version: ${{ inputs.go-version }}
+        cache: true
+
+    - name: Download Go dependencies
+      shell: bash
+      run: |
+        # Download and cache Go module dependencies
+        go mod download
+        go mod verify
+
+    - name: Install Ginkgo testing framework
+      shell: bash
+      run: |
+        echo "Installing Ginkgo testing framework..."
+        go install github.com/onsi/ginkgo/v2/ginkgo@v2.14.0
diff --git a/.github/actions/setup-kind-cluster/README.md b/.github/actions/setup-kind-cluster/README.md
new file mode 100644
index 00000000..aaf70982
--- /dev/null
+++ b/.github/actions/setup-kind-cluster/README.md
@@ -0,0 +1,78 @@
+# Setup Kind Cluster Action
+
+A GitHub Action that sets up a Kubernetes testing environment using Kind (Kubernetes in Docker) for E2E testing.
+
+## Inputs
+
+| Input | Description | Required | Default |
+|-------|-------------|----------|---------|
+| `k8s-version` | Kubernetes version for the kind cluster | No | `v1.31.9` |
+
+## Quick Start
+
+```yaml
+name: E2E Tests
+on: [push, pull_request]
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      
+      - uses: actions/setup-go@v5
+        with:
+          go-version: '1.21'
+      
+      - name: Setup Kind Cluster
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          k8s-version: 'v1.31.9'
+      
+      - name: Run tests
+        run: |
+          kubectl cluster-info
+          make test-e2e
+```
+
+## What it does
+
+1. **Installs Kind CLI** - Downloads Kind v0.29.0 using Go
+2. **Cleans up** - Removes any existing Kind clusters
+3. **Creates cluster** - Spins up Kubernetes v1.31.9 cluster
+4. **Sets up environment** - Configures KUBECONFIG for kubectl access
+5. **Loads images** - Builds and loads Docker images using `make image-load`
+
+## File Structure
+
+Save as `.github/actions/setup-kind-cluster/action.yaml`:
+
+```yaml
+name: 'SetUp kind cluster'
+description: 'Sets up complete testing environment for Kubevela with Go, Kubernetes tools, and Ginkgo framework for E2E testing.'
+
+inputs:
+  k8s-version:
+    description: 'Kubernetes version for the kind cluster'
+    required: false
+    default: 'v1.31.9'
+
+runs:
+  using: 'composite'
+  steps:
+    # ========================================================================
+    # Kind cluster Setup
+    # ========================================================================
+    - name: Setup KinD
+      run: |
+        go install sigs.k8s.io/kind@v0.29.0
+        kind delete cluster || true
+        kind create cluster --image=kindest/node:${{ inputs.k8s-version }}
+      shell: bash
+
+    - name: Load image
+      run: |
+        mkdir -p $HOME/tmp/
+        TMPDIR=$HOME/tmp/ make image-load
+      shell: bash
+```
\ No newline at end of file
diff --git a/.github/actions/setup-kind-cluster/action.yaml b/.github/actions/setup-kind-cluster/action.yaml
new file mode 100644
index 00000000..824c7828
--- /dev/null
+++ b/.github/actions/setup-kind-cluster/action.yaml
@@ -0,0 +1,36 @@
+name: 'SetUp kind cluster'
+description: 'Sets up a KinD (Kubernetes in Docker) cluster with configurable Kubernetes version and optional cluster naming for testing and development workflows.'
+inputs:
+  k8s-version:
+    description: 'Kubernetes version for the kind cluster'
+    required: false
+    default: 'v1.31.9'
+  name:
+    description: 'Name of the kind cluster'
+    required: false
+runs:
+  using: 'composite'
+  steps:
+    # ========================================================================
+    # Kind cluster Setup
+    # ========================================================================
+    - name: Setup KinD
+      run: |
+        go install sigs.k8s.io/kind@v0.29.0
+        if [ -n "${{ inputs.name }}" ]; then
+          kind delete cluster --name="${{ inputs.name }}" || true
+          kind create cluster --name="${{ inputs.name }}" --image=kindest/node:${{ inputs.k8s-version }}
+          kind export kubeconfig --internal --name="${{ inputs.name }}" --kubeconfig /tmp/${{ inputs.name }}.kubeconfig
+        else
+          kind delete cluster || true
+          kind create cluster --image=kindest/node:${{ inputs.k8s-version }}
+        fi
+      shell: bash
+
+    - name: Load image
+      run: |
+        if [ -z "${{ inputs.name }}" ]; then
+          mkdir -p $HOME/tmp/
+          TMPDIR=$HOME/tmp/ make image-load
+        fi
+      shell: bash
\ No newline at end of file
diff --git a/.github/workflows/definition-lint.yml b/.github/workflows/definition-lint.yml
index 1714f5c3..bdfa61c0 100644
--- a/.github/workflows/definition-lint.yml
+++ b/.github/workflows/definition-lint.yml
@@ -33,9 +33,9 @@ jobs:
           submodules: true
 
       - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind create cluster --image=kindest/node:v1.31.9
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          name: linter
 
       - name: Definition Doc generate check
         run: |
diff --git a/.github/workflows/e2e-multicluster-test.yml b/.github/workflows/e2e-multicluster-test.yml
index b2be990c..5ac8d12a 100644
--- a/.github/workflows/e2e-multicluster-test.yml
+++ b/.github/workflows/e2e-multicluster-test.yml
@@ -44,7 +44,7 @@ jobs:
     if: needs.detect-noop.outputs.noop != 'true'
     strategy:
       matrix:
-        k8s-version: ["v1.31"]
+        k8s-version: ["v1.31.9"]
     concurrency:
       group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
       cancel-in-progress: true
@@ -53,61 +53,31 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
 
-      - name: Install tools
-        run: |
-          sudo apt-get update
-          sudo apt-get install make gcc jq ca-certificates curl gnupg -y
-          sudo snap install kubectl --classic
-          sudo snap install helm --classic
-
-      - name: Setup Go
-        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
+      - name: Setup worker cluster kinD
+        uses: ./.github/actions/setup-kind-cluster
         with:
-          go-version: ${{ env.GO_VERSION }}
-
-      - name: Get dependencies
-        run: |
-          go get -v -t -d ./...
-
-      - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind delete cluster --name worker || true
-          kind create cluster --name worker --image=kindest/node:v1.31.9
-          kind export kubeconfig --internal --name worker --kubeconfig /tmp/worker.kubeconfig
-          kind delete cluster || true
-          kind create cluster --image=kindest/node:v1.31.9
-
-      - name: Load image
-        run: |
-          mkdir -p $HOME/tmp/ 
-          TMPDIR=$HOME/tmp/ make image-load
+          name: worker
+          k8s-version: ${{ matrix.k8s-version }}
 
-      - name: Cleanup for e2e tests
-        run: |
-          make vela-cli
-          make e2e-cleanup
-          make e2e-setup-core-auth
-
-      - name: Run e2e multicluster tests
-        run: |
-          export PATH=$(pwd)/bin:$PATH
-          make e2e-multicluster-test
-
-      - name: Stop kubevela, get profile
-        run: |
-          make end-e2e-core-shards
+      - name: Setup master cluster kinD
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          k8s-version: ${{ matrix.k8s-version }}
 
-      - name: Upload coverage report
-        uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
+      - name: Run upgrade multicluster tests
+        uses: ./.github/actions/multicluster-test
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
-          files: /tmp/e2e-profile.out,/tmp/e2e_multicluster_test.out
-          flags: e2e-multicluster-test
-          name: codecov-umbrella
+          codecov-enable: true
+          codecov-token: ${{ secrets.CODECOV_TOKEN }}
 
       - name: Clean e2e profile
-        run: rm /tmp/e2e-profile.out
+        run: |
+          if [ -f /tmp/e2e-profile.out ]; then
+            rm /tmp/e2e-profile.out
+            echo "E2E profile cleaned"
+          else
+            echo "E2E profile not found, skipping cleanup"
+          fi
 
       - name: Cleanup image
         if: ${{ always() }}
diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml
index de063b15..ee46361a 100644
--- a/.github/workflows/e2e-test.yml
+++ b/.github/workflows/e2e-test.yml
@@ -53,68 +53,26 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
 
-      - name: Install tools
-        run: |
-          sudo apt-get update
-          sudo apt-get install make gcc jq ca-certificates curl gnupg -y
-          sudo snap install kubectl --classic
-          sudo snap install helm --classic
-
-      - name: Setup Go
-        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
-        with:
-          go-version: ${{ env.GO_VERSION }}
-
-      - name: Get dependencies
-        run: |
-          go get -v -t -d ./...
-
       - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind delete cluster || true
-          kind create cluster --image=kindest/node:v1.31.9
+        uses: ./.github/actions/setup-kind-cluster
 
-      - name: Get Ginkgo
-        run: |
-          go install github.com/onsi/ginkgo/v2/ginkgo@v2.14.0
-
-      - name: Load image
-        run: |
-          mkdir -p $HOME/tmp/
-          TMPDIR=$HOME/tmp/ make image-load
-
-      - name: Run Make
-        run: make
-
-      - name: Prepare for e2e tests
-        run: |
-          make e2e-cleanup
-          make e2e-setup-core
-          helm test -n vela-system kubevela --timeout 5m
-
-      - name: Run api e2e tests
-        run: make e2e-api-test
-
-      - name: Run addons e2e tests
-        run: make e2e-addon-test
-
-      - name: Run e2e tests
-        run: make e2e-test
-
-      - name: Stop kubevela, get profile
-        run: make end-e2e
-
-      - name: Upload coverage report
-        uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
+      # ========================================================================
+      # E2E Test Execution
+      # ========================================================================
+      - name: Run upgrade e2e tests
+        uses: ./.github/actions/e2e-test
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
-          files: /tmp/e2e-profile.out
-          flags: e2etests
-          name: codecov-umbrella
+          codecov-enable: true
+          codecov-token: ${{ secrets.CODECOV_TOKEN }}
 
       - name: Clean e2e profile
-        run: rm /tmp/e2e-profile.out
+        run: |
+          if [ -f /tmp/e2e-profile.out ]; then
+            rm /tmp/e2e-profile.out
+            echo "E2E profile cleaned"
+          else
+            echo "E2E profile not found, skipping cleanup"
+          fi
 
       - name: Cleanup image
         if: ${{ always() }}
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 1de8a4aa..1549f8c0 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -97,28 +97,16 @@ jobs:
         with:
           submodules: true
 
-      - name: Setup Go
-        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
-        with:
-          go-version: ${{ env.GO_VERSION }}
-
+      - name: Setup Env
+        uses: ./.github/actions/env-setup
+        
       - name: Setup node
         uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
         with:
           node-version: "14"
 
-      - name: Cache Go Dependencies
-        uses: actions/cache@v4
-        with:
-          path: .work/pkg
-          key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
-          restore-keys: ${{ runner.os }}-pkg-
-
-      - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind delete cluster --name kind || true
-          kind create cluster --name kind --image=kindest/node:v1.31.9 --kubeconfig ~/.kube/config
+      - name: Setup kinD
+        uses: ./.github/actions/setup-kind-cluster
 
       - name: Run cross-build
         run: make cross-build
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 078126ca..2c700185 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,7 +3,7 @@ name: Release
 on:
   push:
     tags:
-      - 'v*'
+      - "v*"
   workflow_dispatch: {}
 
 permissions:
@@ -26,6 +26,32 @@ jobs:
     outputs:
       hashes: ${{ steps.hash.outputs.hashes }}
     steps:
+      - name: Check disk (before)
+        run: |
+          df -h
+          sudo du -sh /usr/local/lib/android /usr/share/dotnet /opt/ghc || true
+
+      - name: Free Disk Space (Ubuntu)
+        uses: insightsengineering/disk-space-reclaimer@v1
+        with:
+          # this might remove tools that are actually needed,
+          # if set to "true" but frees about 6 GB
+          tools-cache: false
+          # all of these default to true, but feel free to set to
+          # "false" if necessary for your workflow
+          android: true
+          dotnet: true
+          haskell: true
+          large-packages: true
+          swap-storage: true
+          docker-images: true
+
+      # Extra prune in case your job builds/pulls images
+      - name: Deep Docker prune
+        run: |
+          docker system prune -af || true
+          docker builder prune -af || true
+
       - name: Checkout
         uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
         with:
@@ -43,7 +69,7 @@ jobs:
       - name: Install Cosign
         uses: sigstore/cosign-installer@main
         with:
-          cosign-release: 'v2.5.0'
+          cosign-release: "v2.5.0"
 
       - name: Install syft
         uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
@@ -65,6 +91,9 @@ jobs:
           HASHES=$(find dist -type f -exec sha256sum {} \; | base64 -w0)
           echo "hashes=$HASHES" >> "$GITHUB_OUTPUT"
 
+      - name: Check disk (after)
+        run: df -h
+
   upload-plugin-homebrew:
     name: upload-sha256sums
     needs: goreleaser
@@ -103,5 +132,5 @@ jobs:
       actions: read
     uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # has to be sem var
     with:
-      base64-subjects: '${{ needs.goreleaser.outputs.hashes }}'
+      base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
       upload-assets: true
diff --git a/.github/workflows/sdk-test.yml b/.github/workflows/sdk-test.yml
index 02cbd632..b150d7c1 100644
--- a/.github/workflows/sdk-test.yml
+++ b/.github/workflows/sdk-test.yml
@@ -16,11 +16,6 @@ on:
 permissions:
   contents: read
 
-env:
-  # Common versions
-  GO_VERSION: '1.23.8'
-  GOLANGCI_VERSION: 'v1.60.1'
-
 jobs:
   sdk-tests:
     runs-on: ubuntu-22.04
@@ -28,10 +23,8 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
 
-      - name: Setup Go
-        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
-        with:
-          go-version: ${{ env.GO_VERSION }}
+      - name: Setup Env
+        uses: ./.github/actions/env-setup
 
       - name: Install Go tools
         run: |
@@ -39,9 +32,9 @@ jobs:
           make golangci
 
       - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind create cluster --image=kindest/node:v1.31.9
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          name: sdk-test
 
       - name: Build CLI
         run: make vela-cli
diff --git a/.github/workflows/sync-api.yml b/.github/workflows/sync-api.yml
index 359d92e4..f5f93877 100644
--- a/.github/workflows/sync-api.yml
+++ b/.github/workflows/sync-api.yml
@@ -10,21 +10,16 @@ on:
 permissions:
   contents: read
 
-env:
-  GO_VERSION: '1.23.8'
-
 jobs:
   sync-core-api:
     runs-on: ubuntu-22.04
     steps:
-      - name: Set up Go
-        uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
-        with:
-          go-version: ${{ env.GO_VERSION }}
-
       - name: Check out code into the Go module directory
         uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
 
+      - name: Setup Env
+        uses: ./.github/actions/env-setup
+
       - name: Get the version
         id: get_version
         run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/sync-sdk.yaml b/.github/workflows/sync-sdk.yaml
index ef21596a..64738572 100644
--- a/.github/workflows/sync-sdk.yaml
+++ b/.github/workflows/sync-sdk.yaml
@@ -14,36 +14,33 @@ on:
 permissions:
   contents: read
 
-env:
-  GO_VERSION: '1.23.8'
-
 jobs:
   sync_sdk:
     runs-on: ubuntu-22.04
     steps:
-      - name: Set up Go
-        uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
-        with:
-          go-version: ${{ env.GO_VERSION }}
 
       - name: Check out code into the Go module directory
         uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
 
-      - name: Get the version
-        id: get_version
-        run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
-
-      - name: Get dependencies
-        run: |
-          go get -v -t -d ./...
+      - name: Env setup
+        uses: ./.github/actions/env-setup
 
       - name: Install Go tools
         run: |
           make goimports
-          
+
       - name: Build CLI
         run: make vela-cli
 
+      - name: Setup KinD
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          name: sync-sdk
+
+      - name: Get the version
+        id: get_version
+        run: echo "VERSION=${GITHUB_REF}" >> $GITHUB_OUTPUT
+
       - name: Sync SDK to kubevela/kubevela-go-sdk
         run: bash ./hack/sdk/sync.sh
         env:
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index ed78a19b..4e24a315 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -14,10 +14,6 @@ on:
 permissions:
   contents: read
 
-env:
-  # Common versions
-  GO_VERSION: "1.23.8"
-
 jobs:
   detect-noop:
     permissions:
@@ -41,41 +37,19 @@ jobs:
     if: needs.detect-noop.outputs.noop != 'true'
 
     steps:
-      - name: Set up Go
-        uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
-        with:
-          go-version: ${{ env.GO_VERSION }}
-
       - name: Check out code into the Go module directory
         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
         with:
           submodules: true
 
-      - name: Cache Go Dependencies
-        uses: actions/cache@v4
-        with:
-          path: .work/pkg
-          key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
-          restore-keys: ${{ runner.os }}-pkg-
-
-      - name: Install ginkgo
-        run: |
-          sudo sed -i 's/azure\.//' /etc/apt/sources.list
-          sudo apt-get update
-          sudo apt-get install -y golang-ginkgo-dev
-
-      - name: Setup KinD
-        run: |
-          go install sigs.k8s.io/kind@v0.29.0
-          kind create cluster --image=kindest/node:v1.31.9
+      - name: Setup Env
+        uses: ./.github/actions/env-setup
 
-      - name: Run Make test
-        run: make test
+      - name: Setup KinD with Kubernetes
+        uses: ./.github/actions/setup-kind-cluster
 
-      - name: Upload coverage report
-        uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 #v5.4.3
+      - name: Run unit tests
+        uses: ./.github/actions/unit-test
         with:
-          token: ${{ secrets.CODECOV_TOKEN }}
-          files: ./coverage.txt
-          flags: core-unittests
-          name: codecov-umbrella
+          codecov-enable: true
+          codecov-token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/upgrade-e2e-multicluster-test.yml b/.github/workflows/upgrade-e2e-multicluster-test.yml
new file mode 100644
index 00000000..b120efac
--- /dev/null
+++ b/.github/workflows/upgrade-e2e-multicluster-test.yml
@@ -0,0 +1,98 @@
+# =============================================================================
+# E2E Upgrade Multicluster Test Workflow
+# =============================================================================
+# This workflow performs end-to-end testing for KubeVela multicluster upgrades.
+# It tests the upgrade path from the latest released version to the current
+# development branch across multiple Kubernetes versions.
+#
+# Test Flow:
+# 1. Install latest KubeVela release
+# 2. Build and upgrade to current development version
+# 3. Run multicluster e2e tests to verify functionality
+# =============================================================================
+
+name: E2E Upgrade Multicluster Test
+
+# =============================================================================
+# Trigger Configuration
+# =============================================================================
+on:
+  # Trigger on pull requests targeting main branches
+  pull_request:
+    branches:
+      - master
+      - release-*
+
+  # Allow manual workflow execution
+  workflow_dispatch: {}
+
+# =============================================================================
+# Security Configuration
+# =============================================================================
+permissions:
+  contents: read  # Read-only access to repository contents
+
+# =============================================================================
+# Global Environment Variables
+# =============================================================================
+env:
+  GO_VERSION: '1.23.8'  # Go version for building and testing
+
+# =============================================================================
+# Job Definitions
+# =============================================================================
+jobs:
+  upgrade-multicluster-tests:
+    name: Upgrade Multicluster Tests
+    runs-on: ubuntu-22.04
+    if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
+    timeout-minutes: 60  # Prevent hanging jobs
+
+    # ==========================================================================
+    # Matrix Strategy - Test against multiple Kubernetes versions
+    # ==========================================================================
+    strategy:
+      fail-fast: false  # Continue testing other versions if one fails
+      matrix:
+        k8s-version: ['v1.31.9']
+
+    # ==========================================================================
+    # Concurrency Control - Prevent overlapping runs
+    # ==========================================================================
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
+      cancel-in-progress: true
+
+    steps:
+      # ========================================================================
+      # Environment Setup
+      # ========================================================================
+
+      - name: Check out repository
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
+
+      # ========================================================================
+      # Kubernetes Cluster Setup
+      # ========================================================================
+
+      - name: Setup worker cluster kinD
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          name: worker
+
+      - name: Setup KinD master clusters for multicluster testing
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          k8s-version: ${{ matrix.k8s-version }}
+
+      - name: Deploy latest release
+        uses: ./.github/actions/deploy-latest-release
+
+      - name: Upgrade from current branch
+        uses: ./.github/actions/deploy-current-branch
+
+      - name: Run upgarde multicluster tests
+        uses: ./.github/actions/multicluster-test
+        with:
+          codecov-enable: false
+          codecov-token: ''
\ No newline at end of file
diff --git a/.github/workflows/upgrade-e2e-test.yml b/.github/workflows/upgrade-e2e-test.yml
new file mode 100644
index 00000000..32fc3d8e
--- /dev/null
+++ b/.github/workflows/upgrade-e2e-test.yml
@@ -0,0 +1,102 @@
+# =============================================================================
+# Upgrade E2E Test Workflow
+# =============================================================================
+# This workflow performs comprehensive end-to-end testing for KubeVela upgrades.
+# It validates the upgrade path from the latest stable release to the current
+# development version by running multiple test suites including API, addon,
+# and general e2e tests.
+#
+# Test Flow:
+# 1. Install latest KubeVela release
+# 2. Build and upgrade to current development version
+# 3. Run comprehensive e2e test suites (API, addon, general)
+# 4. Validate upgrade functionality and compatibility
+# =============================================================================
+
+name: Upgrade E2E Test
+
+# =============================================================================
+# Trigger Configuration
+# =============================================================================
+on:
+  # Trigger on pull requests targeting main branches
+  pull_request:
+    branches:
+      - master
+      - release-*
+
+  # Allow manual workflow execution
+  workflow_dispatch: {}
+
+# =============================================================================
+# Environment Variables
+# =============================================================================
+env:
+  GO_VERSION: '1.23.8'
+
+# =============================================================================
+# Security Configuration
+# =============================================================================
+permissions:
+  contents: read  # Read-only access to repository contents
+
+# =============================================================================
+# Job Definitions
+# =============================================================================
+jobs:
+  upgrade-tests:
+    name: Upgrade E2E Tests
+    runs-on: ubuntu-22.04
+    if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
+    timeout-minutes: 90  # Extended timeout for comprehensive e2e testing
+
+    # ==========================================================================
+    # Matrix Strategy - Test against multiple Kubernetes versions
+    # ==========================================================================
+    strategy:
+      fail-fast: false  # Continue testing other versions if one fails
+      matrix:
+        k8s-version: ['v1.31.9']
+
+    # ==========================================================================
+    # Concurrency Control - Prevent overlapping runs
+    # ==========================================================================
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
+      cancel-in-progress: true
+
+    steps:
+      # ========================================================================
+      # Repository Setup
+      # ========================================================================
+      - name: Check out code
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
+
+      # ========================================================================
+      # Kubernetes Cluster Setup
+      # ========================================================================
+      - name: Setup KinD with Kubernetes ${{ matrix.k8s-version }}
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          k8s-version: ${{ matrix.k8s-version }}
+
+      - name: Build vela CLI
+        run: make vela-cli
+
+      - name: Build kubectl-vela plugin
+        run: make kubectl-vela
+
+      - name: Install kustomize
+        run: make kustomize
+
+      - name: Deploy latest release
+        uses: ./.github/actions/deploy-latest-release
+
+      - name: Upgrade from current branch
+        uses: ./.github/actions/deploy-current-branch
+
+      # ========================================================================
+      # E2E Test Execution
+      # ========================================================================
+      - name: Run upgrade e2e tests
+        uses: ./.github/actions/e2e-test
\ No newline at end of file
diff --git a/.github/workflows/upgrade-unit-test.yml b/.github/workflows/upgrade-unit-test.yml
new file mode 100644
index 00000000..bc98a78a
--- /dev/null
+++ b/.github/workflows/upgrade-unit-test.yml
@@ -0,0 +1,83 @@
+# =============================================================================
+# Upgrade Unit Test Workflow
+# =============================================================================
+# This workflow performs unit testing for KubeVela upgrades by:
+# 1. Installing the latest stable KubeVela release
+# 2. Building and upgrading to the current development version
+# 3. Running unit tests to validate the upgrade functionality
+# =============================================================================
+
+name: Upgrade Unit Test
+
+# =============================================================================
+# Trigger Configuration
+# =============================================================================
+on:
+  # Trigger on pull requests targeting main and release branches
+  pull_request:
+    branches:
+      - master
+      - release-*
+
+  # Allow manual workflow execution
+  workflow_dispatch: {}
+
+# =============================================================================
+# Security Configuration
+# =============================================================================
+permissions:
+  contents: read  # Read-only access to repository contents
+
+# =============================================================================
+# Job Definitions
+# =============================================================================
+jobs:
+  upgrade-tests:
+    name: Upgrade Unit Tests
+    runs-on: ubuntu-22.04
+    if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
+    timeout-minutes: 45  # Prevent hanging jobs
+
+    # ==========================================================================
+    # Matrix Strategy - Test against multiple Kubernetes versions
+    # ==========================================================================
+    strategy:
+      fail-fast: false  # Continue testing other versions if one fails
+      matrix:
+        k8s-version: ['v1.31.9']
+
+    # ==========================================================================
+    # Concurrency Control - Prevent overlapping runs
+    # ==========================================================================
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
+      cancel-in-progress: true
+
+    steps:
+      # ========================================================================
+      # Environment Setup
+      # ========================================================================
+
+      - name: Check out code
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
+
+      # ========================================================================
+      # Kubernetes Cluster Setup
+      # ========================================================================
+
+      - name: Setup KinD with Kubernetes ${{ matrix.k8s-version }}
+        uses: ./.github/actions/setup-kind-cluster
+        with:
+          k8s-version: ${{ matrix.k8s-version }}
+
+      - name: Deploy latest release
+        uses: ./.github/actions/deploy-latest-release
+
+      - name: Upgrade from current branch
+        uses: ./.github/actions/deploy-current-branch
+
+      - name: Run unit tests
+        uses: ./.github/actions/unit-test
+        with:
+          codecov-enable: false
+          codecov-token: ''
diff --git a/.github/workflows/webhook-upgrade-validation.yml b/.github/workflows/webhook-upgrade-validation.yml
new file mode 100644
index 00000000..5e8bceb1
--- /dev/null
+++ b/.github/workflows/webhook-upgrade-validation.yml
@@ -0,0 +1,165 @@
+name: Webhook Upgrade Validation
+
+on:
+  push:
+    branches:
+      - master
+      - release-*
+    tags:
+      - v*
+  workflow_dispatch: {}
+  pull_request:
+    branches:
+      - master
+      - release-*
+
+permissions:
+  contents: read
+
+env:
+  GO_VERSION: '1.23.8'
+
+jobs:
+  webhook-upgrade-check:
+    runs-on: ubuntu-22.04
+    timeout-minutes: 30
+    steps:
+      - name: Check out code into the Go module directory
+        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
+
+      - name: Setup Env
+        uses: ./.github/actions/env-setup
+
+      - name: Setup KinD
+        run: |
+          go install sigs.k8s.io/kind@v0.29.0
+          kind delete cluster || true
+          kind create cluster --image=kindest/node:v1.31.9
+
+      - name: Install KubeVela CLI
+        run: curl -fsSL https://kubevela.io/script/install.sh | bash
+
+      - name: Install KubeVela baseline
+        run: |
+          vela install --set featureGates.enableCueValidation=true
+          kubectl wait --namespace vela-system --for=condition=Available deployment/kubevela-vela-core --timeout=300s
+
+      - name: Prepare failing chart changes
+        run: |
+          cat <<'CHART' > charts/vela-core/templates/defwithtemplate/resource.yaml
+          # Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
+          # Definition source cue file: vela-templates/definitions/internal/resource.cue
+          apiVersion: core.oam.dev/v1beta1
+          kind: TraitDefinition
+          metadata:
+            annotations:
+              definition.oam.dev/description: Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'
+            name: resource
+            namespace: {{ include "systemDefinitionNamespace" . }}
+          spec:
+            appliesToWorkloads:
+              - deployments.apps
+              - statefulsets.apps
+              - daemonsets.apps
+              - jobs.batch
+              - cronjobs.batch
+            podDisruptive: true
+            schematic:
+              cue:
+                template: |2
+                  let resourceContent = {
+                    resources: {
+                      if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ {
+                        // +patchStrategy=retainKeys
+                        requests: {
+                          cpu:    parameter.cpu
+                          memory: parameter.memory
+                        }
+                        // +patchStrategy=retainKeys
+                        limits: {
+                          cpu:    parameter.cpu
+                          memory: parameter.memory
+                        }
+                      }
+                      if parameter.requests != _|_ {
+                        // +patchStrategy=retainKeys
+                        requests: {
+                          cpu:    parameter.requests.cpu
+                          memory: parameter.requests.memory
+                        }
+                      }
+                      if parameter.limits != _|_ {
+                        // +patchStrategy=retainKeys
+                        limits: {
+                          cpu:    parameter.limits.cpu
+                          memory: parameter.limits.memory
+                        }
+                      }
+                    }
+                  }
+                  if context.output.spec != _|_ if context.output.spec.template != _|_ {
+                    patch: spec: template: spec: {
+                      // +patchKey=name
+                      containers: [resourceContent]
+                    }
+                  }
+                  if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ {
+                    patch: spec: jobTemplate: spec: template: spec: {
+                      // +patchKey=name
+                      containers: [resourceContent]
+                    }
+                  }
+                  parameter: {
+                    // +usage=Specify the amount of cpu for requests and limits
+                    cpu?: *1 | number | string
+                    // +usage=Specify the amount of memory for requests and limits
+                    memory?: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
+                    // +usage=Specify the resources in requests
+                    requests?: {
+                      // +usage=Specify the amount of cpu for requests
+                      cpu: *1 | number | string
+                      // +usage=Specify the amount of memory for requests
+                      memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
+                    }
+                    // +usage=Specify the resources in limits
+                    limits?: {
+                      // +usage=Specify the amount of cpu for limits
+                      cpu: *1 | number | string
+                      // +usage=Specify the amount of memory for limits
+                      memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
+                    }
+                  }
+
+      - name: Load image
+        run: |
+          mkdir -p $HOME/tmp/
+          TMPDIR=$HOME/tmp/ make image-load
+
+      - name: Run Helm upgrade (expected to fail)
+        run: |
+          set +e
+          helm upgrade \
+            --set image.repository=vela-core-test \
+            --set image.tag=$(git rev-parse --short HEAD) \
+            --set featureGates.enableCueValidation=true \
+            --wait kubevela ./charts/vela-core --debug -n vela-system
+          status=$?
+          echo "Helm upgrade exit code: ${status}"
+          if [ $status -eq 0 ]; then
+            echo "Expected helm upgrade to fail" >&2
+            exit 1
+          fi
+          echo "Helm upgrade failed as expected"
+
+      - name: Dump webhook configurations
+        if: ${{ always() }}
+        run: |
+          kubectl get mutatingwebhookconfiguration kubevela-vela-core-admission -o yaml
+          kubectl get validatingwebhookconfiguration kubevela-vela-core-admission -o yaml
+
+      - name: Verify webhook validation remains active
+        run: ginkgo -v --focus-file requiredparam_validation_test.go ./test/e2e-test
+
+      - name: Cleanup kind cluster
+        if: ${{ always() }}
+        run: kind delete cluster --name kind
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 893138b4..97d51584 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,14 @@ vendor/
 .vscode
 .history
 
+# Debug binaries generated by VS Code/Delve
+__debug_bin*
+*/__debug_bin*
+
+# Webhook certificates generated at runtime
+k8s-webhook-server/
+options.go.bak 
+
 pkg/test/vela
 config/crd/bases
 _tmp/
diff --git a/app.yaml b/app.yaml
deleted file mode 100644
index e69de29b..00000000
diff --git a/charts/vela-core/README.md b/charts/vela-core/README.md
index 00664e1e..8b078362 100644
--- a/charts/vela-core/README.md
+++ b/charts/vela-core/README.md
@@ -100,6 +100,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
 | `featureGates.disableWorkflowContextConfigMapCache`          | disable the workflow context's configmap informer cache                                                                                                                                                                          | `true`  |
 | `featureGates.enableCueValidation`                           | enable the strict cue validation for cue required parameter fields                                                                                                                                                               | `false` |
 | `featureGates.enableApplicationStatusMetrics`                | enable application status metrics and structured logging                                                                                                                                                                         | `false` |
+| `featureGates.validateResourcesExist`                        | enable webhook validation to check if resource types referenced in definition templates exist in the cluster                                                                                                                     | `false` |
 
 ### MultiCluster parameters
 
@@ -147,6 +148,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
 | `affinity`                                     | Affinity                                                                                                                                                           | `{}`                 |
 | `rbac.create`                                  | Specifies whether a RBAC role should be created                                                                                                                    | `true`               |
 | `logDebug`                                     | Enable debug logs for development purpose                                                                                                                          | `false`              |
+| `devLogs`                                      | Enable formatted logging support for development purpose                                                                                                           | `false`              |
 | `logFilePath`                                  | If non-empty, write log files in this path                                                                                                                         | `""`                 |
 | `logFileMaxSize`                               | Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited.                                         | `1024`               |
 | `kubeClient.qps`                               | The qps for reconcile clients                                                                                                                                      | `400`                |
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/clusterrole.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/clusterrole.yaml
index 96b0ba33..446848df 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/clusterrole.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/clusterrole.yaml
@@ -4,7 +4,7 @@ kind: ClusterRole
 metadata:
   name:  {{ template "kubevela.fullname" . }}-admission
   annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
index 649bb713..85cc592b 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
@@ -4,7 +4,7 @@ kind: ClusterRoleBinding
 metadata:
   name:  {{ template "kubevela.fullname" . }}-admission
   annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
index eb2e9847..55af070f 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
@@ -5,7 +5,7 @@ metadata:
   name: {{ template "kubevela.fullname" . }}-admission-patch
   namespace: {{ .Release.Namespace }}
   annotations:
-    "helm.sh/hook": post-install,post-upgrade
+    "helm.sh/hook": post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission-patch
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/role.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/role.yaml
index cf3d7dd3..535c3221 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/role.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/role.yaml
@@ -5,7 +5,7 @@ metadata:
   name:  {{ template "kubevela.fullname" . }}-admission
   namespace: {{ .Release.Namespace }}
   annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/rolebinding.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/rolebinding.yaml
index cffdc0f5..84259e9c 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/rolebinding.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/rolebinding.yaml
@@ -5,7 +5,7 @@ metadata:
   name:  {{ template "kubevela.fullname" . }}-admission
   namespace: {{ .Release.Namespace }}
   annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission
diff --git a/charts/vela-core/templates/admission-webhooks/job-patch/serviceaccount.yaml b/charts/vela-core/templates/admission-webhooks/job-patch/serviceaccount.yaml
index 4e56267d..fe35c96c 100644
--- a/charts/vela-core/templates/admission-webhooks/job-patch/serviceaccount.yaml
+++ b/charts/vela-core/templates/admission-webhooks/job-patch/serviceaccount.yaml
@@ -5,7 +5,7 @@ metadata:
   name:  {{ template "kubevela.fullname" . }}-admission
   namespace: {{ .Release.Namespace }}
   annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
+    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
     "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
   labels:
     app: {{ template "kubevela.name" . }}-admission
diff --git a/charts/vela-core/templates/admission-webhooks/mutatingWebhookConfiguration.yaml b/charts/vela-core/templates/admission-webhooks/mutatingWebhookConfiguration.yaml
index 73608fcb..b0b0b491 100644
--- a/charts/vela-core/templates/admission-webhooks/mutatingWebhookConfiguration.yaml
+++ b/charts/vela-core/templates/admission-webhooks/mutatingWebhookConfiguration.yaml
@@ -1,4 +1,14 @@
 {{- if .Values.admissionWebhooks.enabled -}}
+{{- /* Preserve existing caBundle on upgrade to avoid breaking admission if hooks fail. */}}
+{{- $mName := printf "%s-admission" (include "kubevela.fullname" .) -}}
+{{- $existing := (lookup "admissionregistration.k8s.io/v1" "MutatingWebhookConfiguration" "" $mName) -}}
+{{- $vals := dict "apps" "" "comps" "" -}}
+{{- if $existing -}}
+{{- range $existing.webhooks -}}
+{{- if eq .name "mutating.core.oam.dev.v1beta1.applications" -}}{{- $_ := set $vals "apps" .clientConfig.caBundle -}}{{- end -}}
+{{- if eq .name "mutating.core.oam-dev.v1beta1.componentdefinitions" -}}{{- $_ := set $vals "comps" .clientConfig.caBundle -}}{{- end -}}
+{{- end -}}
+{{- end -}}
 apiVersion: admissionregistration.k8s.io/v1
 kind: MutatingWebhookConfiguration
 metadata:
@@ -10,7 +20,7 @@ metadata:
   {{- end }}
 webhooks:
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "apps") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
@@ -36,7 +46,7 @@ webhooks:
         resources:
           - applications
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "comps") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
diff --git a/charts/vela-core/templates/admission-webhooks/validatingWebhookConfiguration.yaml b/charts/vela-core/templates/admission-webhooks/validatingWebhookConfiguration.yaml
index 270aed33..11ad4bbe 100644
--- a/charts/vela-core/templates/admission-webhooks/validatingWebhookConfiguration.yaml
+++ b/charts/vela-core/templates/admission-webhooks/validatingWebhookConfiguration.yaml
@@ -1,4 +1,16 @@
 {{- if .Values.admissionWebhooks.enabled -}}
+{{- /* Preserve existing caBundle on upgrade to avoid breaking admission if hooks fail. */}}
+{{- $vName := printf "%s-admission" (include "kubevela.fullname" .) -}}
+{{- $existing := (lookup "admissionregistration.k8s.io/v1" "ValidatingWebhookConfiguration" "" $vName) -}}
+{{- $vals := dict "traits" "" "apps" "" "comps" "" "policies" "" -}}
+{{- if $existing -}}
+{{- range $existing.webhooks -}}
+{{- if eq .name "validating.core.oam.dev.v1beta1.traitdefinitions" -}}{{- $_ := set $vals "traits" .clientConfig.caBundle -}}{{- end -}}
+{{- if eq .name "validating.core.oam.dev.v1beta1.applications" -}}{{- $_ := set $vals "apps" .clientConfig.caBundle -}}{{- end -}}
+{{- if eq .name "validating.core.oam-dev.v1beta1.componentdefinitions" -}}{{- $_ := set $vals "comps" .clientConfig.caBundle -}}{{- end -}}
+{{- if eq .name "validating.core.oam-dev.v1beta1.policydefinitions" -}}{{- $_ := set $vals "policies" .clientConfig.caBundle -}}{{- end -}}
+{{- end -}}
+{{- end -}}
 apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
@@ -10,7 +22,7 @@ metadata:
   {{- end }}
 webhooks:
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "traits") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
@@ -37,7 +49,7 @@ webhooks:
           - traitdefinitions
     timeoutSeconds: 5
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "apps") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
@@ -63,7 +75,7 @@ webhooks:
         resources:
           - applications
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "comps") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
@@ -89,7 +101,7 @@ webhooks:
         resources:
           - componentdefinitions
   - clientConfig:
-      caBundle: Cg==
+      caBundle: {{ default "Cg==" (get $vals "policies") }}
       service:
         name: {{ template "kubevela.name" . }}-webhook
         namespace: {{ .Release.Namespace }}
@@ -114,4 +126,30 @@ webhooks:
           - UPDATE
         resources:
           - policydefinitions
+  - clientConfig:
+      caBundle: Cg==
+      service:
+        name: {{ template "kubevela.name" . }}-webhook
+        namespace: {{ .Release.Namespace }}
+        path: /validating-core-oam-dev-v1beta1-workflowstepdefinitions
+    {{- if .Values.admissionWebhooks.patch.enabled  }}
+    failurePolicy: Ignore
+    {{- else }}
+    failurePolicy: Fail
+    {{- end }}
+    name: validating.core.oam-dev.v1beta1.workflowstepdefinitions
+    sideEffects: None
+    admissionReviewVersions:
+      - v1beta1
+      - v1
+    rules:
+      - apiGroups:
+          - core.oam.dev
+        apiVersions:
+          - v1beta1
+        operations:
+          - CREATE
+          - UPDATE
+        resources:
+          - workflowstepdefinitions
 {{- end -}}
diff --git a/charts/vela-core/templates/kubevela-controller.yaml b/charts/vela-core/templates/kubevela-controller.yaml
index bcf8a0e1..746ba142 100644
--- a/charts/vela-core/templates/kubevela-controller.yaml
+++ b/charts/vela-core/templates/kubevela-controller.yaml
@@ -313,6 +313,7 @@ spec:
             - "--feature-gates=DisableWorkflowContextConfigMapCache={{- .Values.featureGates.disableWorkflowContextConfigMapCache | toString -}}"
             - "--feature-gates=EnableCueValidation={{- .Values.featureGates.enableCueValidation | toString -}}"
             - "--feature-gates=EnableApplicationStatusMetrics={{- .Values.featureGates.enableApplicationStatusMetrics | toString -}}"
+            - "--feature-gates=ValidateResourcesExist={{- .Values.featureGates.validateResourcesExist | toString -}}"
             - "--feature-gates=ValidateDefinitionPermissions={{ .Values.authorization.definitionValidationEnabled | toString -}}"
             {{ if .Values.authentication.enabled }}
             {{ if .Values.authentication.withUser }}
@@ -327,6 +328,7 @@ spec:
             - "--feature-gates=ValidateComponentWhenSharding={{- .Values.featureGates.validateComponentWhenSharding | toString -}}"
             - "--feature-gates=DisableWebhookAutoSchedule={{- .Values.featureGates.disableWebhookAutoSchedule | toString -}}"
             {{ end }}
+            - "--dev-logs={{ .Values.devLogs }}"
           image: {{ .Values.imageRegistry }}{{ .Values.image.repository }}:{{ .Values.image.tag }}
           imagePullPolicy: {{ quote .Values.image.pullPolicy }}
           resources:
diff --git a/charts/vela-core/values.yaml b/charts/vela-core/values.yaml
index f659035c..8b2d5fdb 100644
--- a/charts/vela-core/values.yaml
+++ b/charts/vela-core/values.yaml
@@ -125,6 +125,7 @@ optimize:
 ##@param featureGates.disableWorkflowContextConfigMapCache disable the workflow context's configmap informer cache
 ##@param featureGates.enableCueValidation enable the strict cue validation for cue required parameter fields
 ##@param featureGates.enableApplicationStatusMetrics enable application status metrics and structured logging
+##@param featureGates.validateResourcesExist enable webhook validation to check if resource types referenced in definition templates exist in the cluster
 ##@param
 featureGates:
   gzipResourceTracker: false
@@ -142,6 +143,7 @@ featureGates:
   disableWorkflowContextConfigMapCache: true
   enableCueValidation: false
   enableApplicationStatusMetrics: false
+  validateResourcesExist: false
 
 ## @section MultiCluster parameters
 
@@ -256,6 +258,9 @@ rbac:
 ## @param logDebug Enable debug logs for development purpose
 logDebug: false
 
+## @param devLogs Enable formatted logging support for development purpose
+devLogs: false
+
 ## @param logFilePath If non-empty, write log files in this path
 logFilePath: ""
 
diff --git a/cmd/core/app/color_writer.go b/cmd/core/app/color_writer.go
new file mode 100644
index 00000000..dd1fc51a
--- /dev/null
+++ b/cmd/core/app/color_writer.go
@@ -0,0 +1,580 @@
+/*
+Copyright 2022 The KubeVela Authors.
+
+Licensed 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 app
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"io"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+	"sync"
+	"unicode"
+)
+
+const (
+	ansiReset    = "\x1b[0m"
+	ansiDate     = "\x1b[36m"
+	ansiInfo     = "\x1b[32m"
+	ansiWarn     = "\x1b[33m"
+	ansiError    = "\x1b[31m"
+	ansiFatal    = "\x1b[35m"
+	ansiDebug    = "\x1b[34m"
+	ansiThread   = "\x1b[34m"
+	ansiLocation = "\x1b[93m"
+	ansiMessage  = "\x1b[97m"
+	ansiKey      = "\x1b[96m"
+	ansiValue    = "\x1b[37m"
+)
+
+var methodPatterns = []*regexp.Regexp{
+	regexp.MustCompile(`(?i)\b(?:caller|func|function|method)\s*[:=]\s*"?([a-zA-Z0-9_./()*-]+)`),
+}
+
+var srcIdx = newSourceIndex()
+
+type colorWriter struct {
+	dst io.Writer
+	mu  sync.Mutex
+	buf bytes.Buffer
+}
+
+func newColorWriter(dst io.Writer) io.Writer {
+	return &colorWriter{dst: dst}
+}
+
+func (w *colorWriter) Write(p []byte) (int, error) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+
+	written := 0
+	for len(p) > 0 {
+		idx := bytes.IndexByte(p, '\n')
+		if idx == -1 {
+			_, _ = w.buf.Write(p)
+			written += len(p)
+			break
+		}
+		_, _ = w.buf.Write(p[:idx])
+		if err := w.flushLineLocked(); err != nil {
+			written += idx
+			return written, err
+		}
+		if _, err := w.dst.Write([]byte{'\n'}); err != nil {
+			written += idx + 1
+			return written, err
+		}
+		p = p[idx+1:]
+		written += idx + 1
+	}
+	return written, nil
+}
+
+func (w *colorWriter) flushLineLocked() error {
+	if w.buf.Len() == 0 {
+		return nil
+	}
+	line := w.buf.String()
+	w.buf.Reset()
+	_, err := io.WriteString(w.dst, formatColoredLine(line))
+	return err
+}
+
+func formatColoredLine(line string) string {
+	if len(line) == 0 {
+		return line
+	}
+	severity := line[0]
+	rest := line[1:]
+	headerEnd := strings.IndexByte(rest, ']')
+	if headerEnd == -1 {
+		return line
+	}
+	header := rest[:headerEnd]
+	remainder := strings.TrimSpace(rest[headerEnd+1:])
+	fields := strings.Fields(header)
+	if len(fields) < 4 {
+		return line
+	}
+
+	date := fields[0]
+	ts := fields[1]
+	pid := strings.TrimSpace(fields[2])
+	rawLocation := strings.Join(fields[3:], " ")
+	level, levelColor := mapSeverity(severity)
+	location := buildLocation(rawLocation, remainder)
+
+	sb := strings.Builder{}
+	sb.Grow(len(line) + 32)
+
+	sb.WriteString(ansiDate)
+	sb.WriteString("[")
+	sb.WriteString(formatTimestamp(date, ts))
+	sb.WriteString("]")
+	sb.WriteString(ansiReset)
+	sb.WriteString(" ")
+
+	sb.WriteString(levelColor)
+	sb.WriteString("[")
+	sb.WriteString(fmt.Sprintf("%-5s", level))
+	sb.WriteString("]")
+	sb.WriteString(ansiReset)
+	sb.WriteString(" ")
+
+	sb.WriteString(ansiThread)
+	sb.WriteString("[")
+	sb.WriteString(pid)
+	sb.WriteString("]")
+	sb.WriteString(ansiReset)
+	sb.WriteString(" ")
+
+	sb.WriteString(ansiLocation)
+	sb.WriteString("[")
+	sb.WriteString(location)
+	sb.WriteString("]")
+	sb.WriteString(ansiReset)
+
+	if remainder != "" {
+		msg, fields := splitMessageAndFields(remainder)
+		if msg != "" {
+			sb.WriteString(" ")
+			sb.WriteString(ansiMessage)
+			sb.WriteString(msg)
+			sb.WriteString(ansiReset)
+		}
+		for _, field := range fields {
+			sb.WriteString(" ")
+			sb.WriteString(ansiKey)
+			sb.WriteString(field.key)
+			sb.WriteString(ansiReset)
+			sb.WriteString("=")
+			sb.WriteString(ansiValue)
+			sb.WriteString(field.renderValue())
+			sb.WriteString(ansiReset)
+		}
+	}
+
+	return sb.String()
+}
+
+func mapSeverity(s byte) (string, string) {
+	switch s {
+	case 'I':
+		return "INFO", ansiInfo
+	case 'W':
+		return "WARN", ansiWarn
+	case 'E':
+		return "ERROR", ansiError
+	case 'F':
+		return "FATAL", ansiFatal
+	case 'D':
+		return "DEBUG", ansiDebug
+	default:
+		return string(s), ansiDebug
+	}
+}
+
+func formatTimestamp(date, ts string) string {
+	if len(date) == 4 {
+		return fmt.Sprintf("%s-%s %s", date[:2], date[2:], trimMicros(ts))
+	}
+	return strings.TrimSpace(date + " " + trimMicros(ts))
+}
+
+func trimMicros(ts string) string {
+	if dot := strings.IndexByte(ts, '.'); dot != -1 && len(ts) > dot+4 {
+		return ts[:dot+4]
+	}
+	return ts
+}
+
+func buildLocation(rawLocation, remainder string) string {
+	file, line := splitFileAndLine(rawLocation)
+	method := lookupMethod(file, line)
+	if method == "" {
+		method = extractMethodName(remainder)
+	}
+	if file == "" {
+		return rawLocation
+	}
+	if method == "" {
+		if line != "" {
+			return fmt.Sprintf("%s:%s", file, line)
+		}
+		return file
+	}
+	if line == "" {
+		return fmt.Sprintf("%s:%s", file, method)
+	}
+	return fmt.Sprintf("%s:%s:%s", file, method, line)
+}
+
+func splitFileAndLine(raw string) (string, string) {
+	trimmed := strings.TrimSpace(raw)
+	if trimmed == "" {
+		return "", ""
+	}
+	lastColon := strings.LastIndex(trimmed, ":")
+	if lastColon == -1 {
+		return trimmed, ""
+	}
+	return strings.TrimSpace(trimmed[:lastColon]), strings.TrimSpace(trimmed[lastColon+1:])
+}
+
+type kvField struct {
+	key    string
+	value  string
+	quoted bool
+}
+
+func (f kvField) renderValue() string {
+	if f.quoted {
+		return fmt.Sprintf("\"%s\"", f.value)
+	}
+	return f.value
+}
+
+func splitMessageAndFields(s string) (string, []kvField) {
+	s = strings.TrimSpace(s)
+	if s == "" {
+		return "", nil
+	}
+	idx := findFirstKVIndex(s)
+	if idx == -1 {
+		return s, nil
+	}
+	msg := strings.TrimSpace(s[:idx])
+	fields := parseKeyValues(s[idx:])
+	return msg, fields
+}
+
+func findFirstKVIndex(s string) int {
+	inQuotes := false
+	for i := 0; i < len(s); i++ {
+		ch := s[i]
+		if ch == '"' {
+			if i == 0 || s[i-1] != '\\' {
+				inQuotes = !inQuotes
+			}
+			continue
+		}
+		if inQuotes {
+			continue
+		}
+		if ch == '=' {
+			keyEnd := i
+			keyStart := keyEnd - 1
+			for keyStart >= 0 && !unicode.IsSpace(rune(s[keyStart])) {
+				keyStart--
+			}
+			key := strings.TrimSpace(s[keyStart+1 : keyEnd])
+			if isValidKey(key) {
+				return keyStart + 1
+			}
+		}
+	}
+	return -1
+}
+
+func parseKeyValues(s string) []kvField {
+	fields := make([]kvField, 0)
+	i := 0
+	for i < len(s) {
+		for i < len(s) && unicode.IsSpace(rune(s[i])) {
+			i++
+		}
+		if i >= len(s) {
+			break
+		}
+		keyStart := i
+		for i < len(s) && s[i] != '=' && !unicode.IsSpace(rune(s[i])) {
+			i++
+		}
+		keyEnd := i
+		for keyEnd > keyStart && unicode.IsSpace(rune(s[keyEnd-1])) {
+			keyEnd--
+		}
+		if i >= len(s) || s[i] != '=' {
+			for i < len(s) && !unicode.IsSpace(rune(s[i])) {
+				i++
+			}
+			continue
+		}
+		key := s[keyStart:keyEnd]
+		if !isValidKey(key) {
+			i++
+			continue
+		}
+		i++
+		for i < len(s) && unicode.IsSpace(rune(s[i])) {
+			i++
+		}
+		if i >= len(s) {
+			fields = append(fields, kvField{key: key, value: "", quoted: false})
+			break
+		}
+		quoted := false
+		var value string
+		if s[i] == '"' {
+			quoted = true
+			i++
+			start := i
+			for i < len(s) {
+				if s[i] == '"' && (i == start || s[i-1] != '\\') {
+					break
+				}
+				i++
+			}
+			value = s[start:i]
+			if i < len(s) && s[i] == '"' {
+				i++
+			}
+		} else {
+			start := i
+			for i < len(s) && !unicode.IsSpace(rune(s[i])) {
+				i++
+			}
+			value = s[start:i]
+		}
+		fields = append(fields, kvField{key: key, value: value, quoted: quoted})
+	}
+	return fields
+}
+
+func isValidKey(key string) bool {
+	if key == "" {
+		return false
+	}
+	for _, r := range key {
+		if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' || r == '.' {
+			continue
+		}
+		return false
+	}
+	return true
+}
+
+func extractMethodName(remainder string) string {
+	if remainder == "" {
+		return ""
+	}
+	for _, pattern := range methodPatterns {
+		if matches := pattern.FindStringSubmatch(remainder); len(matches) > 1 {
+			return simplifyMethodName(matches[1])
+		}
+	}
+	return ""
+}
+
+func simplifyMethodName(name string) string {
+	if name == "" {
+		return ""
+	}
+	name = strings.Trim(name, "\"' ")
+	if idx := strings.LastIndex(name, "/"); idx != -1 {
+		name = name[idx+1:]
+	}
+	return name
+}
+
+func lookupMethod(file, line string) string {
+	if file == "" || line == "" {
+		return ""
+	}
+	ln, err := strconv.Atoi(line)
+	if err != nil || ln <= 0 {
+		return ""
+	}
+	return srcIdx.functionAt(file, ln)
+}
+
+type funcInfo struct {
+	name      string
+	startLine int
+	endLine   int
+}
+
+type fileCache struct {
+	once  sync.Once
+	funcs []funcInfo
+}
+
+type sourceIndex struct {
+	mu    sync.Mutex
+	files map[string]*fileCache
+}
+
+func newSourceIndex() *sourceIndex {
+	return &sourceIndex{files: make(map[string]*fileCache)}
+}
+
+func (s *sourceIndex) functionAt(base string, line int) string {
+	s.mu.Lock()
+	cache, ok := s.files[base]
+	if !ok {
+		cache = &fileCache{}
+		s.files[base] = cache
+	}
+	s.mu.Unlock()
+
+	cache.once.Do(func() {
+		cache.funcs = loadFunctionsFor(base)
+	})
+	for _, fn := range cache.funcs {
+		if line >= fn.startLine && line <= fn.endLine {
+			return fn.name
+		}
+	}
+	return ""
+}
+
+func loadFunctionsFor(base string) []funcInfo {
+	paths := findSourceFiles(base)
+	if len(paths) == 0 {
+		return nil
+	}
+	infos := make([]funcInfo, 0, len(paths)*4)
+	for _, path := range paths {
+		fset := token.NewFileSet()
+		fileAst, err := parser.ParseFile(fset, path, nil, 0)
+		if err != nil {
+			continue
+		}
+		for _, decl := range fileAst.Decls {
+			fn, ok := decl.(*ast.FuncDecl)
+			if !ok || fn.Name == nil {
+				continue
+			}
+			start := fset.Position(fn.Pos()).Line
+			end := fset.Position(fn.End()).Line
+			name := fn.Name.Name
+			if recv := receiverType(fn); recv != "" {
+				name = fmt.Sprintf("%s.%s", recv, name)
+			}
+			infos = append(infos, funcInfo{name: name, startLine: start, endLine: end})
+		}
+	}
+	return infos
+}
+
+func receiverType(fn *ast.FuncDecl) string {
+	if fn.Recv == nil || len(fn.Recv.List) == 0 {
+		return ""
+	}
+	return typeString(fn.Recv.List[0].Type)
+}
+
+func typeString(expr ast.Expr) string {
+	switch v := expr.(type) {
+	case *ast.Ident:
+		return v.Name
+	case *ast.StarExpr:
+		return typeString(v.X)
+	case *ast.SelectorExpr:
+		return v.Sel.Name
+	case *ast.IndexExpr:
+		return typeString(v.X)
+	case *ast.IndexListExpr:
+		return typeString(v.X)
+	case *ast.ParenExpr:
+		return typeString(v.X)
+	default:
+		return ""
+	}
+}
+
+var (
+	searchRootsOnce sync.Once
+	cachedRoots     []string
+)
+
+func findSourceFiles(base string) []string {
+	matches := make([]string, 0)
+	seen := make(map[string]struct{})
+	for _, root := range sourceRoots() {
+		if root == "" {
+			continue
+		}
+		lookupFilesInRoot(root, base, seen, &matches)
+	}
+	return matches
+}
+
+func sourceRoots() []string {
+	searchRootsOnce.Do(func() {
+		roots := make([]string, 0, 4)
+		if env := os.Getenv("VELA_SOURCE_ROOT"); env != "" {
+			for _, item := range strings.Split(env, string(os.PathListSeparator)) {
+				if trimmed := strings.TrimSpace(item); trimmed != "" {
+					roots = append(roots, trimmed)
+				}
+			}
+		}
+		if cwd, err := os.Getwd(); err == nil {
+			roots = append(roots, cwd)
+		}
+		cachedRoots = dedupeStrings(roots)
+	})
+	return cachedRoots
+}
+
+func lookupFilesInRoot(root, base string, seen map[string]struct{}, matches *[]string) {
+	_ = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			// Continue scanning on error.
+			//nolint:nilerr
+			return nil
+		}
+		if d.IsDir() {
+			name := d.Name()
+			if name == "vendor" || name == "node_modules" || strings.HasPrefix(name, ".") {
+				if root == path {
+					return nil
+				}
+				return filepath.SkipDir
+			}
+			return nil
+		}
+		if d.Name() == base {
+			if _, ok := seen[path]; !ok {
+				seen[path] = struct{}{}
+				*matches = append(*matches, path)
+			}
+		}
+		return nil
+	})
+}
+
+func dedupeStrings(in []string) []string {
+	seen := make(map[string]struct{}, len(in))
+	out := make([]string, 0, len(in))
+	for _, v := range in {
+		if _, ok := seen[v]; ok {
+			continue
+		}
+		seen[v] = struct{}{}
+		out = append(out, v)
+	}
+	return out
+}
diff --git a/cmd/core/app/options/options.go b/cmd/core/app/options/options.go
index be3096d3..7959c0f8 100644
--- a/cmd/core/app/options/options.go
+++ b/cmd/core/app/options/options.go
@@ -50,6 +50,7 @@ type CoreOptions struct {
 	LogFilePath             string
 	LogFileMaxSize          uint64
 	LogDebug                bool
+	DevLogs                 bool
 	ControllerArgs          *oamcontroller.Args
 	HealthAddr              string
 	StorageDriver           string
@@ -76,6 +77,7 @@ func NewCoreOptions() *CoreOptions {
 		LogFilePath:             "",
 		LogFileMaxSize:          1024,
 		LogDebug:                false,
+		DevLogs:                 false,
 		ControllerArgs: &oamcontroller.Args{
 			RevisionLimit:                                50,
 			AppRevisionLimit:                             10,
@@ -116,6 +118,7 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
 	gfs.StringVar(&s.LogFilePath, "log-file-path", s.LogFilePath, "The file to write logs to.")
 	gfs.Uint64Var(&s.LogFileMaxSize, "log-file-max-size", s.LogFileMaxSize, "Defines the maximum size a log file can grow to, Unit is megabytes.")
 	gfs.BoolVar(&s.LogDebug, "log-debug", s.LogDebug, "Enable debug logs for development purpose")
+	gfs.BoolVar(&s.DevLogs, "dev-logs", s.DevLogs, "Enable ANSI color formatting for console logs (ignored when log-file-path is set)")
 	gfs.StringVar(&s.HealthAddr, "health-addr", s.HealthAddr, "The address the health endpoint binds to.")
 	gfs.DurationVar(&s.InformerSyncPeriod, "informer-sync-period", s.InformerSyncPeriod,
 		"The re-sync period for informer in controller-runtime. This is a system-level configuration.")
diff --git a/cmd/core/app/server.go b/cmd/core/app/server.go
index 06482191..36eef859 100644
--- a/cmd/core/app/server.go
+++ b/cmd/core/app/server.go
@@ -103,6 +103,17 @@ func run(ctx context.Context, s *options.CoreOptions) error {
 	restConfig.QPS = float32(s.QPS)
 	restConfig.Burst = s.Burst
 	restConfig.Wrap(auth.NewImpersonatingRoundTripper)
+
+	// Set logger (use --dev-logs=true for local development)
+	if s.DevLogs {
+		logOutput := newColorWriter(os.Stdout)
+		klog.LogToStderr(false)
+		klog.SetOutput(logOutput)
+		ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig(textlogger.Output(logOutput))))
+	} else {
+		ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))
+	}
+
 	klog.InfoS("Kubernetes Config Loaded",
 		"UserAgent", restConfig.UserAgent,
 		"QPS", restConfig.QPS,
@@ -127,8 +138,6 @@ func run(ctx context.Context, s *options.CoreOptions) error {
 		}
 	}
 
-	ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))
-
 	if utilfeature.DefaultMutableFeatureGate.Enabled(features.ApplyOnce) {
 		commonconfig.ApplicationReSyncPeriod = s.InformerSyncPeriod
 	}
diff --git a/docs/WEBHOOK_DEBUGGING.md b/docs/WEBHOOK_DEBUGGING.md
new file mode 100644
index 00000000..ad544c38
--- /dev/null
+++ b/docs/WEBHOOK_DEBUGGING.md
@@ -0,0 +1,191 @@
+# KubeVela Webhook Debugging Guide
+
+This guide explains how to debug KubeVela webhook validation locally, particularly for the feature that validates ComponentDefinitions, TraitDefinitions, and PolicyDefinitions to ensure they don't reference non-existent CRDs.
+
+## Overview
+
+The webhook validation feature checks that CUE templates in definitions only reference Kubernetes resources that exist on the cluster. This prevents runtime errors when non-existent CRDs are referenced.
+
+## Prerequisites
+
+- Docker Desktop or similar container runtime
+- k3d for local Kubernetes clusters
+- VS Code with Go extension
+- kubectl configured
+- openssl for certificate generation
+
+## Quick Start
+
+```bash
+# 1. Complete setup (cluster + CRDs + webhook)
+make webhook-debug-setup
+
+# 2. Start VS Code debugger
+# Press F5 and select "Debug Webhook Validation"
+```
+
+## Detailed Setup Steps
+
+### 1. Environment Setup
+
+```bash
+# Create k3d cluster
+make k3d-create
+
+# Install KubeVela CRDs
+make manifests
+kubectl apply -f charts/vela-core/crds/
+```
+
+### 2. Webhook Certificate Setup
+
+The webhook requires TLS certificates with proper Subject Alternative Names (SANs) for IP addresses.
+
+```bash
+# Generate certificates and create Kubernetes secret
+make webhook-setup
+```
+
+This creates:
+- CA certificate and key
+- Server certificate with IP SANs (127.0.0.1, Docker internal IP, local machine IP)
+- Kubernetes Secret `webhook-server-cert` in `vela-system` namespace
+- ValidatingWebhookConfiguration pointing to local debugger
+
+### 3. Start Debugger in VS Code
+
+#### VS Code Launch Configuration
+
+If you're using VSCode add this configuration to `.vscode/launch.json`:
+
+```json
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Debug Webhook Validation",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "${workspaceFolder}/cmd/core",
+            "args": [
+                "--log-debug=true",
+                "--metrics-addr=:8080",
+                "--enable-leader-election=false",
+                "--use-webhook=true",
+                "--webhook-port=9445",
+                "--webhook-cert-dir=${workspaceFolder}/k8s-webhook-server/serving-certs"
+            ],
+            "env": {
+                "KUBECONFIG": "${env:HOME}/.kube/config",
+                "POD_NAMESPACE": "vela-system"
+            },
+            "showLog": false,
+            "console": "integratedTerminal"
+        }
+    ]
+}
+```
+
+#### Set Breakpoints
+
+Recommended breakpoint locations:
+- `pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go` - ComponentDefinition handler
+- `pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler.go` - TraitDefinition handler
+- `pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler.go` - PolicyDefinition handler
+- `pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler.go` - WorkflowDefinition handler
+
+#### Launch Debugger
+
+1. Open VS Code
+2. Press `F5` or go to Run → Start Debugging
+3. Select **"Debug Webhook Validation"** configuration
+4. Wait for webhook server to start (look for message about port 9445)
+
+The debugger configuration includes:
+- `--use-webhook=true` - Enables webhook server
+- `--webhook-port=9445` - Port for webhook server
+- `--webhook-cert-dir` - Path to certificates
+- `POD_NAMESPACE=vela-system` - Required for finding the secret
+
+## Make Targets Reference
+
+| Target | Description |
+|--------|-------------|
+| `make webhook-help` | Show webhook debugging help |
+| `make webhook-debug-setup` | Complete setup (cluster + CRDs + webhook) |
+| `make k3d-create` | Create k3d cluster |
+| `make k3d-delete` | Delete k3d cluster |
+| `make webhook-setup` | Setup certificates and webhook configuration |
+| `make webhook-clean` | Clean up webhook environment |
+
+## Troubleshooting
+
+### Connection Refused Error
+
+If you get "connection refused" errors:
+1. Ensure the debugger is running in VS Code
+2. Check that port 9445 is not blocked by firewall
+3. Verify the webhook server started (check VS Code console)
+
+### TLS Certificate Errors
+
+If you get certificate validation errors:
+1. Regenerate certificates: `make webhook-setup`
+2. Restart the debugger
+3. Ensure IP addresses in certificates match your setup
+
+### Webhook Not Triggering
+
+If the webhook doesn't trigger:
+1. Check ValidatingWebhookConfiguration: `kubectl get validatingwebhookconfiguration`
+2. Verify the webhook URL matches your debugger's IP
+3. Check namespace is correct (vela-system)
+
+### Secret Not Found
+
+If you see "Wait webhook secret" messages:
+1. Ensure the secret exists: `kubectl get secret webhook-server-cert -n vela-system`
+2. Recreate if needed: `make webhook-setup`
+
+## How It Works
+
+1. **Certificate Generation**: Creates TLS certificates with proper SANs for local IPs
+2. **Secret Creation**: Stores certificates in Kubernetes secret
+3. **Webhook Configuration**: Creates ValidatingWebhookConfiguration pointing to local debugger
+4. **Debugger Startup**: VS Code starts the webhook server on port 9445
+5. **Validation**: When definitions are applied, Kubernetes calls the webhook
+6. **Debugging**: Breakpoints allow stepping through validation logic
+
+## Files and Components
+
+- **Script**: `hack/debug-webhook-setup.sh` - Main setup script
+- **Makefile**: `makefiles/develop.mk` - Make targets for debugging
+- **VS Code Config**: `.vscode/launch.json` - Debugger configuration
+- **Test Files**: `test/webhook-*.yaml` - Test manifests
+- **Validation Logic**: `pkg/webhook/utils/utils.go` - Core validation implementation
+- **Handlers**: `pkg/webhook/core.oam.dev/v1beta1/*/validating_handler.go` - Resource handlers
+
+## Clean Up
+
+```bash
+# Clean up webhook setup
+make webhook-clean
+
+# Delete k3d cluster
+make k3d-delete
+```
+
+## Tips
+
+1. **Always start the debugger before testing** - The webhook configuration points to your local machine
+2. **Use breakpoints wisely** - Too many breakpoints can cause timeouts
+3. **Check logs** - VS Code Debug Console shows detailed logs
+4. **Test both valid and invalid cases** - Ensures validation works correctly
+5. **Keep certificates updated** - Regenerate if IPs change
+
+## Related Documentation
+
+- [KubeVela Webhook Implementation](../pkg/webhook/README.md)
+- [CUE Template Validation](../pkg/webhook/utils/README.md)
+- [Admission Webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
\ No newline at end of file
diff --git a/e2e/addon/mock/testrepo/helm-repo/index.yaml b/e2e/addon/mock/testrepo/helm-repo/index.yaml
index fc089d7d..87ee524c 100644
--- a/e2e/addon/mock/testrepo/helm-repo/index.yaml
+++ b/e2e/addon/mock/testrepo/helm-repo/index.yaml
@@ -32,8 +32,8 @@ entries:
       icon: https://static.kubevela.net/images/logos/KubeVela%20-03.png
       name: vela-workflow
       urls:
-        - http://127.0.0.1:9098/helm/vela-workflow-v0.3.5.tgz
-      version: v0.3.5
+        - http://127.0.0.1:9098/helm/vela-workflow-v0.6.2.tgz
+      version: v0.6.2
   foo:
     - created: "2022-10-29T09:11:16.865230605Z"
       description: Vela test addon named foo
diff --git a/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.3.5.tgz b/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.3.5.tgz
deleted file mode 100644
index 0850ee9e..00000000
Binary files a/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.3.5.tgz and /dev/null differ
diff --git a/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz b/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz
new file mode 100644
index 00000000..a017b014
Binary files /dev/null and b/e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz differ
diff --git a/e2e/addon/mock/vela_addon_mock_server.go b/e2e/addon/mock/vela_addon_mock_server.go
index 31cb8098..279d99e0 100644
--- a/e2e/addon/mock/vela_addon_mock_server.go
+++ b/e2e/addon/mock/vela_addon_mock_server.go
@@ -125,8 +125,8 @@ var helmHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Reques
 			_, _ = rw.Write([]byte(err.Error()))
 		}
 		rw.Write(file)
-	case strings.Contains(req.URL.Path, "vela-workflow-v0.3.5.tgz"):
-		file, err := os.ReadFile("./e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.3.5.tgz")
+	case strings.Contains(req.URL.Path, "vela-workflow-v0.6.2.tgz"):
+		file, err := os.ReadFile("./e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz")
 		if err != nil {
 			_, _ = rw.Write([]byte(err.Error()))
 		}
diff --git a/hack/debug-webhook-setup.sh b/hack/debug-webhook-setup.sh
new file mode 100755
index 00000000..54b069ac
--- /dev/null
+++ b/hack/debug-webhook-setup.sh
@@ -0,0 +1,243 @@
+#!/bin/bash
+# Webhook debugging setup script for KubeVela
+# This script sets up everything needed to debug webhooks locally
+
+set -e
+
+# Configuration
+CERT_DIR="k8s-webhook-server/serving-certs"
+NAMESPACE="vela-system"
+SECRET_NAME="webhook-server-cert"
+WEBHOOK_CONFIG_NAME="kubevela-vela-core-admission"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+echo -e "${GREEN}=== KubeVela Webhook Debug Setup ===${NC}"
+
+# Function to check prerequisites
+check_prerequisites() {
+    echo -e "${YELLOW}Checking prerequisites...${NC}"
+
+    # Check kubectl
+    if ! command -v kubectl &> /dev/null; then
+        echo -e "${RED}kubectl is not installed${NC}"
+        exit 1
+    fi
+
+    # Check openssl
+    if ! command -v openssl &> /dev/null; then
+        echo -e "${RED}openssl is not installed${NC}"
+        exit 1
+    fi
+
+    # Check cluster connectivity
+    if ! kubectl cluster-info &> /dev/null; then
+        echo -e "${RED}Cannot connect to Kubernetes cluster${NC}"
+        echo "Please ensure your kubeconfig is set up correctly"
+        exit 1
+    fi
+
+    # Wait for cluster to be ready
+    echo "Waiting for cluster nodes to be ready..."
+    kubectl wait --for=condition=Ready nodes --all --timeout=60s &> /dev/null || true
+
+    echo -e "${GREEN}Prerequisites check passed${NC}"
+}
+
+# Function to create namespace if not exists
+create_namespace() {
+    echo -e "${YELLOW}Creating namespace ${NAMESPACE}...${NC}"
+    kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
+    echo -e "${GREEN}Namespace ready${NC}"
+}
+
+# Function to generate certificates
+generate_certificates() {
+    echo -e "${YELLOW}Generating webhook certificates...${NC}"
+
+    # Create directory
+    mkdir -p ${CERT_DIR}
+
+    # Clean old certificates
+    rm -f ${CERT_DIR}/*
+
+    # Generate CA private key
+    openssl genrsa -out ${CERT_DIR}/ca.key 2048
+
+    # Generate CA certificate
+    openssl req -x509 -new -nodes -key ${CERT_DIR}/ca.key -days 365 -out ${CERT_DIR}/ca.crt \
+        -subj "/CN=webhook-ca"
+
+    # Generate server private key
+    openssl genrsa -out ${CERT_DIR}/tls.key 2048
+
+    # Get host IP for Docker internal network
+    # NOTE: 192.168.5.2 is the standard k3d host gateway IP that allows containers to reach the host machine
+    # This is only for local k3d development environments - DO NOT use this script in production
+    # With failurePolicy: Fail, an unreachable webhook can block CRD operations cluster-wide
+    HOST_IP="192.168.5.2"
+    LOCAL_IP=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}')
+
+    # Create certificate config with SANs
+    cat > /tmp/webhook.conf << EOF
+[req]
+req_extensions = v3_req
+distinguished_name = req_distinguished_name
+[req_distinguished_name]
+[v3_req]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+subjectAltName = @alt_names
+[alt_names]
+DNS.1 = localhost
+DNS.2 = vela-webhook.${NAMESPACE}.svc
+DNS.3 = vela-webhook.${NAMESPACE}.svc.cluster.local
+DNS.4 = *.${NAMESPACE}.svc
+DNS.5 = *.${NAMESPACE}.svc.cluster.local
+IP.1 = 127.0.0.1
+IP.2 = ${HOST_IP}
+IP.3 = ${LOCAL_IP}
+EOF
+
+    # Generate certificate request
+    openssl req -new -key ${CERT_DIR}/tls.key -out /tmp/server.csr \
+        -subj "/CN=vela-webhook.${NAMESPACE}.svc" -config /tmp/webhook.conf
+
+    # Generate server certificate with SANs
+    openssl x509 -req -in /tmp/server.csr -CA ${CERT_DIR}/ca.crt -CAkey ${CERT_DIR}/ca.key \
+        -CAcreateserial -out ${CERT_DIR}/tls.crt -days 365 \
+        -extensions v3_req -extfile /tmp/webhook.conf
+
+    echo -e "${GREEN}Certificates generated with IP SANs: 127.0.0.1, ${HOST_IP}, ${LOCAL_IP}${NC}"
+
+    # Clean up temp files
+    rm -f /tmp/server.csr /tmp/webhook.conf
+}
+
+# Function to create Kubernetes secret
+create_k8s_secret() {
+    echo -e "${YELLOW}Creating Kubernetes secret...${NC}"
+
+    # Delete old secret if exists
+    kubectl delete secret ${SECRET_NAME} -n ${NAMESPACE} --ignore-not-found
+
+    # Create new secret
+    kubectl create secret tls ${SECRET_NAME} \
+        --cert=${CERT_DIR}/tls.crt \
+        --key=${CERT_DIR}/tls.key \
+        -n ${NAMESPACE}
+
+    echo -e "${GREEN}Secret ${SECRET_NAME} created in namespace ${NAMESPACE}${NC}"
+}
+
+# Function to create webhook configuration
+create_webhook_config() {
+    echo -e "${YELLOW}Creating webhook configuration...${NC}"
+
+    # Get CA bundle
+    CA_BUNDLE=$(cat ${CERT_DIR}/ca.crt | base64 | tr -d '\n')
+
+    # Delete old webhook configuration if exists
+    kubectl delete validatingwebhookconfiguration ${WEBHOOK_CONFIG_NAME} --ignore-not-found
+
+    # Create webhook configuration
+    cat > /tmp/webhook-config.yaml << EOF
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  name: ${WEBHOOK_CONFIG_NAME}
+webhooks:
+- name: componentdefinition.core.oam.dev
+  clientConfig:
+    url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-componentdefinitions
+    caBundle: ${CA_BUNDLE}
+  rules:
+  - apiGroups: ["core.oam.dev"]
+    apiVersions: ["v1beta1"]
+    resources: ["componentdefinitions"]
+    operations: ["CREATE", "UPDATE"]
+  admissionReviewVersions: ["v1", "v1beta1"]
+  sideEffects: None
+  failurePolicy: Fail
+- name: traitdefinition.core.oam.dev
+  clientConfig:
+    url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-traitdefinitions
+    caBundle: ${CA_BUNDLE}
+  rules:
+  - apiGroups: ["core.oam.dev"]
+    apiVersions: ["v1beta1"]
+    resources: ["traitdefinitions"]
+    operations: ["CREATE", "UPDATE"]
+  admissionReviewVersions: ["v1", "v1beta1"]
+  sideEffects: None
+  failurePolicy: Fail
+- name: policydefinition.core.oam.dev
+  clientConfig:
+    url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-policydefinitions
+    caBundle: ${CA_BUNDLE}
+  rules:
+  - apiGroups: ["core.oam.dev"]
+    apiVersions: ["v1beta1"]
+    resources: ["policydefinitions"]
+    operations: ["CREATE", "UPDATE"]
+  admissionReviewVersions: ["v1", "v1beta1"]
+  sideEffects: None
+  failurePolicy: Fail
+- name: workflowstepdefinition.core.oam.dev
+  clientConfig:
+    url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-workflowstepdefinitions
+    caBundle: ${CA_BUNDLE}
+  rules:
+  - apiGroups: ["core.oam.dev"]
+    apiVersions: ["v1beta1"]
+    resources: ["workflowstepdefinitions"]
+    operations: ["CREATE", "UPDATE"]
+  admissionReviewVersions: ["v1", "v1beta1"]
+  sideEffects: None
+  failurePolicy: Fail
+EOF
+
+    kubectl apply -f /tmp/webhook-config.yaml
+    rm -f /tmp/webhook-config.yaml
+
+    echo -e "${GREEN}Webhook configuration created${NC}"
+}
+
+# Function to show next steps
+show_next_steps() {
+    echo -e "${GREEN}"
+    echo "========================================="
+    echo "Webhook debugging setup complete!"
+    echo "========================================="
+    echo -e "${NC}"
+    echo "Next steps:"
+    echo "1. Open VS Code"
+    echo "2. Set breakpoints in webhook validation code:"
+    echo "   - pkg/webhook/utils/utils.go:141"
+    echo "   - pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go:74"
+    echo "3. Press F5 and select 'Debug Webhook Validation'"
+    echo "4. Wait for webhook server to start (port 9445)"
+    echo "5. Test with kubectl apply commands"
+    echo ""
+    echo -e "${YELLOW}Test command (should be rejected):${NC}"
+    echo 'kubectl apply -f test/webhook-test-invalid.yaml'
+    echo ""
+    echo -e "${GREEN}The webhook will reject ComponentDefinitions with non-existent CRDs${NC}"
+}
+
+# Main execution
+main() {
+    check_prerequisites
+    create_namespace
+    generate_certificates
+    create_k8s_secret
+    create_webhook_config
+    show_next_steps
+}
+
+# Run main function
+main "$@"
\ No newline at end of file
diff --git a/makefiles/develop.mk b/makefiles/develop.mk
index f957b844..585e613a 100644
--- a/makefiles/develop.mk
+++ b/makefiles/develop.mk
@@ -30,3 +30,75 @@ core-run: fmt vet manifests
 .PHONY: gen-cue
 gen-cue:
 	./hack/cuegen/cuegen.sh $(DIR) $(FLAGS)
+
+# ==============================================================================
+# Webhook Debug and Development Targets
+
+K3D_CLUSTER_NAME ?= kubevela-debug
+K3D_VERSION ?= v1.31.5
+
+## webhook-help: Show webhook debugging help
+.PHONY: webhook-help
+webhook-help:
+	@echo "=== KubeVela Webhook Debugging Guide ==="
+	@echo ""
+	@echo "Quick Start (recommended):"
+	@echo "  1. make webhook-debug-setup   # Complete setup"
+	@echo "  2. Start VS Code debugger (F5) with 'Debug Webhook Validation'"
+	@echo ""
+	@echo "Individual Commands:"
+	@echo "  make k3d-create               # Create k3d cluster"
+	@echo "  make k3d-delete               # Delete k3d cluster"
+	@echo "  make webhook-setup            # Setup webhook (certs + config)"
+	@echo "  make webhook-clean            # Clean up webhook setup"
+
+## k3d-create: Create a k3d cluster for debugging
+.PHONY: k3d-create
+k3d-create:
+	@echo "Creating k3d cluster: $(K3D_CLUSTER_NAME)"
+	@if k3d cluster list | grep -q "^$(K3D_CLUSTER_NAME)"; then \
+		echo "k3d cluster $(K3D_CLUSTER_NAME) already exists"; \
+	else \
+		k3d cluster create "$(K3D_CLUSTER_NAME)" \
+			--servers 1 \
+			--agents 1 \
+			--wait || (echo "Failed to create k3d cluster" && exit 1); \
+	fi
+	@kubectl config use-context "k3d-$(K3D_CLUSTER_NAME)"
+	@echo "k3d cluster $(K3D_CLUSTER_NAME) ready"
+
+## k3d-delete: Delete the k3d cluster
+.PHONY: k3d-delete
+k3d-delete:
+	@echo "Deleting k3d cluster: $(K3D_CLUSTER_NAME)"
+	@k3d cluster delete "$(K3D_CLUSTER_NAME)" || true
+
+## webhook-setup: Setup webhook certificates and configuration
+.PHONY: webhook-setup
+webhook-setup:
+	@echo "Setting up webhook certificates and configuration..."
+	@chmod +x hack/debug-webhook-setup.sh
+	@./hack/debug-webhook-setup.sh
+
+## webhook-debug-setup: Complete webhook debug environment setup
+.PHONY: webhook-debug-setup
+webhook-debug-setup:
+	@echo "Setting up complete webhook debug environment..."
+	@$(MAKE) k3d-create
+	@echo "Waiting for cluster to be ready..."
+	@sleep 5
+	@kubectl wait --for=condition=Ready nodes --all --timeout=60s || true
+	@echo "Installing KubeVela CRDs..."
+	@$(MAKE) manifests
+	@kubectl apply -f charts/vela-core/crds/ --validate=false
+	@echo "Setting up webhook..."
+	@$(MAKE) webhook-setup
+
+## webhook-clean: Clean up webhook debug environment
+.PHONY: webhook-clean
+webhook-clean:
+	@echo "Cleaning up webhook debug environment..."
+	@rm -rf k8s-webhook-server/
+	@kubectl delete secret webhook-server-cert -n vela-system --ignore-not-found
+	@kubectl delete validatingwebhookconfiguration kubevela-vela-core-admission --ignore-not-found
+	@echo "Webhook debug environment cleaned"
diff --git a/makefiles/e2e.mk b/makefiles/e2e.mk
index f3b2957d..3ae7d544 100644
--- a/makefiles/e2e.mk
+++ b/makefiles/e2e.mk
@@ -31,6 +31,7 @@ e2e-setup-core-wo-auth:
 		--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
 		--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
 		--set featureGates.enableCueValidation=true \
+		--set featureGates.validateResourcesExist=true \
 	    --wait kubevela ./charts/vela-core          \
 		--debug
 
@@ -48,10 +49,11 @@ e2e-setup-core-w-auth:
 	    ./charts/vela-core                              \
 	    --set authentication.enabled=true               \
 	    --set authentication.withUser=true              \
-	    --set authentication.groupPattern=*             \
+	    --set authentication.groupPattern='*'           \
 	    --set featureGates.zstdResourceTracker=true     \
 	    --set featureGates.zstdApplicationRevision=true \
 	    --set featureGates.validateComponentWhenSharding=true \
+	    --set featureGates.validateResourcesExist=true \
 	    --set multicluster.clusterGateway.enabled=true  \
 			--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
 			--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
@@ -85,6 +87,32 @@ e2e-test:
 	ginkgo -v ./test/e2e-test
 	@$(OK) tests pass
 
+# Run e2e tests with k3d and webhook validation
+.PHONY: e2e-test-local
+e2e-test-local:
+	# Create k3d cluster if needed
+	@k3d cluster create kubevela-debug --servers 1 --agents 1 || true
+	# Build and load image
+	docker build -t vela-core:e2e-test -f Dockerfile . --build-arg=VERSION=e2e-test --build-arg=GITVERSION=test
+	k3d image import vela-core:e2e-test -c kubevela-debug
+	# Deploy with Helm
+	kubectl delete validatingwebhookconfiguration kubevela-vela-core-admission 2>/dev/null || true
+	helm upgrade --install kubevela ./charts/vela-core \
+		--namespace vela-system --create-namespace \
+		--set image.repository=vela-core \
+		--set image.tag=e2e-test \
+		--set image.pullPolicy=IfNotPresent \
+		--set admissionWebhooks.enabled=true \
+		--set featureGates.enableCueValidation=true \
+		--set featureGates.validateResourcesExist=true \
+		--set applicationRevisionLimit=5 \
+		--set controllerArgs.reSyncPeriod=1m \
+		--wait --timeout 3m
+	# Run tests
+	ginkgo -v ./test/e2e-test
+	@$(OK) tests pass
+
+
 .PHONY: e2e-addon-test
 e2e-addon-test:
 	cp bin/vela /tmp/
diff --git a/pkg/controller/core.oam.dev/v1beta1/application/generator.go b/pkg/controller/core.oam.dev/v1beta1/application/generator.go
index ce742ac1..138d5dc5 100644
--- a/pkg/controller/core.oam.dev/v1beta1/application/generator.go
+++ b/pkg/controller/core.oam.dev/v1beta1/application/generator.go
@@ -508,6 +508,7 @@ func getComponentResources(ctx context.Context, manifest *types.ComponentManifes
 	return workload, traits, nil
 }
 
+// generateContextDataFromApp builds the process context for workflow (non-component) execution.
 func generateContextDataFromApp(app *v1beta1.Application, appRev string) velaprocess.ContextData {
 	data := velaprocess.ContextData{
 		Namespace:       app.Namespace,
@@ -519,5 +520,12 @@ func generateContextDataFromApp(app *v1beta1.Application, appRev string) velapro
 		data.WorkflowName = app.Annotations[oam.AnnotationWorkflowName]
 		data.PublishVersion = app.Annotations[oam.AnnotationPublishVersion]
 	}
+	// pass labels and annotations to workflow context
+	if len(app.Labels) > 0 {
+		data.AppLabels = app.Labels
+	}
+	if len(app.Annotations) > 0 {
+		data.AppAnnotations = app.Annotations
+	}
 	return data
 }
diff --git a/pkg/features/controller_features.go b/pkg/features/controller_features.go
index 841cca98..16a8518f 100644
--- a/pkg/features/controller_features.go
+++ b/pkg/features/controller_features.go
@@ -119,6 +119,10 @@ const (
 
 	// EnableApplicationStatusMetrics enable the collection and export of application status metrics and structured logging
 	EnableApplicationStatusMetrics = "EnableApplicationStatusMetrics"
+
+	// ValidateResourcesExist enables webhook validation to check if resource types referenced in
+	// ComponentDefinition/TraitDefinition/WorkflowStepDefinition/PolicyDefinition CUE templates exist in the cluster
+	ValidateResourcesExist = "ValidateResourcesExist"
 )
 
 var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
@@ -146,6 +150,7 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
 	DisableWorkflowContextConfigMapCache:          {Default: true, PreRelease: featuregate.Alpha},
 	EnableCueValidation:                           {Default: false, PreRelease: featuregate.Beta},
 	EnableApplicationStatusMetrics:                {Default: false, PreRelease: featuregate.Alpha},
+	ValidateResourcesExist:                        {Default: false, PreRelease: featuregate.Alpha},
 }
 
 func init() {
diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go
new file mode 100644
index 00000000..73c8d282
--- /dev/null
+++ b/pkg/logging/logger.go
@@ -0,0 +1,173 @@
+/*
+Copyright 2024 The KubeVela Authors.
+
+Licensed 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 logging provides structured logging utilities for KubeVela webhooks
+// with focus on request traceability and observability.
+package logging
+
+import (
+	"context"
+	"time"
+
+	"github.com/go-logr/logr"
+	"sigs.k8s.io/controller-runtime/pkg/log"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// Structured logging field keys - consistent across all handlers for observability
+const (
+	// Core traceability fields
+	FieldRequestID = "requestID"  // Unique identifier for request correlation
+	FieldOperation = "operation"  // Webhook operation (CREATE/UPDATE/DELETE)
+	FieldHandler   = "handler"    // Handler processing the request
+	FieldStep      = "step"       // Current processing step
+	FieldDuration  = "durationMs" // Operation duration in milliseconds
+
+	// Resource identification
+	FieldName       = "name"       // Resource name
+	FieldNamespace  = "namespace"  // Resource namespace
+	FieldKind       = "kind"       // Resource kind
+	FieldGeneration = "generation" // Resource generation
+
+	// User context
+	FieldUserName = "user" // User making the request
+
+	// Error tracking
+	FieldError   = "error"   // Error indicator
+	FieldSuccess = "success" // Success indicator
+)
+
+// contextKey for storing values in context
+type contextKey struct{ name string }
+
+var (
+	requestIDKey = contextKey{name: "requestID"}
+	loggerKey    = contextKey{name: "logger"}
+)
+
+// Logger wraps logr.Logger with structured logging methods
+type Logger struct {
+	logr.Logger
+}
+
+// WithValues adds key-value pairs to the logger
+func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
+	return Logger{Logger: l.Logger.WithValues(keysAndValues...)}
+}
+
+// New creates a new Logger
+func New() Logger {
+	return Logger{Logger: log.Log}
+}
+
+// WithContext returns a Logger from context or creates a new one
+func WithContext(ctx context.Context) Logger {
+	if logger, ok := ctx.Value(loggerKey).(Logger); ok {
+		return logger
+	}
+	return New()
+}
+
+// IntoContext stores the Logger in context
+func (l Logger) IntoContext(ctx context.Context) context.Context {
+	return context.WithValue(ctx, loggerKey, l)
+}
+
+// WithRequestID stores request ID in context
+func WithRequestID(ctx context.Context, requestID string) context.Context {
+	if requestID == "" {
+		return ctx
+	}
+	return context.WithValue(ctx, requestIDKey, requestID)
+}
+
+// RequestIDFrom retrieves request ID from context
+func RequestIDFrom(ctx context.Context) (string, bool) {
+	id, ok := ctx.Value(requestIDKey).(string)
+	return id, ok && id != ""
+}
+
+// NewHandlerLogger creates a logger for webhook handlers with full request context
+func NewHandlerLogger(ctx context.Context, req admission.Request, handlerName string) Logger {
+	logger := New()
+
+	// Use admission UID as request ID for correlation
+	requestID := string(req.UID)
+	if rid, ok := RequestIDFrom(ctx); ok && rid != "" {
+		requestID = rid
+	}
+
+	// Build structured log with essential fields for observability
+	logger = logger.WithValues(
+		FieldRequestID, requestID,
+		FieldHandler, handlerName,
+		FieldOperation, req.Operation,
+		FieldKind, req.Kind.Kind,
+		FieldName, req.Name,
+		FieldNamespace, req.Namespace,
+		FieldUserName, req.UserInfo.Username,
+	)
+
+	return logger
+}
+
+// Helper methods that return the logger with values added
+// These don't log directly, so the actual logging call site is preserved
+
+// WithStep adds a step field to the logger
+func (l Logger) WithStep(step string) Logger {
+	return l.WithValues(FieldStep, step)
+}
+
+// WithSuccess adds success and duration fields to the logger
+func (l Logger) WithSuccess(success bool, startTime ...time.Time) Logger {
+	logger := l.WithValues(FieldSuccess, success)
+	if len(startTime) > 0 {
+		duration := time.Since(startTime[0])
+		logger = logger.WithValues(FieldDuration, duration.Milliseconds())
+	}
+	return logger
+}
+
+// WithError adds error context to the logger
+func (l Logger) WithError(err error) Logger {
+	return l.WithValues(FieldError, err.Error(), FieldSuccess, false)
+}
+
+// V returns a logger with verbosity level (0=info, 1=debug, 2=trace)
+func (l Logger) V(level int) Logger {
+	return Logger{Logger: l.Logger.V(level)}
+}
+
+// Debug logs debug message (verbosity 1)
+func (l Logger) Debug(msg string, keysAndValues ...interface{}) {
+	l.Logger.V(1).Info(msg, keysAndValues...)
+}
+
+// Trace logs trace message (verbosity 2)
+func (l Logger) Trace(msg string, keysAndValues ...interface{}) {
+	l.Logger.V(2).Info(msg, keysAndValues...)
+}
+
+// Info logs info message
+func (l Logger) Info(msg string, keysAndValues ...interface{}) {
+	l.Logger.Info(msg, keysAndValues...)
+}
+
+// Error logs error message
+func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
+	l.Logger.Error(err, msg, keysAndValues...)
+}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go
index cdc27857..b02f65d7 100644
--- a/pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go
+++ b/pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go
@@ -21,6 +21,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"time"
 
 	admissionv1 "k8s.io/api/admission/v1"
 	"k8s.io/apimachinery/pkg/util/validation/field"
@@ -31,6 +32,7 @@ import (
 
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
 	controller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
+	"github.com/oam-dev/kubevela/pkg/logging"
 	"github.com/oam-dev/kubevela/pkg/oam/util"
 )
 
@@ -62,35 +64,78 @@ func mergeErrors(errs field.ErrorList) error {
 
 // Handle validate Application Spec here
 func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
+	startTime := time.Now()
+	ctx = logging.WithRequestID(ctx, string(req.UID))
+	logger := logging.NewHandlerLogger(ctx, req, "ApplicationValidator")
+
+	logger.WithStep("start").Info("Starting admission validation for Application resource", "operation", req.Operation, "applicationName", req.Name, "namespace", req.Namespace)
+
+	// Decode the application
 	app := &v1beta1.Application{}
 	if err := h.Decoder.Decode(req, app); err != nil {
-		return admission.Errored(http.StatusBadRequest, err)
+		logger.WithStep("decode").WithError(err).Error(err, "Unable to decode admission request payload into Application object - malformed request")
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("failed to decode: %w (requestUID=%s)", err, req.UID))
 	}
+
 	if req.Namespace != "" {
 		app.Namespace = req.Namespace
 	}
 
+	logger = logger.WithValues(logging.FieldGeneration, app.Generation)
+
+	workflowSteps := 0
+	if app.Spec.Workflow != nil {
+		workflowSteps = len(app.Spec.Workflow.Steps)
+	}
+
+	logger.WithStep("decode").Info("Successfully decoded Application from admission request",
+		"applicationName", app.Name,
+		"namespace", app.Namespace,
+		"componentCount", len(app.Spec.Components),
+		"policyCount", len(app.Spec.Policies),
+		"workflowSteps", workflowSteps)
+
 	ctx = util.SetNamespaceInCtx(ctx, app.Namespace)
+
 	switch req.Operation {
 	case admissionv1.Create:
+		logger.WithStep("validate-create").Info("Validating Application creation - checking components, policies, and workflow configuration")
 		if allErrs := h.ValidateCreate(ctx, app, req); len(allErrs) > 0 {
-			// http.StatusUnprocessableEntity will NOT report any error descriptions
-			// to the client, use generic http.StatusBadRequest instead.
-			return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs))
+			mergedErr := mergeErrors(allErrs)
+			logger.WithStep("validate-create").WithError(mergedErr).Error(mergedErr, "Application creation validation failed - contains invalid components, policies, or workflow steps", "errorCount", len(allErrs), "applicationName", app.Name)
+			return admission.Errored(http.StatusBadRequest, fmt.Errorf("%w (requestUID=%s)", mergedErr, req.UID))
 		}
+		logger.WithStep("validate-create").WithSuccess(true).Info("Application creation validation completed successfully - all components, policies, and workflows are valid", "applicationName", app.Name)
+
 	case admissionv1.Update:
+		logger.WithStep("validate-update").Info("Validating Application update - comparing new configuration with existing state")
 		oldApp := &v1beta1.Application{}
 		if err := h.Decoder.DecodeRaw(req.AdmissionRequest.OldObject, oldApp); err != nil {
-			return admission.Errored(http.StatusBadRequest, simplifyError(err))
+			logger.WithStep("decode-old").WithError(err).Error(err, "Unable to decode previous Application state from admission request - cannot validate update")
+			return admission.Errored(http.StatusBadRequest, fmt.Errorf("%w (requestUID=%s)", simplifyError(err), req.UID))
 		}
+
+		logger = logger.WithValues("oldGeneration", oldApp.Generation)
+
 		if app.ObjectMeta.DeletionTimestamp.IsZero() {
 			if allErrs := h.ValidateUpdate(ctx, app, oldApp, req); len(allErrs) > 0 {
-				return admission.Errored(http.StatusBadRequest, mergeErrors(allErrs))
+				mergedErr := mergeErrors(allErrs)
+				logger.WithStep("validate-update").WithError(mergedErr).Error(mergedErr, "Application update validation failed - new configuration contains invalid changes", "errorCount", len(allErrs), "applicationName", app.Name, "oldGeneration", oldApp.Generation, "newGeneration", app.Generation)
+				return admission.Errored(http.StatusBadRequest, fmt.Errorf("%w (requestUID=%s)", mergedErr, req.UID))
 			}
+			logger.WithStep("validate-update").WithSuccess(true).Info("Application update validation completed successfully - configuration changes are valid", "applicationName", app.Name, "generationChange", fmt.Sprintf("%d->%d", oldApp.Generation, app.Generation))
+		} else {
+			logger.WithStep("skip-validation").Info("Skipping Application validation - resource is being deleted and validation is not required", "reason", "deletion-in-progress", "deletionTimestamp", app.DeletionTimestamp)
 		}
+
+	case admissionv1.Delete:
+		logger.WithStep("skip-validation").Info("Skipping Application validation - DELETE operations do not require content validation", "reason", "delete-operation-no-validation-needed")
+
 	default:
-		// Do nothing for DELETE and CONNECT
+		logger.WithStep("skip-validation").Info("Skipping Application validation - operation type is not supported by validator", "operation", req.Operation, "reason", "only CREATE, UPDATE, and DELETE operations are handled")
 	}
+
+	logger.WithStep("complete").WithSuccess(true, startTime).Info("Application admission validation completed successfully - resource will be admitted", "applicationName", req.Name, "operation", req.Operation, "namespace", req.Namespace)
 	return admission.ValidationResponse(true, "")
 }
 
diff --git a/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler.go
new file mode 100644
index 00000000..62bc20f6
--- /dev/null
+++ b/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler.go
@@ -0,0 +1,171 @@
+/*
+ Copyright 2021. The KubeVela Authors.
+
+ Licensed 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 componentdefinition
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"time"
+
+	admissionv1 "k8s.io/api/admission/v1"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/webhook"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/logging"
+	"github.com/oam-dev/kubevela/pkg/oam"
+	"github.com/oam-dev/kubevela/pkg/oam/util"
+	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
+)
+
+var componentDefGVR = v1beta1.ComponentDefinitionGVR
+
+// ValidatingHandler handles validation of component definition
+type ValidatingHandler struct {
+	// Decoder decodes object
+	Decoder admission.Decoder
+	Client  client.Client
+}
+
+var _ admission.Handler = &ValidatingHandler{}
+
+// Handle validate ComponentDefinition Spec here
+func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
+	startTime := time.Now()
+	ctx = logging.WithRequestID(ctx, string(req.UID))
+	logger := logging.NewHandlerLogger(ctx, req, "ComponentDefinitionValidator")
+
+	// Using the logger methods directly will show the correct file location
+	logger.WithStep("start").Info("Starting admission validation for ComponentDefinition resource", "operation", req.Operation, "resourceVersion", req.Kind.Version)
+
+	obj := &v1beta1.ComponentDefinition{}
+	if req.Resource.String() != componentDefGVR.String() {
+		err := fmt.Errorf("expect resource to be %s", componentDefGVR)
+		logger.WithStep("resource-check").WithError(err).Error(err, "Admission request targets unexpected resource type - rejecting request",
+			"expected", componentDefGVR.String(),
+			"actual", req.Resource.String(),
+			"operation", req.Operation)
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
+		if err := h.Decoder.Decode(req, obj); err != nil {
+			logger.WithStep("decode").WithError(err).Error(err, "Unable to decode admission request payload into ComponentDefinition object - malformed request")
+			return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+
+		// Add definition-specific fields to logger
+		if obj.Spec.Version != "" {
+			logger = logger.WithValues("version", obj.Spec.Version)
+		}
+		logger.WithStep("decode").Info("Successfully decoded ComponentDefinition from admission request",
+			"definitionName", obj.Name,
+			"namespace", obj.Namespace,
+			"workloadType", obj.Spec.Workload.Type,
+			"hasSchematic", obj.Spec.Schematic != nil)
+
+		// Validate workload
+		if err := ValidateWorkload(h.Client.RESTMapper(), obj); err != nil {
+			logger.WithStep("validate-workload").WithError(err).Error(err, "ComponentDefinition workload configuration is invalid - type and definition must be consistent")
+			return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+		logger.WithStep("validate-workload").Info("ComponentDefinition workload configuration validated successfully", "workloadType", obj.Spec.Workload.Type)
+
+		// Validate CUE template
+		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
+			logger.WithStep("validate-cue").Info("Validating CUE template syntax and semantics for ComponentDefinition schematic")
+
+			if err := webhookutils.ValidateCuexTemplate(ctx, obj.Spec.Schematic.CUE.Template); err != nil {
+				logger.WithStep("validate-cue").WithError(err).Error(err, "CUE template contains syntax errors or invalid constructs - template compilation failed")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+
+			if err := webhookutils.ValidateOutputResourcesExist(obj.Spec.Schematic.CUE.Template, h.Client.RESTMapper(), obj); err != nil {
+				logger.WithStep("validate-output-resources").WithError(err).Error(err, "CUE template references output resources that don't exist in cluster - unknown resource types detected")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-cue").WithSuccess(true).Info("CUE template validation completed successfully - template is syntactically correct and all output resources exist")
+		}
+
+		// Validate semantic version
+		if obj.Spec.Version != "" {
+			if err := webhookutils.ValidateSemanticVersion(obj.Spec.Version); err != nil {
+				logger.WithStep("validate-version").WithError(err).Error(err, "ComponentDefinition version does not follow semantic versioning format (x.y.z)", "version", obj.Spec.Version, "expectedFormat", "x.y.z")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-version").Info("ComponentDefinition version follows semantic versioning format", "version", obj.Spec.Version)
+		}
+
+		// Validate revision
+		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
+		if len(revisionName) != 0 {
+			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
+			if err := webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName}); err != nil {
+				logger.WithStep("validate-revision").WithError(err).Error(err, "ComponentDefinition revision conflicts with existing revision or has invalid format", "revisionName", revisionName, "expectedRevisionName", fmt.Sprintf("%s-v%s", obj.Name, revisionName))
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-revision").Info("ComponentDefinition revision validation completed - no conflicts detected", "revisionName", revisionName)
+		}
+
+		// Check version conflicts
+		if err := webhookutils.ValidateMultipleDefVersionsNotPresent(obj.Spec.Version, revisionName, obj.Kind); err != nil {
+			logger.WithStep("validate-version-conflict").WithError(err).Error(err, "ComponentDefinition has conflicting version specifications - cannot have both spec.version and revision annotation", "specVersion", obj.Spec.Version, "revisionName", revisionName)
+			return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+
+		// Log successful completion
+		logger.WithStep("complete").WithSuccess(true, startTime).Info("ComponentDefinition admission validation completed successfully - resource is valid and will be admitted", "definitionName", obj.Name, "operation", req.Operation)
+	} else {
+		logger.WithStep("skip-validation").Info("Skipping ComponentDefinition validation - operation does not require validation", "operation", req.Operation, "reason", "only CREATE and UPDATE operations are validated")
+	}
+	return admission.ValidationResponse(true, "")
+}
+
+// RegisterValidatingHandler will register ComponentDefinition validation to webhook
+func RegisterValidatingHandler(mgr manager.Manager) {
+	server := mgr.GetWebhookServer()
+	server.Register("/validating-core-oam-dev-v1beta1-componentdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
+		Client:  mgr.GetClient(),
+		Decoder: admission.NewDecoder(mgr.GetScheme()),
+	}})
+}
+
+// ValidateWorkload validates whether the Workload field is valid
+func ValidateWorkload(mapper meta.RESTMapper, cd *v1beta1.ComponentDefinition) error {
+
+	// If the Type and Definition are all empty, it will be rejected.
+	if cd.Spec.Workload.Type == "" && cd.Spec.Workload.Definition == (common.WorkloadGVK{}) {
+		return fmt.Errorf("neither the type nor the definition of the workload field in the ComponentDefinition %s can be empty", cd.Name)
+	}
+
+	// if Type and Definitiondon‘t point to the same workloaddefinition, it will be rejected.
+	if cd.Spec.Workload.Type != "" && cd.Spec.Workload.Definition != (common.WorkloadGVK{}) {
+		defRef, err := util.ConvertWorkloadGVK2Definition(mapper, cd.Spec.Workload.Definition)
+		if err != nil {
+			return err
+		}
+		if defRef.Name != cd.Spec.Workload.Type {
+			return fmt.Errorf("the type and the definition of the workload field in ComponentDefinition %s should represent the same workload", cd.Name)
+		}
+	}
+	return nil
+}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go
deleted file mode 100644
index 8622e21a..00000000
--- a/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright 2021. The KubeVela Authors.
-
- Licensed 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 componentdefinition
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-
-	admissionv1 "k8s.io/api/admission/v1"
-	"k8s.io/apimachinery/pkg/api/meta"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/manager"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
-	"github.com/oam-dev/kubevela/pkg/oam"
-	"github.com/oam-dev/kubevela/pkg/oam/util"
-	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
-)
-
-var componentDefGVR = v1beta1.ComponentDefinitionGVR
-
-// ValidatingHandler handles validation of component definition
-type ValidatingHandler struct {
-	// Decoder decodes object
-	Decoder admission.Decoder
-	Client  client.Client
-}
-
-var _ admission.Handler = &ValidatingHandler{}
-
-// Handle validate ComponentDefinition Spec here
-func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
-	obj := &v1beta1.ComponentDefinition{}
-	if req.Resource.String() != componentDefGVR.String() {
-		return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", componentDefGVR))
-	}
-
-	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
-		err := h.Decoder.Decode(req, obj)
-		if err != nil {
-			return admission.Errored(http.StatusBadRequest, err)
-		}
-		err = ValidateWorkload(h.Client.RESTMapper(), obj)
-		if err != nil {
-			return admission.Denied(err.Error())
-		}
-
-		// validate cueTemplate
-		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
-			err = webhookutils.ValidateCuexTemplate(ctx, obj.Spec.Schematic.CUE.Template)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		if obj.Spec.Version != "" {
-			err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
-		if len(revisionName) != 0 {
-			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
-			err = webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName})
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		version := obj.Spec.Version
-		err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
-		if err != nil {
-			return admission.Denied(err.Error())
-		}
-	}
-	return admission.ValidationResponse(true, "")
-}
-
-// RegisterValidatingHandler will register ComponentDefinition validation to webhook
-func RegisterValidatingHandler(mgr manager.Manager) {
-	server := mgr.GetWebhookServer()
-	server.Register("/validating-core-oam-dev-v1beta1-componentdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
-		Client:  mgr.GetClient(),
-		Decoder: admission.NewDecoder(mgr.GetScheme()),
-	}})
-}
-
-// ValidateWorkload validates whether the Workload field is valid
-func ValidateWorkload(mapper meta.RESTMapper, cd *v1beta1.ComponentDefinition) error {
-
-	// If the Type and Definition are all empty, it will be rejected.
-	if cd.Spec.Workload.Type == "" && cd.Spec.Workload.Definition == (common.WorkloadGVK{}) {
-		return fmt.Errorf("neither the type nor the definition of the workload field in the ComponentDefinition %s can be empty", cd.Name)
-	}
-
-	// if Type and Definitiondon‘t point to the same workloaddefinition, it will be rejected.
-	if cd.Spec.Workload.Type != "" && cd.Spec.Workload.Definition != (common.WorkloadGVK{}) {
-		defRef, err := util.ConvertWorkloadGVK2Definition(mapper, cd.Spec.Workload.Definition)
-		if err != nil {
-			return err
-		}
-		if defRef.Name != cd.Spec.Workload.Type {
-			return fmt.Errorf("the type and the definition of the workload field in ComponentDefinition %s should represent the same workload", cd.Name)
-		}
-	}
-	return nil
-}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/policydefinition/policy_definition_validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/policydefinition/policy_definition_validating_handler.go
new file mode 100644
index 00000000..5246e5c2
--- /dev/null
+++ b/pkg/webhook/core.oam.dev/v1beta1/policydefinition/policy_definition_validating_handler.go
@@ -0,0 +1,129 @@
+/*
+ Copyright 2021. The KubeVela Authors.
+
+ Licensed 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 policydefinition
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"time"
+
+	admissionv1 "k8s.io/api/admission/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/webhook"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/logging"
+	"github.com/oam-dev/kubevela/pkg/oam"
+	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
+)
+
+var policyDefGVR = v1beta1.PolicyDefinitionGVR
+
+// ValidatingHandler handles validation of policy definition
+type ValidatingHandler struct {
+	// Decoder decodes object
+	Decoder admission.Decoder
+	Client  client.Client
+}
+
+var _ admission.Handler = &ValidatingHandler{}
+
+// Handle validate component definition
+func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
+	startTime := time.Now()
+	ctx = logging.WithRequestID(ctx, string(req.UID))
+	logger := logging.NewHandlerLogger(ctx, req, "PolicyDefinitionValidator")
+
+	logger.WithStep("start").Info("Starting admission validation for PolicyDefinition resource", "operation", req.Operation, "resourceVersion", req.Kind.Version)
+
+	obj := &v1beta1.PolicyDefinition{}
+	if req.Resource.String() != policyDefGVR.String() {
+		err := fmt.Errorf("expect resource to be %s", policyDefGVR)
+		logger.WithStep("resource-check").WithError(err).Error(err, "Admission request targets unexpected resource type - rejecting request",
+			"expected", policyDefGVR.String(),
+			"actual", req.Resource.String(),
+			"operation", req.Operation)
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
+		if err := h.Decoder.Decode(req, obj); err != nil {
+			logger.WithStep("decode").WithError(err).Error(err, "Unable to decode admission request payload into PolicyDefinition object - malformed request")
+			return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+		if obj.Spec.Version != "" {
+			logger = logger.WithValues("version", obj.Spec.Version)
+		}
+		logger.WithStep("decode").Info("Successfully decoded PolicyDefinition from admission request",
+			"definitionName", obj.Name,
+			"namespace", obj.Namespace,
+			"hasSchematic", obj.Spec.Schematic != nil,
+			"version", obj.Spec.Version)
+
+		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
+			logger.WithStep("validate-cue").Info("Validating CUE template syntax and semantics for PolicyDefinition schematic")
+			if err := webhookutils.ValidateCueTemplate(obj.Spec.Schematic.CUE.Template); err != nil {
+				logger.WithStep("validate-cue").WithError(err).Error(err, "CUE template contains syntax errors or invalid constructs - template compilation failed")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			if err := webhookutils.ValidateOutputResourcesExist(obj.Spec.Schematic.CUE.Template, h.Client.RESTMapper(), obj); err != nil {
+				logger.WithStep("validate-output-resources").WithError(err).Error(err, "CUE template references output resources that don't exist in cluster - unknown resource types detected")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-cue").WithSuccess(true).Info("CUE template validation completed successfully - template is syntactically correct and all output resources exist")
+		}
+
+		if obj.Spec.Version != "" {
+			if err := webhookutils.ValidateSemanticVersion(obj.Spec.Version); err != nil {
+				logger.WithStep("validate-version").WithError(err).Error(err, "PolicyDefinition version does not follow semantic versioning format (x.y.z)", "version", obj.Spec.Version, "expectedFormat", "x.y.z")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-version").Info("PolicyDefinition version follows semantic versioning format", "version", obj.Spec.Version)
+		}
+
+		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
+		if len(revisionName) != 0 {
+			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
+			if err := webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName}); err != nil {
+				logger.WithStep("validate-revision").WithError(err).Error(err, "PolicyDefinition revision conflicts with existing revision or has invalid format", "revisionName", revisionName, "expectedRevisionName", fmt.Sprintf("%s-v%s", obj.Name, revisionName))
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-revision").Info("PolicyDefinition revision validation completed - no conflicts detected", "revisionName", revisionName)
+		}
+
+		if err := webhookutils.ValidateMultipleDefVersionsNotPresent(obj.Spec.Version, revisionName, obj.Kind); err != nil {
+			logger.WithStep("validate-version-conflict").WithError(err).Error(err, "PolicyDefinition has conflicting version specifications - cannot have both spec.version and revision annotation", "specVersion", obj.Spec.Version, "revisionName", revisionName)
+			return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+		logger.WithStep("complete").WithSuccess(true, startTime).Info("PolicyDefinition admission validation completed successfully - resource is valid and will be admitted", "definitionName", obj.Name, "operation", req.Operation)
+	} else {
+		logger.WithStep("skip-validation").Info("Skipping PolicyDefinition validation - operation does not require validation", "operation", req.Operation, "reason", "only CREATE and UPDATE operations are validated")
+	}
+	return admission.ValidationResponse(true, "")
+}
+
+// RegisterValidatingHandler will register ComponentDefinition validation to webhook
+func RegisterValidatingHandler(mgr manager.Manager) {
+	server := mgr.GetWebhookServer()
+	server.Register("/validating-core-oam-dev-v1beta1-policydefinitions", &webhook.Admission{Handler: &ValidatingHandler{
+		Client:  mgr.GetClient(),
+		Decoder: admission.NewDecoder(mgr.GetScheme()),
+	}})
+}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler.go
deleted file mode 100644
index 464c7e85..00000000
--- a/pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler.go
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- Copyright 2021. The KubeVela Authors.
-
- Licensed 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 policydefinition
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-
-	admissionv1 "k8s.io/api/admission/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/manager"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
-	"github.com/oam-dev/kubevela/pkg/oam"
-	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
-)
-
-var policyDefGVR = v1beta1.PolicyDefinitionGVR
-
-// ValidatingHandler handles validation of policy definition
-type ValidatingHandler struct {
-	// Decoder decodes object
-	Decoder admission.Decoder
-	Client  client.Client
-}
-
-var _ admission.Handler = &ValidatingHandler{}
-
-// Handle validate component definition
-func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
-	obj := &v1beta1.PolicyDefinition{}
-	if req.Resource.String() != policyDefGVR.String() {
-		return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", policyDefGVR))
-	}
-
-	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
-		err := h.Decoder.Decode(req, obj)
-		if err != nil {
-			return admission.Errored(http.StatusBadRequest, err)
-		}
-
-		// validate cueTemplate
-		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
-			err = webhookutils.ValidateCueTemplate(obj.Spec.Schematic.CUE.Template)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		if obj.Spec.Version != "" {
-			err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
-		if len(revisionName) != 0 {
-			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
-			err = webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName})
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		version := obj.Spec.Version
-		err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
-		if err != nil {
-			return admission.Denied(err.Error())
-		}
-	}
-	return admission.ValidationResponse(true, "")
-}
-
-// RegisterValidatingHandler will register ComponentDefinition validation to webhook
-func RegisterValidatingHandler(mgr manager.Manager) {
-	server := mgr.GetWebhookServer()
-	server.Register("/validating-core-oam-dev-v1beta1-policydefinitions", &webhook.Admission{Handler: &ValidatingHandler{
-		Client:  mgr.GetClient(),
-		Decoder: admission.NewDecoder(mgr.GetScheme()),
-	}})
-}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler.go
new file mode 100644
index 00000000..105cda25
--- /dev/null
+++ b/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler.go
@@ -0,0 +1,188 @@
+/*
+Copyright 2021 The KubeVela Authors.
+
+Licensed 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 traitdefinition
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"time"
+
+	"github.com/pkg/errors"
+	admissionv1 "k8s.io/api/admission/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/webhook"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/appfile"
+	controller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
+	"github.com/oam-dev/kubevela/pkg/logging"
+	"github.com/oam-dev/kubevela/pkg/oam"
+	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
+)
+
+const (
+	errValidateDefRef = "error occurs when validating definition reference"
+
+	failInfoDefRefOmitted = "if definition reference is omitted, patch or output with GVK is required"
+)
+
+var traitDefGVR = v1beta1.TraitDefinitionGVR
+
+// ValidatingHandler handles validation of trait definition
+type ValidatingHandler struct {
+	Client client.Client
+
+	// Decoder decodes object
+	Decoder admission.Decoder
+	// Validators validate objects
+	Validators []TraitDefValidator
+}
+
+// TraitDefValidator validate trait definition
+type TraitDefValidator interface {
+	Validate(context.Context, v1beta1.TraitDefinition) error
+}
+
+// TraitDefValidatorFn implements TraitDefValidator
+type TraitDefValidatorFn func(context.Context, v1beta1.TraitDefinition) error
+
+// Validate implements TraitDefValidator method
+func (fn TraitDefValidatorFn) Validate(ctx context.Context, td v1beta1.TraitDefinition) error {
+	return fn(ctx, td)
+}
+
+var _ admission.Handler = &ValidatingHandler{}
+
+// Handle validate trait definition
+func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
+	startTime := time.Now()
+	ctx = logging.WithRequestID(ctx, string(req.UID))
+	logger := logging.NewHandlerLogger(ctx, req, "TraitDefinitionValidator")
+
+	logger.WithStep("start").Info("Starting admission validation for TraitDefinition resource", "operation", req.Operation, "resourceVersion", req.Kind.Version)
+
+	obj := &v1beta1.TraitDefinition{}
+	if req.Resource.String() != traitDefGVR.String() {
+		err := fmt.Errorf("expect resource to be %s", traitDefGVR)
+		logger.WithStep("resource-check").WithError(err).Error(err, "Admission request targets unexpected resource type - rejecting request",
+			"expected", traitDefGVR.String(),
+			"actual", req.Resource.String(),
+			"operation", req.Operation)
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
+		if err := h.Decoder.Decode(req, obj); err != nil {
+			logger.WithStep("decode").WithError(err).Error(err, "Unable to decode admission request payload into TraitDefinition object - malformed request")
+			return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+		if obj.Spec.Version != "" {
+			logger = logger.WithValues("version", obj.Spec.Version)
+		}
+		logger.WithStep("decode").Info("Successfully decoded TraitDefinition from admission request",
+			"definitionName", obj.Name,
+			"namespace", obj.Namespace,
+			"hasReference", len(obj.Spec.Reference.Name) > 0,
+			"hasSchematic", obj.Spec.Schematic != nil)
+
+		for i, validator := range h.Validators {
+			if err := validator.Validate(ctx, *obj); err != nil {
+				logger.WithStep(fmt.Sprintf("validator-%d", i)).WithError(err).Error(err, "TraitDefinition custom validator failed - definition does not meet validation requirements", "validatorIndex", i)
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+		}
+
+		// validate cueTemplate
+		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
+			logger.WithStep("validate-cue").Info("Validating CUE template syntax and semantics for TraitDefinition schematic")
+			if err := webhookutils.ValidateCuexTemplate(ctx, obj.Spec.Schematic.CUE.Template); err != nil {
+				logger.WithStep("validate-cue").WithError(err).Error(err, "CUE template contains syntax errors or invalid constructs - template compilation failed")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			if err := webhookutils.ValidateOutputResourcesExist(obj.Spec.Schematic.CUE.Template, h.Client.RESTMapper(), obj); err != nil {
+				logger.WithStep("validate-output-resources").WithError(err).Error(err, "CUE template references output resources that don't exist in cluster - unknown resource types detected")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+			logger.WithStep("validate-cue").WithSuccess(true).Info("CUE template validation completed successfully - template is syntactically correct and all output resources exist")
+		}
+
+		if obj.Spec.Version != "" {
+			if err := webhookutils.ValidateSemanticVersion(obj.Spec.Version); err != nil {
+				logger.WithStep("validate-version").WithError(err).Error(err, "TraitDefinition version does not follow semantic versioning format (x.y.z)", "version", obj.Spec.Version, "expectedFormat", "x.y.z")
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+		}
+
+		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
+		if len(revisionName) != 0 {
+			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
+			if err := webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName}); err != nil {
+				logger.WithStep("validate-revision").WithError(err).Error(err, "TraitDefinition revision conflicts with existing revision or has invalid format", "revisionName", revisionName, "expectedRevisionName", fmt.Sprintf("%s-v%s", obj.Name, revisionName))
+				return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+			}
+		}
+
+		version := obj.Spec.Version
+		if err := webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind); err != nil {
+			logger.WithStep("validate-version-conflict").WithError(err).Error(err, "TraitDefinition has conflicting version specifications - cannot have both spec.version and revision annotation", "specVersion", version, "revisionName", revisionName)
+			return admission.Denied(fmt.Sprintf("%s (requestUID=%s)", err.Error(), req.UID))
+		}
+		logger.WithStep("complete").WithSuccess(true, startTime).Info("TraitDefinition admission validation completed successfully - resource is valid and will be admitted", "definitionName", obj.Name, "operation", req.Operation)
+	} else {
+		logger.WithStep("skip-validation").Info("Skipping TraitDefinition validation - operation does not require validation", "operation", req.Operation, "reason", "only CREATE and UPDATE operations are validated")
+	}
+	return admission.ValidationResponse(true, "")
+}
+
+// RegisterValidatingHandler will register TraitDefinition validation to webhook
+func RegisterValidatingHandler(mgr manager.Manager, _ controller.Args) {
+	server := mgr.GetWebhookServer()
+	server.Register("/validating-core-oam-dev-v1beta1-traitdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
+		Client:  mgr.GetClient(),
+		Decoder: admission.NewDecoder(mgr.GetScheme()),
+		Validators: []TraitDefValidator{
+			TraitDefValidatorFn(ValidateDefinitionReference),
+			// add more validators here
+		},
+	}})
+}
+
+// ValidateDefinitionReference validates whether the trait definition is valid if
+// its `.spec.reference` field is unset.
+// It's valid if
+// it has at least one output, and all outputs must have GVK
+// or it has no output but has a patch
+// or it has a patch and outputs, and all outputs must have GVK
+// TODO(roywang) currently we only validate whether it contains CUE template.
+// Further validation, e.g., output with GVK, valid patch, etc, remains to be done.
+func ValidateDefinitionReference(_ context.Context, td v1beta1.TraitDefinition) error {
+	if len(td.Spec.Reference.Name) > 0 {
+		return nil
+	}
+	capability, err := appfile.ConvertTemplateJSON2Object(td.Name, td.Spec.Extension, td.Spec.Schematic)
+	if err != nil {
+		return errors.WithMessage(err, errValidateDefRef)
+	}
+	if capability.CueTemplate == "" {
+		return errors.New(failInfoDefRefOmitted)
+
+	}
+	return nil
+}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler.go
deleted file mode 100644
index a850ae30..00000000
--- a/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler.go
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-Copyright 2021 The KubeVela Authors.
-
-Licensed 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 traitdefinition
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-
-	"github.com/pkg/errors"
-	admissionv1 "k8s.io/api/admission/v1"
-	"k8s.io/klog/v2"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/manager"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
-	"github.com/oam-dev/kubevela/pkg/appfile"
-	controller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
-	"github.com/oam-dev/kubevela/pkg/oam"
-	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
-)
-
-const (
-	errValidateDefRef = "error occurs when validating definition reference"
-
-	failInfoDefRefOmitted = "if definition reference is omitted, patch or output with GVK is required"
-)
-
-var traitDefGVR = v1beta1.TraitDefinitionGVR
-
-// ValidatingHandler handles validation of trait definition
-type ValidatingHandler struct {
-	Client client.Client
-
-	// Decoder decodes object
-	Decoder admission.Decoder
-	// Validators validate objects
-	Validators []TraitDefValidator
-}
-
-// TraitDefValidator validate trait definition
-type TraitDefValidator interface {
-	Validate(context.Context, v1beta1.TraitDefinition) error
-}
-
-// TraitDefValidatorFn implements TraitDefValidator
-type TraitDefValidatorFn func(context.Context, v1beta1.TraitDefinition) error
-
-// Validate implements TraitDefValidator method
-func (fn TraitDefValidatorFn) Validate(ctx context.Context, td v1beta1.TraitDefinition) error {
-	return fn(ctx, td)
-}
-
-var _ admission.Handler = &ValidatingHandler{}
-
-// Handle validate trait definition
-func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
-	obj := &v1beta1.TraitDefinition{}
-	if req.Resource.String() != traitDefGVR.String() {
-		return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", traitDefGVR))
-	}
-
-	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
-		err := h.Decoder.Decode(req, obj)
-		if err != nil {
-			return admission.Errored(http.StatusBadRequest, err)
-		}
-		klog.Info("validating ", " name: ", obj.Name, " operation: ", string(req.Operation))
-		for _, validator := range h.Validators {
-			if err := validator.Validate(ctx, *obj); err != nil {
-				klog.Info("validation failed ", " name: ", obj.Name, " errMsgi: ", err.Error())
-				return admission.Denied(err.Error())
-			}
-		}
-
-		// validate cueTemplate
-		if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
-			err = webhookutils.ValidateCuexTemplate(ctx, obj.Spec.Schematic.CUE.Template)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		if obj.Spec.Version != "" {
-			err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
-		if len(revisionName) != 0 {
-			defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
-			err = webhookutils.ValidateDefinitionRevision(ctx, h.Client, obj, client.ObjectKey{Namespace: obj.Namespace, Name: defRevName})
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-
-		version := obj.Spec.Version
-		err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
-		if err != nil {
-			return admission.Denied(err.Error())
-		}
-		klog.Info("validation passed ", " name: ", obj.Name, " operation: ", string(req.Operation))
-	}
-	return admission.ValidationResponse(true, "")
-}
-
-// RegisterValidatingHandler will register TraitDefinition validation to webhook
-func RegisterValidatingHandler(mgr manager.Manager, _ controller.Args) {
-	server := mgr.GetWebhookServer()
-	server.Register("/validating-core-oam-dev-v1beta1-traitdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
-		Client:  mgr.GetClient(),
-		Decoder: admission.NewDecoder(mgr.GetScheme()),
-		Validators: []TraitDefValidator{
-			TraitDefValidatorFn(ValidateDefinitionReference),
-			// add more validators here
-		},
-	}})
-}
-
-// ValidateDefinitionReference validates whether the trait definition is valid if
-// its `.spec.reference` field is unset.
-// It's valid if
-// it has at least one output, and all outputs must have GVK
-// or it has no output but has a patch
-// or it has a patch and outputs, and all outputs must have GVK
-// TODO(roywang) currently we only validate whether it contains CUE template.
-// Further validation, e.g., output with GVK, valid patch, etc, remains to be done.
-func ValidateDefinitionReference(_ context.Context, td v1beta1.TraitDefinition) error {
-	if len(td.Spec.Reference.Name) > 0 {
-		return nil
-	}
-	capability, err := appfile.ConvertTemplateJSON2Object(td.Name, td.Spec.Extension, td.Spec.Schematic)
-	if err != nil {
-		return errors.WithMessage(err, errValidateDefRef)
-	}
-	if capability.CueTemplate == "" {
-		return errors.New(failInfoDefRefOmitted)
-
-	}
-	return nil
-}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/validating_handler.go
deleted file mode 100644
index f430d368..00000000
--- a/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/validating_handler.go
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-Copyright 2024 The KubeVela Authors.
-
-Licensed 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 workflowstepdefinition
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-
-	admissionv1 "k8s.io/api/admission/v1"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/manager"
-	"sigs.k8s.io/controller-runtime/pkg/webhook"
-	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
-	"github.com/oam-dev/kubevela/pkg/oam"
-	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
-)
-
-var workflowStepDefGVR = v1beta1.WorkflowStepDefinitionGVR
-
-// ValidatingHandler handles validation of workflow step definition
-type ValidatingHandler struct {
-	// Decoder decodes object
-	Decoder admission.Decoder
-	Client  client.Client
-}
-
-// InjectClient injects the client into the ValidatingHandler
-func (h *ValidatingHandler) InjectClient(c client.Client) error {
-	h.Client = c
-	return nil
-}
-
-// InjectDecoder injects the decoder into the ValidatingHandler
-func (h *ValidatingHandler) InjectDecoder(d admission.Decoder) error {
-	h.Decoder = d
-	return nil
-}
-
-// Handle validate WorkflowStepDefinition Spec here
-func (h *ValidatingHandler) Handle(_ context.Context, req admission.Request) admission.Response {
-	obj := &v1beta1.WorkflowStepDefinition{}
-	if req.Resource.String() != workflowStepDefGVR.String() {
-		return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", workflowStepDefGVR))
-	}
-
-	if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
-		err := h.Decoder.Decode(req, obj)
-		if err != nil {
-			return admission.Errored(http.StatusBadRequest, err)
-		}
-
-		if obj.Spec.Version != "" {
-			err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
-			if err != nil {
-				return admission.Denied(err.Error())
-			}
-		}
-		revisionName := obj.Annotations[oam.AnnotationDefinitionRevisionName]
-		version := obj.Spec.Version
-		err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
-		if err != nil {
-			return admission.Denied(err.Error())
-		}
-	}
-	return admission.ValidationResponse(true, "")
-}
-
-// RegisterValidatingHandler will register WorkflowStepDefinition validation to webhook
-func RegisterValidatingHandler(mgr manager.Manager) {
-	server := mgr.GetWebhookServer()
-	server.Register("/validating-core-oam-dev-v1beta1-workflowstepdefinitions", &webhook.Admission{Handler: &ValidatingHandler{}})
-}
diff --git a/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler.go b/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler.go
new file mode 100644
index 00000000..e159af12
--- /dev/null
+++ b/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler.go
@@ -0,0 +1,148 @@
+/*
+Copyright 2024 The KubeVela Authors.
+
+Licensed 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 workflowstepdefinition provides admission control validation
+// for WorkflowStepDefinition resources in KubeVela.
+package workflowstepdefinition
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"time"
+
+	admissionv1 "k8s.io/api/admission/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/webhook"
+	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/logging"
+	"github.com/oam-dev/kubevela/pkg/oam"
+	webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
+)
+
+const (
+	// ValidationWebhookPath defines the HTTP path for the validation webhook
+	ValidationWebhookPath = "/validating-core-oam-dev-v1beta1-workflowstepdefinitions"
+)
+
+var (
+	workflowStepDefGVR = v1beta1.WorkflowStepDefinitionGVR
+)
+
+// ValidatingHandler handles validation of WorkflowStepDefinition resources.
+type ValidatingHandler struct {
+	Decoder admission.Decoder
+	Client  client.Client
+}
+
+// InjectClient injects the Kubernetes client into the handler.
+func (h *ValidatingHandler) InjectClient(c client.Client) error {
+	h.Client = c
+	return nil
+}
+
+// InjectDecoder injects the admission decoder into the handler.
+func (h *ValidatingHandler) InjectDecoder(d admission.Decoder) error {
+	h.Decoder = d
+	return nil
+}
+
+// Handle validates WorkflowStepDefinition resources during admission control.
+func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
+	startTime := time.Now()
+	ctx = logging.WithRequestID(ctx, string(req.UID))
+	logger := logging.NewHandlerLogger(ctx, req, "WorkflowStepDefinitionValidator")
+
+	logger.WithStep("start").Info("Starting admission validation for WorkflowStepDefinition resource", "operation", req.Operation, "resourceVersion", req.Kind.Version)
+
+	// Validate resource type
+	if req.Resource.String() != workflowStepDefGVR.String() {
+		err := fmt.Errorf("expected resource to be %s, got %s", workflowStepDefGVR, req.Resource.String())
+		logger.WithStep("resource-check").WithError(err).Error(err, "Admission request targets unexpected resource type - rejecting request",
+			"expected", workflowStepDefGVR.String(),
+			"actual", req.Resource.String(),
+			"operation", req.Operation)
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	// Only validate create and update operations
+	if req.Operation != admissionv1.Create && req.Operation != admissionv1.Update {
+		logger.WithStep("skip-validation").Info("Skipping WorkflowStepDefinition validation - operation does not require validation", "operation", req.Operation, "reason", "only CREATE and UPDATE operations are validated")
+		return admission.ValidationResponse(true, "Operation does not require validation")
+	}
+
+	// Decode the object
+	obj := &v1beta1.WorkflowStepDefinition{}
+	if err := h.Decoder.Decode(req, obj); err != nil {
+		logger.WithStep("decode").WithError(err).Error(err, "Unable to decode admission request payload into WorkflowStepDefinition object - malformed request")
+		return admission.Errored(http.StatusBadRequest, fmt.Errorf("failed to decode: %s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	if obj.Spec.Version != "" {
+		logger = logger.WithValues("version", obj.Spec.Version)
+	}
+	logger.WithStep("decode").Info("Successfully decoded WorkflowStepDefinition from admission request",
+		"definitionName", obj.Name,
+		"namespace", obj.Namespace,
+		"hasSchematic", obj.Spec.Schematic != nil,
+		"version", obj.Spec.Version)
+
+	// Validate output resources
+	if obj.Spec.Schematic != nil && obj.Spec.Schematic.CUE != nil {
+		logger.WithStep("validate-output-resources").Info("Validating output resources referenced in WorkflowStepDefinition CUE template")
+		if err := webhookutils.ValidateOutputResourcesExist(obj.Spec.Schematic.CUE.Template, h.Client.RESTMapper(), obj); err != nil {
+			logger.WithStep("validate-output-resources").WithError(err).Error(err, "CUE template references output resources that don't exist in cluster - unknown resource types detected")
+			return admission.Denied(fmt.Sprintf("output resource validation failed: %s (requestUID=%s)", err.Error(), req.UID))
+		}
+		logger.WithStep("validate-output-resources").WithSuccess(true).Info("Output resources validation completed successfully - all referenced resources exist in cluster")
+	}
+
+	// Validate semantic version
+	if obj.Spec.Version != "" {
+		if err := webhookutils.ValidateSemanticVersion(obj.Spec.Version); err != nil {
+			logger.WithStep("validate-version").WithError(err).Error(err, "WorkflowStepDefinition version does not follow semantic versioning format (x.y.z)", "version", obj.Spec.Version, "expectedFormat", "x.y.z")
+			return admission.Denied(fmt.Sprintf("semantic version validation failed: %s (requestUID=%s)", err.Error(), req.UID))
+		}
+		logger.WithStep("validate-version").Info("WorkflowStepDefinition version follows semantic versioning format", "version", obj.Spec.Version)
+	}
+
+	// Validate version conflicts
+	revisionName := obj.Annotations[oam.AnnotationDefinitionRevisionName]
+	if err := webhookutils.ValidateMultipleDefVersionsNotPresent(obj.Spec.Version, revisionName, obj.Kind); err != nil {
+		logger.WithStep("validate-version-conflict").WithError(err).Error(err, "WorkflowStepDefinition has conflicting version specifications - cannot have both spec.version and revision annotation", "specVersion", obj.Spec.Version, "revisionName", revisionName)
+		return admission.Denied(fmt.Sprintf("definition version conflict: %s (requestUID=%s)", err.Error(), req.UID))
+	}
+
+	logger.WithStep("complete").WithSuccess(true, startTime).Info("WorkflowStepDefinition admission validation completed successfully - resource is valid and will be admitted", "definitionName", obj.Name, "operation", req.Operation)
+	return admission.ValidationResponse(true, "Validation passed")
+}
+
+// RegisterValidatingHandler registers the WorkflowStepDefinition validation webhook with the manager.
+func RegisterValidatingHandler(mgr manager.Manager) {
+	logger := logging.New()
+	logger.Info("Registering WorkflowStepDefinition validation webhook", "path", ValidationWebhookPath)
+
+	server := mgr.GetWebhookServer()
+	server.Register(ValidationWebhookPath, &webhook.Admission{
+		Handler: &ValidatingHandler{
+			Client:  mgr.GetClient(),
+			Decoder: admission.NewDecoder(mgr.GetScheme()),
+		},
+	})
+}
diff --git a/pkg/webhook/utils/invalid_resource_check.go b/pkg/webhook/utils/invalid_resource_check.go
new file mode 100644
index 00000000..2f2d336c
--- /dev/null
+++ b/pkg/webhook/utils/invalid_resource_check.go
@@ -0,0 +1,257 @@
+/*
+ Copyright 2021. The KubeVela Authors.
+
+ Licensed 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 utils
+
+import (
+	"fmt"
+	"strings"
+
+	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/cue/parser"
+	"cuelang.org/go/cue/token"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	"github.com/oam-dev/kubevela/pkg/features"
+)
+
+// ExtractResourceInfo extracts apiVersion and kind from CUE template without evaluation
+func ExtractResourceInfo(cueTemplate string) ([]ResourceInfo, error) {
+	file, err := parser.ParseFile("", cueTemplate, parser.ParseComments)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse CUE template: %w", err)
+	}
+
+	var resources []ResourceInfo
+
+	// Walk through the AST to find output and outputs fields
+	ast.Walk(file, func(node ast.Node) bool {
+		if n, ok := node.(*ast.Field); ok {
+			label := extractLabel(n.Label)
+			if label == "output" || label == "outputs" {
+				if label == "output" {
+					// Extract from single output field
+					if resource := extractResourceFromStruct(n.Value); resource != nil {
+						resources = append(resources, *resource)
+					}
+				} else if label == "outputs" {
+					// Extract from outputs field (multiple resources)
+					resources = append(resources, extractResourcesFromOutputs(n.Value)...)
+				}
+			}
+		}
+		return true
+	}, nil)
+
+	return resources, nil
+}
+
+type ResourceInfo struct {
+	APIVersion string
+	Kind       string
+	Name       string // optional, for better error messages
+}
+
+func extractLabel(label ast.Label) string {
+	switch l := label.(type) {
+	case *ast.Ident:
+		return l.Name
+	case *ast.BasicLit:
+		if l.Kind == token.STRING {
+			// Remove quotes
+			return strings.Trim(l.Value, `"`)
+		}
+	}
+	return ""
+}
+
+func extractResourceFromStruct(expr ast.Expr) *ResourceInfo {
+	structLit, ok := expr.(*ast.StructLit)
+	if !ok {
+		return nil
+	}
+
+	resource := &ResourceInfo{}
+
+	for _, elt := range structLit.Elts {
+		field, ok := elt.(*ast.Field)
+		if !ok {
+			continue
+		}
+
+		label := extractLabel(field.Label)
+		value := extractStringValue(field.Value)
+
+		switch label {
+		case "apiVersion":
+			resource.APIVersion = value
+		case "kind":
+			resource.Kind = value
+		case "metadata":
+			// Try to extract name from metadata.name
+			if name := extractNameFromMetadata(field.Value); name != "" {
+				resource.Name = name
+			}
+		}
+	}
+
+	// Only return if we have both apiVersion and kind
+	if resource.APIVersion != "" && resource.Kind != "" {
+		return resource
+	}
+	return nil
+}
+
+func extractResourcesFromOutputs(expr ast.Expr) []ResourceInfo {
+	var resources []ResourceInfo
+
+	structLit, ok := expr.(*ast.StructLit)
+	if !ok {
+		return resources
+	}
+
+	for _, elt := range structLit.Elts {
+		field, ok := elt.(*ast.Field)
+		if !ok {
+			continue
+		}
+
+		if resource := extractResourceFromStruct(field.Value); resource != nil {
+			// Use the field label as the resource name if not found in metadata
+			if resource.Name == "" {
+				resource.Name = extractLabel(field.Label)
+			}
+			resources = append(resources, *resource)
+		}
+	}
+
+	return resources
+}
+
+func extractStringValue(expr ast.Expr) string {
+	if e, ok := expr.(*ast.BasicLit); ok {
+		if e.Kind == token.STRING {
+			return strings.Trim(e.Value, `"`)
+		}
+	}
+	return ""
+}
+
+func extractNameFromMetadata(expr ast.Expr) string {
+	structLit, ok := expr.(*ast.StructLit)
+	if !ok {
+		return ""
+	}
+
+	for _, elt := range structLit.Elts {
+		field, ok := elt.(*ast.Field)
+		if !ok {
+			continue
+		}
+
+		if extractLabel(field.Label) == "name" {
+			return extractStringValue(field.Value)
+		}
+	}
+	return ""
+}
+
+// ValidateOutputResourcesExist validates that resources referenced in output/outputs fields exist on the cluster
+func ValidateOutputResourcesExist(cueTemplate string, mapper meta.RESTMapper, obj client.Object) error {
+	// Check if feature gate is enabled FIRST before doing anything
+	if !utilfeature.DefaultMutableFeatureGate.Enabled(features.ValidateResourcesExist) {
+		return nil // Skip validation if feature is disabled
+	}
+
+	// Skip validation for addon definitions
+	// Addons often bundle CRDs with definitions that reference them
+	if IsAddonDefinition(obj) {
+		return nil
+	}
+
+	// Only extract and validate resources if feature is enabled and not an addon
+	resources, err := ExtractResourceInfo(cueTemplate)
+	if err != nil {
+		return fmt.Errorf("failed to extract resource info: %w", err)
+	}
+
+	for _, resource := range resources {
+		gvk := schema.GroupVersionKind{
+			Version: resource.APIVersion,
+			Kind:    resource.Kind,
+		}
+
+		// Parse the apiVersion to get group and version
+		if strings.Contains(resource.APIVersion, "/") {
+			parts := strings.SplitN(resource.APIVersion, "/", 2)
+			gvk.Group = parts[0]
+			gvk.Version = parts[1]
+		} else {
+			// Core API resources (like v1) don't have a group
+			gvk.Group = ""
+			gvk.Version = resource.APIVersion
+		}
+
+		_, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+		if err != nil {
+			ref := fmt.Sprintf("%s/%s", resource.APIVersion, resource.Kind)
+			return fmt.Errorf("resource type not found on cluster: %s (%w)", ref, err)
+		}
+	}
+
+	return nil
+}
+
+// IsAddonDefinition checks if the object is part of an addon installation
+// This is a generic solution that works for ALL addons by checking owner references
+func IsAddonDefinition(obj client.Object) bool {
+	if obj == nil {
+		return false
+	}
+
+	// Generic approach: Check if the object has an owner reference to an addon application
+	// All addon definitions get owner references to their addon application (pattern: addon-{name})
+	for _, ownerRef := range obj.GetOwnerReferences() {
+		if ownerRef.Kind == "Application" &&
+			ownerRef.APIVersion == "core.oam.dev/v1beta1" &&
+			strings.HasPrefix(ownerRef.Name, "addon-") {
+			return true
+		}
+	}
+
+	// Fallback checks for edge cases where owner references might not be set yet
+	labels := obj.GetLabels()
+	if labels != nil {
+		// Check if this is managed by an addon application
+		appName, hasApp := labels["app.oam.dev/name"]
+		if hasApp && strings.HasPrefix(appName, "addon-") {
+			return true
+		}
+	}
+
+	// Also check annotations for addon markers
+	annotations := obj.GetAnnotations()
+	if annotations != nil {
+		if addonName, hasAddon := annotations["addons.oam.dev/name"]; hasAddon && addonName != "" {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/references/appfile/addon.go b/references/appfile/addon.go
index 5e88da79..448ba298 100644
--- a/references/appfile/addon.go
+++ b/references/appfile/addon.go
@@ -95,11 +95,7 @@ func ApplyTerraform(app *v1beta1.Application, k8sClient client.Client, ioStream
 				return nil, err
 			}
 
-			outputList := strings.Split(strings.ReplaceAll(string(outputs), " ", ""), "\n")
-			if outputList[len(outputList)-1] == "" {
-				outputList = outputList[:len(outputList)-1]
-			}
-			if err := generateSecretFromTerraformOutput(k8sClient, outputList, name, namespace); err != nil {
+			if err := generateSecretFromTerraformOutput(k8sClient, string(outputs), name, namespace); err != nil {
 				return nil, err
 			}
 		default:
@@ -135,21 +131,32 @@ func callTerraform(tfJSONDir string) ([]byte, error) {
 }
 
 // generateSecretFromTerraformOutput generates secret from Terraform output
-func generateSecretFromTerraformOutput(k8sClient client.Client, outputList []string, name, namespace string) error {
+func generateSecretFromTerraformOutput(k8sClient client.Client, rawOutput string, name, namespace string) error {
 	ctx := context.TODO()
-	err := k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}})
-	if err == nil {
-		return fmt.Errorf("namespace %s doesn't exist", namespace)
+
+	// Check if namespace exists
+	var ns v1.Namespace
+	if err := k8sClient.Get(ctx, client.ObjectKey{Name: namespace}, &ns); err != nil {
+		if errors.IsNotFound(err) {
+			return fmt.Errorf("namespace %s doesn't exist", namespace)
+		}
+		return fmt.Errorf("failed to get namespace %s: %w", namespace, err)
 	}
-	var cmData = make(map[string]string, len(outputList))
+
+	var cmData = make(map[string]string)
+	outputList := strings.Split(rawOutput, "\n")
 	for _, i := range outputList {
-		line := strings.Split(i, "=")
+		if strings.TrimSpace(i) == "" {
+			continue
+		}
+		line := strings.SplitN(i, "=", 2)
 		if len(line) != 2 {
-			return fmt.Errorf("terraform output isn't in the right format")
+			return fmt.Errorf("terraform output isn't in the right format: %q", i)
 		}
 		k := strings.TrimSpace(line[0])
-		v := strings.TrimSpace(line[1])
-		if k != "" && v != "" {
+		// Terraform string outputs are quoted, remove them.
+		v := strings.Trim(strings.TrimSpace(line[1]), "\"")
+		if k != "" {
 			cmData[k] = v
 		}
 	}



Test patch:
diff --git a/.github/actions/e2e-test/README.md b/.github/actions/e2e-test/README.md
new file mode 100644
index 00000000..ef5ca8b9
--- /dev/null
+++ b/.github/actions/e2e-test/README.md
@@ -0,0 +1,51 @@
+# Kubevela K8s Upgrade E2E Test Action
+
+A comprehensive GitHub composite action for running KubeVela Kubernetes upgrade end-to-end (E2E) tests with complete environment setup, multiple test suites, and failure diagnostics.
+
+
+> **Note**: This action requires the `GO_VERSION` environment variable to be set in your workflow.
+
+## Quick Start
+
+### Basic Usage
+
+```yaml
+name: E2E Tests
+on: [push, pull_request]
+
+jobs:
+  e2e-tests:
+    runs-on: ubuntu-latest
+    env:
+      GO_VERSION: '1.23.8'
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+        
+      - name: Run KubeVela E2E Tests
+        uses: ./.github/actions/upgrade-e2e-test
+```
+
+## Test Flow Diagram
+
+```
+┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
+│ Environment     │    │ E2E Environment  │    │ Test Execution  │
+│ Setup           │───▶│ Preparation      │───▶│ (3 Suites)      │
+│                 │    │                  │    │                 │
+│ • Install tools │    │ • Cleanup        │    │ • API tests     │
+│ • Setup Go      │    │ • Core setup     │    │ • Addon tests   │
+│ • Dependencies  │    │ • Helm tests     │    │ • General tests │
+│ • Build project │    │                  │    │                 │
+└─────────────────┘    └──────────────────┘    └─────────────────┘
+                                                        │
+                                                        ▼
+                                                ┌─────────────────┐
+                                                │ Diagnostics     │
+                                                │ (On Failure)    │
+                                                │                 │
+                                                │ • Cluster logs  │
+                                                │ • System events │
+                                                │ • Test artifacts│
+                                                └─────────────────┘
+```
\ No newline at end of file
diff --git a/.github/actions/e2e-test/action.yaml b/.github/actions/e2e-test/action.yaml
new file mode 100644
index 00000000..068d6959
--- /dev/null
+++ b/.github/actions/e2e-test/action.yaml
@@ -0,0 +1,96 @@
+name: 'Kubevela K8s Upgrade e2e Test'
+description: 'Runs Kubevela K8s upgrade e2e tests, uploads coverage, and collects diagnostics on failure.'
+
+inputs:
+  codecov-token:
+    description: 'Codecov token for uploading coverage reports'
+    required: false
+    default: ''
+  codecov-enable:
+    description: 'Enable codecov coverage upload'
+    required: false
+    default: 'false'
+
+runs:
+  using: "composite"
+  steps:
+    # ========================================================================
+    # Environment Setup
+    # ========================================================================
+    - name: Configure environment setup
+      uses: ./.github/actions/env-setup
+
+    - name: Build project
+      shell: bash
+      run: make
+
+    # ========================================================================
+    # E2E Test Environment Preparation
+    # ========================================================================
+    - name: Prepare e2e environment
+      shell: bash
+      run: |
+        echo "Preparing e2e test environment..."
+        make e2e-cleanup
+        make e2e-setup-core
+
+        echo "Running Helm tests..."
+        helm test -n vela-system kubevela --timeout 5m
+
+    # ========================================================================
+    # E2E Test Execution
+    # ========================================================================
+    - name: Run API e2e tests
+      shell: bash
+      run: |
+        echo "Running API e2e tests..."
+        make e2e-api-test
+
+    - name: Run addon e2e tests
+      shell: bash
+      run: |
+        echo "Running addon e2e tests..."
+        make e2e-addon-test
+
+    - name: Run general e2e tests
+      shell: bash
+      run: |
+        echo "Running general e2e tests..."
+        make e2e-test
+
+    - name: Upload coverage report
+      if: ${{ inputs.codecov-enable == 'true' }}
+      uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
+      with:
+        token: ${{ inputs.codecov-token }}
+        files: ./coverage.txt
+        flags: core-unittests
+        name: codecov-umbrella
+        fail_ci_if_error: false
+
+    # ========================================================================
+    # Failure Diagnostics
+    # ========================================================================
+    - name: Collect failure diagnostics
+      if: failure()
+      shell: bash
+      run: |
+        echo "=== FAILURE DIAGNOSTICS ==="
+        echo "Collecting diagnostic information for debugging..."
+
+        echo "--- Cluster Status ---"
+        kubectl get nodes -o wide || true
+        kubectl get pods -A || true
+
+        echo "--- KubeVela System Logs ---"
+        kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
+
+        echo "--- Recent Events ---"
+        kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
+
+        echo "--- Helm Release Status ---"
+        helm list -A || true
+        helm status kubevela -n vela-system || true
+
+        echo "--- Test Artifacts ---"
+        find . -name "*.log" -type f -exec echo "=== {} ===" \; -exec cat {} \; || true
\ No newline at end of file
diff --git a/.github/actions/multicluster-test/README.md b/.github/actions/multicluster-test/README.md
new file mode 100644
index 00000000..45c69ef5
--- /dev/null
+++ b/.github/actions/multicluster-test/README.md
@@ -0,0 +1,35 @@
+# Kubevela K8s Upgrade Multicluster E2E Test Action
+
+A comprehensive GitHub Actions composite action for running Kubevela Kubernetes upgrade multicluster end-to-end tests with automated coverage reporting and failure diagnostics.
+
+## Usage
+
+
+```yaml
+name: Kubevela Multicluster E2E Tests
+on:
+  push:
+    branches: [main, develop]
+  pull_request:
+    branches: [main]
+
+jobs:
+  multicluster-e2e:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - name: Run Multicluster E2E Tests
+        uses: ./.github/actions/multicluster-test
+        with:
+          codecov-enable: 'true'
+          codecov-token: ${{ secrets.CODECOV_TOKEN }}
+```
+
+## Inputs
+
+| Input | Description | Required | Default | Type |
+|-------|-------------|----------|---------|------|
+| `codecov-token` | Codecov token for uploading coverage reports | No | `''` | string |
+| `codecov-enable` | Enable codecov coverage upload | No | `'false'` | string |
diff --git a/.github/actions/multicluster-test/action.yaml b/.github/actions/multicluster-test/action.yaml
new file mode 100644
index 00000000..61e5882c
--- /dev/null
+++ b/.github/actions/multicluster-test/action.yaml
@@ -0,0 +1,76 @@
+name: 'Kubevela K8s Upgrade Multicluster E2E Test'
+description: 'Runs Kubevela Kubernetes upgrade multicluster end-to-end tests, uploads coverage, and collects diagnostics on failure.'
+author: 'viskumar_gwre'
+
+inputs:
+  codecov-token:
+    description: 'Codecov token for uploading coverage reports'
+    required: false
+    default: ''
+  codecov-enable:
+    description: 'Enable codecov coverage upload'
+    required: false
+    default: 'false'
+
+runs:
+  using: 'composite'
+  steps:
+    # ========================================================================
+    # Environment Setup
+    # ========================================================================
+    - name: Configure environment setup
+      uses: ./.github/actions/env-setup
+
+    # ========================================================================
+    # E2E Test Execution
+    # ========================================================================
+    - name: Prepare e2e test environment
+      shell: bash
+      run: |
+        # Build CLI tools and prepare test environment
+        echo "Building KubeVela CLI..."
+        make vela-cli
+
+        echo "Cleaning up previous test artifacts..."
+        make e2e-cleanup
+
+        echo "Setting up core authentication for e2e tests..."
+        make e2e-setup-core-auth
+
+    - name: Execute multicluster upgrade e2e tests
+      shell: bash
+      run: |
+        # Add built CLI to PATH and run multicluster tests
+        export PATH=$(pwd)/bin:$PATH
+
+        echo "Running e2e multicluster upgrade tests..."
+        make e2e-multicluster-test
+
+    - name: Upload coverage report
+      if: ${{ inputs.codecov-enable == 'true' }}
+      uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
+      with:
+        token: ${{ inputs.codecov-token }}
+        files: /tmp/e2e-profile.out,/tmp/e2e_multicluster_test.out
+        flags: e2e-multicluster-test
+        name: codecov-umbrella
+
+    # ========================================================================
+    # Failure Diagnostics
+    # ========================================================================
+    - name: Collect failure diagnostics
+      if: failure()
+      shell: bash
+      run: |
+        echo "=== FAILURE DIAGNOSTICS ==="
+        echo "Collecting diagnostic information for debugging..."
+
+        echo "--- Cluster Status ---"
+        kubectl get nodes -o wide || true
+        kubectl get pods -A || true
+
+        echo "--- KubeVela System Logs ---"
+        kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
+
+        echo "--- Recent Events ---"
+        kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
\ No newline at end of file
diff --git a/.github/actions/unit-test/README.md b/.github/actions/unit-test/README.md
new file mode 100644
index 00000000..492389bc
--- /dev/null
+++ b/.github/actions/unit-test/README.md
@@ -0,0 +1,34 @@
+# Kubevela K8s Upgrade Unit Test Action
+
+A comprehensive GitHub composite action for running KubeVela Kubernetes upgrade unit tests with coverage reporting and failure diagnostics.
+
+## Inputs
+
+| Input | Description | Required | Default |
+|-------|-------------|----------|---------|
+| `codecov-token` | Codecov token for uploading coverage reports | ❌ | `''` |
+| `codecov-enable` | Enable Codecov coverage upload (`'true'` or `'false'`) | ❌ | `'false'` |
+| `go-version` | Go version to use for testing | ❌ | `'1.23.8'` |
+
+## Quick Start
+
+### Basic Usage
+
+```yaml
+name: Unit Tests with Coverage
+on: [push, pull_request]
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+        
+      - name: Run KubeVela Unit Tests
+        uses: viskumar_gwre/kubevela-k8s-upgrade-unit-test-action@v1
+        with:
+          codecov-enable: 'true'
+          codecov-token: ${{ secrets.CODECOV_TOKEN }}
+          go-version: '1.23.8'
+```
\ No newline at end of file
diff --git a/.github/actions/unit-test/action.yaml b/.github/actions/unit-test/action.yaml
new file mode 100644
index 00000000..e5cf2e19
--- /dev/null
+++ b/.github/actions/unit-test/action.yaml
@@ -0,0 +1,67 @@
+name: 'Kubevela K8s Upgrade Unit Test'
+description: 'Runs Kubevela K8s upgrade unit tests, uploads coverage, and collects diagnostics on failure.'
+
+inputs:
+  codecov-token:
+    description: 'Codecov token for uploading coverage reports'
+    required: false
+    default: ''
+  codecov-enable:
+    description: 'Enable codecov coverage upload'
+    required: false
+    default: 'false'
+
+runs:
+  using: "composite"
+  steps:
+    # ========================================================================
+    # Environment Setup
+    # ========================================================================
+    - name: Configure environment setup
+      uses: ./.github/actions/env-setup
+
+    # ========================================================================
+    # Unit Test Execution
+    # ========================================================================
+    - name: Run unit tests
+      shell: bash
+      run: |
+        echo "Running unit tests..."
+        make test
+
+    - name: Upload coverage report
+      if: ${{ inputs.codecov-enable == 'true' }}
+      uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
+      with:
+        token: ${{ inputs.codecov-token }}
+        files: ./coverage.txt
+        flags: core-unittests
+        name: codecov-umbrella
+        fail_ci_if_error: false
+
+    # ========================================================================
+    # Failure Diagnostics
+    # ========================================================================
+    - name: Collect failure diagnostics
+      if: failure()
+      shell: bash
+      run: |
+        echo "=== FAILURE DIAGNOSTICS ==="
+        echo "Collecting diagnostic information for debugging..."
+
+        echo "--- Go Environment ---"
+        go version || true
+        go env || true
+
+        echo "--- Cluster Status ---"
+        kubectl get nodes -o wide || true
+        kubectl get pods -A || true
+
+        echo "--- KubeVela System Logs ---"
+        kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
+
+        echo "--- Recent Events ---"
+        kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
+
+        echo "--- Test Artifacts ---"
+        find . -name "*.log" -o -name "*test*.xml" -o -name "coverage.*" | head -20 || true
\ No newline at end of file
diff --git a/e2e/plugin/plugin_test.go b/e2e/plugin/plugin_test.go
index 8efe5871..06c033c3 100644
--- a/e2e/plugin/plugin_test.go
+++ b/e2e/plugin/plugin_test.go
@@ -425,7 +425,7 @@ spec:
         }
         
         outputs: ingress: {
-        	apiVersion: "networking.k8s.io/v1beta1"
+        	apiVersion: "networking.k8s.io/v1"
         	kind:       "Ingress"
         	metadata:
         		name: context.name
@@ -436,9 +436,14 @@ spec:
         				paths: [
         					for k, v in parameter.http {
         						path: k
+        						pathType: "Prefix"
         						backend: {
-        							serviceName: context.name
-        							servicePort: v
+        							service: {
+        								name: context.name
+        								port: {
+        									number: v
+        								}
+        							}
         						}
         					},
         				]
@@ -617,7 +622,7 @@ spec:
 
 ---
 ## From the trait test-ingress 
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations: {}
@@ -637,9 +642,12 @@ spec:
     http:
       paths:
       - backend:
-          serviceName: express-server
-          servicePort: 80
+          service:
+            name: express-server
+            port:
+              number: 80
         path: /
+        pathType: Prefix
 
 ---
 `
@@ -721,7 +729,7 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
 -     app.oam.dev/component: express-server
   
 * Component (express-server) / Trait (test-ingress/ingress) has been removed(-)
-- apiVersion: networking.k8s.io/v1beta1
+- apiVersion: networking.k8s.io/v1
 - kind: Ingress
 - metadata:
 -   labels:
@@ -739,9 +747,12 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
 -     http:
 -       paths:
 -       - backend:
--           serviceName: express-server
--           servicePort: 80
+-           service:
+-             name: express-server
+-             port:
+-               number: 80
 -         path: /
+-         pathType: Prefix
   
 * Component (new-express-server) has been added(+)
 + apiVersion: apps/v1
@@ -796,7 +807,7 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
 +     app.oam.dev/component: new-express-server
   
 * Component (new-express-server) / Trait (test-ingress/ingress) has been added(+)
-+ apiVersion: networking.k8s.io/v1beta1
++ apiVersion: networking.k8s.io/v1
 + kind: Ingress
 + metadata:
 +   labels:
@@ -814,9 +825,12 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
 +     http:
 +       paths:
 +       - backend:
-+           serviceName: new-express-server
-+           servicePort: 8080
++           service:
++             name: new-express-server
++             port:
++               number: 8080
 +         path: /
++         pathType: Prefix
 `
 
 var testShowComponentDef = `
diff --git a/pkg/addon/helper_test.go b/pkg/addon/helper_test.go
index 15c6dbcf..0d3dd0de 100644
--- a/pkg/addon/helper_test.go
+++ b/pkg/addon/helper_test.go
@@ -39,7 +39,7 @@ func setupMockServer() *httptest.Server {
 			"index.yaml",
 			"fluxcd-test-version-1.0.0.tgz",
 			"fluxcd-test-version-2.0.0.tgz",
-			"vela-workflow-v0.3.5.tgz",
+			"vela-workflow-v0.6.2.tgz",
 			"foo-v1.0.0.tgz",
 			"bar-v1.0.0.tgz",
 			"bar-v2.0.0.tgz",
diff --git a/pkg/appfile/template_test.go b/pkg/appfile/template_test.go
index 0708f7dd..c6485664 100644
--- a/pkg/appfile/template_test.go
+++ b/pkg/appfile/template_test.go
@@ -155,7 +155,7 @@ func TestLoadTraitTemplate(t *testing.T) {
         }
 
         outputs: ingress: {
-        	apiVersion: "networking.k8s.io/v1beta1"
+        	apiVersion: "networking.k8s.io/v1"
         	kind:       "Ingress"
         	metadata:
         		name: context.name
@@ -166,9 +166,14 @@ func TestLoadTraitTemplate(t *testing.T) {
         				paths: [
         					for k, v in parameter.http {
         						path: k
+        						pathType: "Prefix"
         						backend: {
-        							serviceName: context.name
-        							servicePort: v
+        							service: {
+        								name: context.name
+        								port: {
+        									number: v
+        								}
+        							}
         						}
         					},
         				]
diff --git a/pkg/controller/core.oam.dev/v1beta1/application/generator_test.go b/pkg/controller/core.oam.dev/v1beta1/application/generator_test.go
index 06a38a85..7314c6dc 100644
--- a/pkg/controller/core.oam.dev/v1beta1/application/generator_test.go
+++ b/pkg/controller/core.oam.dev/v1beta1/application/generator_test.go
@@ -289,4 +289,31 @@ var _ = Describe("Test Application workflow generator", func() {
 		_, _, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af)
 		Expect(err).NotTo(BeNil())
 	})
+
+	It("Test workflow context contains app labels and annotations", func() {
+		app := &oamcore.Application{
+			TypeMeta: metav1.TypeMeta{Kind: "Application", APIVersion: "core.oam.dev/v1beta1"},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:        "app-with-meta",
+				Namespace:   namespaceName,
+				Labels:      map[string]string{"team": "platform", "env": "prod"},
+				Annotations: map[string]string{"description": "meta test", "owner": "sre"},
+			},
+			Spec: oamcore.ApplicationSpec{Components: []common.ApplicationComponent{}},
+		}
+		ctxData := generateContextDataFromApp(app, "apprev-with-meta")
+		Expect(ctxData.AppLabels).To(Equal(app.Labels))
+		Expect(ctxData.AppAnnotations).To(Equal(app.Annotations))
+	})
+
+	It("Test workflow context empty labels annotations", func() {
+		app := &oamcore.Application{
+			TypeMeta:   metav1.TypeMeta{Kind: "Application", APIVersion: "core.oam.dev/v1beta1"},
+			ObjectMeta: metav1.ObjectMeta{Name: "app-without-meta", Namespace: namespaceName},
+			Spec:       oamcore.ApplicationSpec{Components: []common.ApplicationComponent{}},
+		}
+		ctxData := generateContextDataFromApp(app, "apprev-without-meta")
+		Expect(ctxData.AppLabels).To(BeNil())
+		Expect(ctxData.AppAnnotations).To(BeNil())
+	})
 })
diff --git a/pkg/cue/definition/template_test.go b/pkg/cue/definition/template_test.go
index 15a9f5bf..dfd5965d 100644
--- a/pkg/cue/definition/template_test.go
+++ b/pkg/cue/definition/template_test.go
@@ -725,7 +725,7 @@ parameter: {
         }
       }
       outputs: ingress: {
-        apiVersion: "networking.k8s.io/v1beta1"
+        apiVersion: "networking.k8s.io/v1"
         kind: "Ingress"
         metadata:
           name: context.name
@@ -736,9 +736,14 @@ parameter: {
             http: {
               paths: [{
                   path: parameter.path
+                  pathType: "Prefix"
                   backend: {
-                    serviceName: context.name
-                    servicePort: parameter.exposePort
+                    service: {
+                      name: context.name
+                      port: {
+                        number: parameter.exposePort
+                      }
+                    }
                   }
               }]
             }
@@ -781,7 +786,7 @@ parameter: {
 						"metadata":   map[string]interface{}{"name": "testgame-config"}, "data": map[string]interface{}{"enemies": "enemies-data", "lives": "lives-data"}},
 				},
 				"t3service": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "v1", "kind": "Service", "spec": map[string]interface{}{"ports": []interface{}{map[string]interface{}{"port": int64(1080), "targetPort": int64(443)}}, "selector": map[string]interface{}{"app": "test"}}}},
-				"t3ingress": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "networking.k8s.io/v1beta1", "kind": "Ingress", "labels": map[string]interface{}{"config": "enemies-data"}, "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"rules": []interface{}{map[string]interface{}{"host": "example.com", "http": map[string]interface{}{"paths": []interface{}{map[string]interface{}{"backend": map[string]interface{}{"serviceName": "test", "servicePort": int64(1080)}, "path": "ping"}}}}}}}},
+				"t3ingress": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "networking.k8s.io/v1", "kind": "Ingress", "labels": map[string]interface{}{"config": "enemies-data"}, "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"rules": []interface{}{map[string]interface{}{"host": "example.com", "http": map[string]interface{}{"paths": []interface{}{map[string]interface{}{"path": "ping", "pathType": "Prefix", "backend": map[string]interface{}{"service": map[string]interface{}{"name": "test", "port": map[string]interface{}{"number": int64(1080)}}}}}}}}}}},
 			},
 		},
 		"outputs trait with schema": {
diff --git a/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler_test.go b/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler_test.go
similarity index 64%
rename from pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler_test.go
rename to pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler_test.go
index 3e1c9578..4e57758c 100644
--- a/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler_test.go
+++ b/pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler_test.go
@@ -30,6 +30,7 @@ import (
 	admissionv1 "k8s.io/api/admission/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/rest"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -39,6 +40,7 @@ import (
 	core "github.com/oam-dev/kubevela/apis/core.oam.dev"
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/features"
 )
 
 var handler ValidatingHandler
@@ -153,7 +155,7 @@ var _ = Describe("Test ComponentDefinition validating handler", func() {
 			resp := handler.Handle(context.TODO(), req)
 			Expect(resp.Allowed).Should(BeFalse())
 			Expect(resp.Result.Reason).Should(Equal(metav1.StatusReason(http.StatusText(http.StatusForbidden))))
-			Expect(resp.Result.Message).Should(Equal("neither the type nor the definition of the workload field in the ComponentDefinition wrongCd can be empty"))
+			Expect(resp.Result.Message).Should(ContainSubstring("neither the type nor the definition of the workload field in the ComponentDefinition wrongCd can be empty"))
 		})
 
 		It("Test componentDefinition which type and definition point to different workload type", func() {
@@ -176,7 +178,7 @@ var _ = Describe("Test ComponentDefinition validating handler", func() {
 			resp := handler.Handle(context.TODO(), req)
 			Expect(resp.Allowed).Should(BeFalse())
 			Expect(resp.Result.Reason).Should(Equal(metav1.StatusReason(http.StatusText(http.StatusForbidden))))
-			Expect(resp.Result.Message).Should(Equal("the type and the definition of the workload field in ComponentDefinition wrongCd should represent the same workload"))
+			Expect(resp.Result.Message).Should(ContainSubstring("the type and the definition of the workload field in ComponentDefinition wrongCd should represent the same workload"))
 		})
 		It("Test cue template validation passed", func() {
 			cd.Spec = v1beta1.ComponentDefinitionSpec{
@@ -401,5 +403,278 @@ var _ = Describe("Test ComponentDefinition validating handler", func() {
 			Expect(resp.Allowed).Should(BeTrue())
 		})
 
+		It("Test ComponentDefinition with non-existent CRD in outputs should be rejected", func() {
+			// Enable the ValidateResourcesExist feature gate for this test
+			originalState := utilfeature.DefaultMutableFeatureGate.Enabled(features.ValidateResourcesExist)
+			defer utilfeature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{
+				string(features.ValidateResourcesExist): originalState,
+			})
+			utilfeature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{
+				string(features.ValidateResourcesExist): true,
+			})
+
+			templateWithInvalidCRD := `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	invalidResource: {
+		apiVersion: "custom.io/v1alpha1"
+		kind: "NonExistentResource"
+		metadata: name: parameter.name + "-custom"
+		spec: {
+			foo: "bar"
+		}
+	}
+}`
+
+			cd := v1beta1.ComponentDefinition{}
+			cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
+			cd.SetName("test-invalid-outputs")
+			cd.Spec = v1beta1.ComponentDefinitionSpec{
+				Workload: common.WorkloadTypeDescriptor{
+					Type: "deployments.apps",
+					Definition: common.WorkloadGVK{
+						APIVersion: "apps/v1",
+						Kind:       "Deployment",
+					},
+				},
+				Schematic: &common.Schematic{
+					CUE: &common.CUE{
+						Template: templateWithInvalidCRD,
+					},
+				},
+			}
+			cdRaw, _ := json.Marshal(cd)
+			req := admission.Request{
+				AdmissionRequest: admissionv1.AdmissionRequest{
+					Operation: admissionv1.Create,
+					Resource:  reqResource,
+					Object:    runtime.RawExtension{Raw: cdRaw},
+				},
+			}
+			resp := handler.Handle(context.TODO(), req)
+			Expect(resp.Allowed).Should(BeFalse())
+			Expect(resp.Result.Message).Should(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Test ComponentDefinition with valid outputs should pass", func() {
+			templateWithValidOutputs := `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{
+				port: 80
+				targetPort: 8080
+			}]
+		}
+	}
+	configmap: {
+		apiVersion: "v1"
+		kind: "ConfigMap"
+		metadata: name: parameter.name + "-config"
+		data: {
+			config: "test-config"
+		}
+	}
+}`
+
+			cd := v1beta1.ComponentDefinition{}
+			cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
+			cd.SetName("test-valid-outputs")
+			cd.Spec = v1beta1.ComponentDefinitionSpec{
+				Workload: common.WorkloadTypeDescriptor{
+					Type: "deployments.apps",
+					Definition: common.WorkloadGVK{
+						APIVersion: "apps/v1",
+						Kind:       "Deployment",
+					},
+				},
+				Schematic: &common.Schematic{
+					CUE: &common.CUE{
+						Template: templateWithValidOutputs,
+					},
+				},
+			}
+			cdRaw, _ := json.Marshal(cd)
+			req := admission.Request{
+				AdmissionRequest: admissionv1.AdmissionRequest{
+					Operation: admissionv1.Create,
+					Resource:  reqResource,
+					Object:    runtime.RawExtension{Raw: cdRaw},
+				},
+			}
+			resp := handler.Handle(context.TODO(), req)
+			Expect(resp.Allowed).Should(BeTrue())
+		})
+
+		It("Test ComponentDefinition with mixed valid and non-k8s outputs should pass", func() {
+			templateWithMixedOutputs := `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{port: 80}]
+		}
+	}
+	customData: {
+		field1: "value1"
+		field2: "value2"
+		nested: {
+			data: "some-data"
+		}
+	}
+}`
+
+			cd := v1beta1.ComponentDefinition{}
+			cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
+			cd.SetName("test-mixed-outputs")
+			cd.Spec = v1beta1.ComponentDefinitionSpec{
+				Workload: common.WorkloadTypeDescriptor{
+					Type: "deployments.apps",
+					Definition: common.WorkloadGVK{
+						APIVersion: "apps/v1",
+						Kind:       "Deployment",
+					},
+				},
+				Schematic: &common.Schematic{
+					CUE: &common.CUE{
+						Template: templateWithMixedOutputs,
+					},
+				},
+			}
+			cdRaw, _ := json.Marshal(cd)
+			req := admission.Request{
+				AdmissionRequest: admissionv1.AdmissionRequest{
+					Operation: admissionv1.Create,
+					Resource:  reqResource,
+					Object:    runtime.RawExtension{Raw: cdRaw},
+				},
+			}
+			resp := handler.Handle(context.TODO(), req)
+			Expect(resp.Allowed).Should(BeTrue())
+		})
+
+		It("Test ComponentDefinition with empty outputs should pass", func() {
+			templateWithEmptyOutputs := `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {}`
+
+			cd := v1beta1.ComponentDefinition{}
+			cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
+			cd.SetName("test-empty-outputs")
+			cd.Spec = v1beta1.ComponentDefinitionSpec{
+				Workload: common.WorkloadTypeDescriptor{
+					Type: "deployments.apps",
+					Definition: common.WorkloadGVK{
+						APIVersion: "apps/v1",
+						Kind:       "Deployment",
+					},
+				},
+				Schematic: &common.Schematic{
+					CUE: &common.CUE{
+						Template: templateWithEmptyOutputs,
+					},
+				},
+			}
+			cdRaw, _ := json.Marshal(cd)
+			req := admission.Request{
+				AdmissionRequest: admissionv1.AdmissionRequest{
+					Operation: admissionv1.Create,
+					Resource:  reqResource,
+					Object:    runtime.RawExtension{Raw: cdRaw},
+				},
+			}
+			resp := handler.Handle(context.TODO(), req)
+			Expect(resp.Allowed).Should(BeTrue())
+		})
+
 	})
 })
diff --git a/pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler_test.go b/pkg/webhook/core.oam.dev/v1beta1/policydefinition/policy_definition_validating_handler_test.go
similarity index 100%
rename from pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler_test.go
rename to pkg/webhook/core.oam.dev/v1beta1/policydefinition/policy_definition_validating_handler_test.go
diff --git a/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler_test.go b/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler_test.go
similarity index 99%
rename from pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler_test.go
rename to pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler_test.go
index 9fdf5899..ec8675e9 100644
--- a/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler_test.go
+++ b/pkg/webhook/core.oam.dev/v1beta1/traitdefinition/trait_definition_validating_handler_test.go
@@ -168,7 +168,7 @@ var _ = Describe("Test TraitDefinition validating handler", func() {
 			resp := handler.Handle(context.TODO(), req)
 			Expect(resp.Allowed).Should(BeFalse())
 			Expect(resp.Result.Reason).Should(Equal(metav1.StatusReason(http.StatusText(http.StatusForbidden))))
-			Expect(resp.Result.Message).Should(Equal("mock validator error"))
+			Expect(resp.Result.Message).Should(ContainSubstring("mock validator error"))
 		})
 		It("Test cue template validation passed", func() {
 			td.Spec = v1beta1.TraitDefinitionSpec{
diff --git a/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/validating_handler_test.go b/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler_test.go
similarity index 100%
rename from pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/validating_handler_test.go
rename to pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler_test.go
diff --git a/pkg/webhook/utils/invalid_resource_check_test.go b/pkg/webhook/utils/invalid_resource_check_test.go
new file mode 100644
index 00000000..c2f9d9bd
--- /dev/null
+++ b/pkg/webhook/utils/invalid_resource_check_test.go
@@ -0,0 +1,307 @@
+/*
+ Copyright 2021. The KubeVela Authors.
+
+ Licensed 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 utils
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
+
+	"github.com/oam-dev/kubevela/pkg/features"
+)
+
+// fakeRESTMapper implements meta.RESTMapper for tests (minimal).
+type fakeRESTMapper struct {
+	known map[string]bool // key: group|kind|version
+}
+
+func newFakeRESTMapper(entries ...[3]string) *fakeRESTMapper {
+	m := &fakeRESTMapper{known: map[string]bool{}}
+	for _, e := range entries {
+		m.known[e[0]+"|"+e[1]+"|"+e[2]] = true
+	}
+	return m
+}
+
+func (f *fakeRESTMapper) key(gk schema.GroupKind, version string) string {
+	return gk.Group + "|" + gk.Kind + "|" + version
+}
+
+func (f *fakeRESTMapper) Reset() {}
+func (f *fakeRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
+	return schema.GroupVersionKind{}, errors.New("not implemented")
+}
+func (f *fakeRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
+	return nil, errors.New("not implemented")
+}
+func (f *fakeRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
+	return schema.GroupVersionResource{}, errors.New("not implemented")
+}
+func (f *fakeRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
+	return nil, errors.New("not implemented")
+}
+func (f *fakeRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
+	for _, v := range versions {
+		if f.known[f.key(gk, v)] {
+			return &meta.RESTMapping{
+				Resource: schema.GroupVersionResource{
+					Group:    gk.Group,
+					Version:  v,
+					Resource: "",
+				},
+				GroupVersionKind: schema.GroupVersionKind{
+					Group:   gk.Group,
+					Version: v,
+					Kind:    gk.Kind,
+				},
+			}, nil
+		}
+	}
+	return nil, errors.New("no match for kind")
+}
+func (f *fakeRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
+	m, err := f.RESTMapping(gk, versions...)
+	if err != nil {
+		return nil, err
+	}
+	return []*meta.RESTMapping{m}, nil
+}
+func (f *fakeRESTMapper) ResourceSingularizer(resource string) (string, error) {
+	return resource, nil
+}
+
+func TestExtractResourceInfo(t *testing.T) {
+	tests := map[string]struct {
+		cue     string
+		want    []ResourceInfo
+		wantErr bool
+	}{
+		"singleOutput": {
+			cue: `
+output: {
+  apiVersion: "apps/v1"
+  kind: "Deployment"
+  metadata: { name: "my-deploy" }
+  spec: {}
+}`,
+			want: []ResourceInfo{
+				{APIVersion: "apps/v1", Kind: "Deployment", Name: "my-deploy"},
+			},
+		},
+		"multipleOutputs": {
+			cue: `
+outputs: {
+  first: {
+    apiVersion: "v1"
+    kind: "ConfigMap"
+    metadata: { name: "cfg" }
+  }
+  second: {
+    apiVersion: "batch/v1"
+    kind: "Job"
+  }
+  third: { kind: "Service" } // missing apiVersion ignored
+}`,
+			want: []ResourceInfo{
+				{APIVersion: "v1", Kind: "ConfigMap", Name: "cfg"},
+				{APIVersion: "batch/v1", Kind: "Job", Name: "second"},
+			},
+		},
+		"parseError": {
+			cue: `
+output: {
+  apiVersion: "v1"
+  kind: "Pod"
+`,
+			wantErr: true,
+		},
+		"outputWithoutKindIgnored": {
+			cue: `
+output: {
+  apiVersion: "v1"
+  metadata: { name: "x" }
+}`,
+			want: []ResourceInfo{},
+		},
+		"metadataNameOverridesLabel": {
+			cue: `
+outputs: {
+  cfg: { apiVersion: "v1", kind: "ConfigMap", metadata: { name: "real" } }
+}`,
+			want: []ResourceInfo{
+				{APIVersion: "v1", Kind: "ConfigMap", Name: "real"},
+			},
+		},
+		"fallbackNameCoreGroup": {
+			cue: `
+outputs: {
+  svc: { apiVersion: "v1", kind: "Service" }
+}`,
+			want: []ResourceInfo{
+				{APIVersion: "v1", Kind: "Service", Name: "svc"},
+			},
+		},
+		"deepMetadataNameIgnoredFallbackToLabel": {
+			cue: `
+outputs: {
+  deep: { apiVersion: "v1", kind: "ConfigMap", metadata: { other: { name: "inner" } } }
+}`,
+			want: []ResourceInfo{
+				{APIVersion: "v1", Kind: "ConfigMap", Name: "deep"},
+			},
+		},
+		"nonStructOutputsValueIgnored": {
+			cue: `
+outputs: [
+  { apiVersion: "v1", kind: "ConfigMap" }
+]`,
+			want: []ResourceInfo{},
+		},
+		"missingAPIVersionAndKindEntriesIgnored": {
+			cue: `
+outputs: {
+  a: { apiVersion: "v1" }
+  b: { kind: "ConfigMap" }
+  c: { metadata: { name: "x" } }
+}`,
+			want: []ResourceInfo{},
+		},
+	}
+
+	for name, tc := range tests {
+		tc := tc
+		t.Run(name, func(t *testing.T) {
+			got, err := ExtractResourceInfo(tc.cue)
+			if tc.wantErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			if len(tc.want) == 0 {
+				assert.Len(t, got, 0)
+			} else {
+				assert.Equal(t, tc.want, got)
+			}
+		})
+	}
+}
+
+func TestValidateOutputResourcesExist(t *testing.T) {
+	// Enable the ValidateResourcesExist feature gate for these tests
+	originalState := utilfeature.DefaultMutableFeatureGate.Enabled(features.ValidateResourcesExist)
+	defer utilfeature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{
+		string(features.ValidateResourcesExist): originalState,
+	})
+	utilfeature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{
+		string(features.ValidateResourcesExist): true,
+	})
+
+	tests := map[string]struct {
+		cue     string
+		mapper  *fakeRESTMapper
+		wantErr string
+	}{
+		"singleSuccess": {
+			cue: `
+output: {
+  apiVersion: "apps/v1"
+  kind: "Deployment"
+  metadata: { name: "my-deploy" }
+}`,
+			mapper: newFakeRESTMapper([3]string{"apps", "Deployment", "v1"}),
+		},
+		"multipleSuccess": {
+			cue: `
+outputs: {
+  cm: { apiVersion: "v1", kind: "ConfigMap" }
+  jobRes: { apiVersion: "batch/v1", kind: "Job" }
+}`,
+			mapper: newFakeRESTMapper(
+				[3]string{"", "ConfigMap", "v1"},
+				[3]string{"batch", "Job", "v1"},
+			),
+		},
+		"missingResource": {
+			cue: `
+output: {
+  apiVersion: "apps/v1"
+  kind: "Deployment"
+}`,
+			mapper:  newFakeRESTMapper(),
+			wantErr: "resource type not found on cluster: apps/v1/Deployment",
+		},
+		"firstOkSecondMissing": {
+			cue: `
+outputs: {
+  a: { apiVersion: "v1", kind: "ConfigMap" }
+  b: { apiVersion: "batch/v1", kind: "Job" }
+}`,
+			mapper:  newFakeRESTMapper([3]string{"", "ConfigMap", "v1"}),
+			wantErr: "resource type not found on cluster: batch/v1/Job",
+		},
+		"ignoreIncompleteEntries": {
+			cue: `
+outputs: {
+  a: { apiVersion: "v1" }
+  b: { kind: "ConfigMap" }
+  c: { apiVersion: "v1", kind: "ConfigMap" }
+}`,
+			mapper: newFakeRESTMapper([3]string{"", "ConfigMap", "v1"}),
+		},
+		"duplicateResourceTypes": {
+			cue: `
+outputs: {
+  one: { apiVersion: "v1", kind: "ConfigMap" }
+  two: { apiVersion: "v1", kind: "ConfigMap" }
+}`,
+			mapper: newFakeRESTMapper([3]string{"", "ConfigMap", "v1"}),
+		},
+		"malformedApiVersionTrailingSlash": {
+			cue: `
+outputs: {
+  bad: { apiVersion: "apps/", kind: "Deployment" }
+}`,
+			mapper:  newFakeRESTMapper([3]string{"apps", "Deployment", "v1"}),
+			wantErr: "resource type not found on cluster: apps//Deployment",
+		},
+		"deepMetadataNameDoesNotAffectValidation": {
+			cue: `
+outputs: {
+  deep: { apiVersion: "v1", kind: "ConfigMap", metadata: { other: { name: "x" } } }
+}`,
+			mapper: newFakeRESTMapper([3]string{"", "ConfigMap", "v1"}),
+		},
+	}
+
+	for name, tc := range tests {
+		tc := tc
+		t.Run(name, func(t *testing.T) {
+			// Pass nil object for tests - feature gate is disabled by default
+			err := ValidateOutputResourcesExist(tc.cue, tc.mapper, nil)
+			if tc.wantErr != "" {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tc.wantErr)
+			} else {
+				assert.NoError(t, err)
+			}
+		})
+	}
+}
diff --git a/pkg/workflow/providers/legacy/query/handler_test.go b/pkg/workflow/providers/legacy/query/handler_test.go
index 94ffbc7a..35cc52b6 100644
--- a/pkg/workflow/providers/legacy/query/handler_test.go
+++ b/pkg/workflow/providers/legacy/query/handler_test.go
@@ -788,7 +788,7 @@ var _ = Describe("Test Query Provider", func() {
 			},
 			&networkv1.Ingress{
 				TypeMeta: metav1.TypeMeta{
-					APIVersion: "networking.k8s.io/v1beta1",
+					APIVersion: "networking.k8s.io/v1",
 				},
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "ingress-helm",
diff --git a/pkg/workflow/providers/query/handler_test.go b/pkg/workflow/providers/query/handler_test.go
index ecc43aa0..bdcc05f8 100644
--- a/pkg/workflow/providers/query/handler_test.go
+++ b/pkg/workflow/providers/query/handler_test.go
@@ -788,7 +788,7 @@ var _ = Describe("Test Query Provider", func() {
 			},
 			&networkv1.Ingress{
 				TypeMeta: metav1.TypeMeta{
-					APIVersion: "networking.k8s.io/v1beta1",
+					APIVersion: "networking.k8s.io/v1",
 				},
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "ingress-helm",
diff --git a/references/appfile/addon_test.go b/references/appfile/addon_test.go
index 93939c8f..a3790461 100644
--- a/references/appfile/addon_test.go
+++ b/references/appfile/addon_test.go
@@ -55,18 +55,18 @@ var _ = Describe("Test generateSecretFromTerraformOutput", func() {
 	var name = "test-addon-secret"
 	It("namespace doesn't exist", func() {
 		badNamespace := "a-not-existed-namespace"
-		err := generateSecretFromTerraformOutput(k8sClient, nil, name, badNamespace)
+		err := generateSecretFromTerraformOutput(k8sClient, "", name, badNamespace)
 		Expect(err).Should(Equal(fmt.Errorf("namespace %s doesn't exist", badNamespace)))
 	})
 	It("valid output list", func() {
-		outputList := []string{"name=aaa", "age=1"}
-		err := generateSecretFromTerraformOutput(k8sClient, outputList, name, addonNamespace)
+		rawOutput := "name=aaa\nage=1"
+		err := generateSecretFromTerraformOutput(k8sClient, rawOutput, name, addonNamespace)
 		Expect(err).Should(BeNil())
 	})
 
 	It("invalid output list", func() {
-		outputList := []string{"name"}
-		err := generateSecretFromTerraformOutput(k8sClient, outputList, name, addonNamespace)
-		Expect(err).Should(Equal(fmt.Errorf("terraform output isn't in the right format")))
+		rawOutput := "name"
+		err := generateSecretFromTerraformOutput(k8sClient, rawOutput, name, addonNamespace)
+		Expect(err).Should(Equal(fmt.Errorf("terraform output isn't in the right format: %q", rawOutput)))
 	})
 })
diff --git a/references/appfile/api/appfile_test.go b/references/appfile/api/appfile_test.go
index d1e647a7..074b874e 100644
--- a/references/appfile/api/appfile_test.go
+++ b/references/appfile/api/appfile_test.go
@@ -223,7 +223,7 @@ outputs: service: {
 }
 
 outputs: ingress: {
-  apiVersion: "networking.k8s.io/v1beta1"
+  apiVersion: "networking.k8s.io/v1"
   kind: "Ingress"
   spec: {
     rules: [{
@@ -232,9 +232,14 @@ outputs: ingress: {
         paths: [
           for k, v in parameter.http {
             path: k
+            pathType: "Prefix"
             backend: {
-              serviceName: context.name
-              servicePort: v
+              service: {
+                name: context.name
+                port: {
+                  number: v
+                }
+              }
             }
           }
         ]
diff --git a/references/cli/top/model/suit_test.go b/references/cli/top/model/suit_test.go
index fcc1cec0..66a7aee5 100644
--- a/references/cli/top/model/suit_test.go
+++ b/references/cli/top/model/suit_test.go
@@ -120,7 +120,7 @@ var _ = BeforeSuite(func() {
 					Kind:       "Ingress",
 					Namespace:  "default",
 					Name:       "ingress-http",
-					APIVersion: "networking.k8s.io/v1beta1",
+					APIVersion: "networking.k8s.io/v1",
 				},
 			},
 			{
diff --git a/references/cli/velaql_test.go b/references/cli/velaql_test.go
index 7eb1c46c..f605813f 100644
--- a/references/cli/velaql_test.go
+++ b/references/cli/velaql_test.go
@@ -117,7 +117,7 @@ var _ = Describe("Test velaQL", func() {
 						Kind:       "Ingress",
 						Namespace:  "default",
 						Name:       "ingress-http",
-						APIVersion: "networking.k8s.io/v1beta1",
+						APIVersion: "networking.k8s.io/v1",
 					},
 				},
 				{
@@ -386,7 +386,7 @@ var _ = Describe("Test velaQL", func() {
 			},
 			&networkv1.Ingress{
 				TypeMeta: metav1.TypeMeta{
-					APIVersion: "networking.k8s.io/v1beta1",
+					APIVersion: "networking.k8s.io/v1",
 				},
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "ingress-helm",
diff --git a/test/e2e-addon-test/addon_test.go b/test/e2e-addon-test/addon_test.go
index 6385bff0..fcccfa9c 100644
--- a/test/e2e-addon-test/addon_test.go
+++ b/test/e2e-addon-test/addon_test.go
@@ -21,17 +21,22 @@ import (
 	"errors"
 	"fmt"
 	"math/rand"
+
 	"os/exec"
 	"strconv"
+
 	"time"
 
 	terraformv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
+	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
+	workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
+
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
 	"github.com/oam-dev/kubevela/pkg/oam/util"
 	"github.com/oam-dev/kubevela/pkg/utils/common"
@@ -132,4 +137,41 @@ var _ = Describe("Addon tests", func() {
 		Expect(err).Should(BeNil())
 		Expect(string(output)).Should(ContainSubstring("enabled successfully"))
 	})
+
+	It("Addon Workflow is successfully enabled and WorkflowRun creates Deployment", func() {
+		By("Install Addon Workflow")
+
+		output, err := exec.Command("bash", "-c", "/tmp/vela addon enable vela-workflow").Output()
+		var ee *exec.ExitError
+		if errors.As(err, &ee) {
+			fmt.Println("exit code error:", string(ee.Stderr))
+		}
+		Expect(err).Should(BeNil())
+		Expect(string(output)).Should(ContainSubstring("enabled successfully"))
+
+		By("Apply a WorkflowRun which creates a Deployment")
+		var wr workflowv1alpha1.WorkflowRun
+		Expect(common.ReadYamlToObject("./testdata/workflow/workflowrun_nginx.yaml", &wr)).Should(BeNil())
+		// set namespace to dynamically created test namespace
+		wr.Namespace = namespaceName
+		Eventually(func() error { return k8sClient.Create(ctx, wr.DeepCopy()) }, 20*time.Second, 500*time.Millisecond).Should(Succeed())
+
+		By("Verify the Deployment is created by WorkflowRun")
+		Eventually(func() error {
+			var deploy appsv1.Deployment
+			return k8sClient.Get(ctx, client.ObjectKey{Name: "apply-nginx-deployment", Namespace: namespaceName}, &deploy)
+		}, 180*time.Second, 2*time.Second).Should(Succeed())
+
+		By("Check the WorkflowRun reaches a succeeded phase")
+		Eventually(func() error {
+			var latest workflowv1alpha1.WorkflowRun
+			if err := k8sClient.Get(ctx, client.ObjectKey{Name: wr.Name, Namespace: namespaceName}, &latest); err != nil {
+				return err
+			}
+			if latest.Status.Phase == workflowv1alpha1.WorkflowStateSucceeded {
+				return nil
+			}
+			return fmt.Errorf("workflowrun not finished, current phase: %s", latest.Status.Phase)
+		}, 300*time.Second, 2*time.Second).Should(Succeed())
+	})
 })
diff --git a/test/e2e-addon-test/suite_test.go b/test/e2e-addon-test/suite_test.go
index c68fcee0..a8a00230 100644
--- a/test/e2e-addon-test/suite_test.go
+++ b/test/e2e-addon-test/suite_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 	"time"
 
+	workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
 	terraformv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -57,6 +58,8 @@ var _ = BeforeSuite(func() {
 	Expect(err).Should(BeNil())
 	err = terraformv1beta1.AddToScheme(scheme)
 	Expect(err).Should(BeNil())
+	err = workflowv1alpha1.AddToScheme(scheme)
+	Expect(err).Should(BeNil())
 	By("Setting up kubernetes client")
 	k8sClient, err = client.New(config.GetConfigOrDie(), client.Options{Scheme: scheme})
 	if err != nil {
diff --git a/test/e2e-addon-test/testdata/app/app_terraform_pod.yaml b/test/e2e-addon-test/testdata/app/app_terraform_pod.yaml
new file mode 100644
index 00000000..94f818ce
--- /dev/null
+++ b/test/e2e-addon-test/testdata/app/app_terraform_pod.yaml
@@ -0,0 +1,12 @@
+apiVersion: core.oam.dev/v1beta1
+kind: Application
+metadata:
+  name: terraform-pod-sample
+spec:
+  components:
+    - name: sample-pod
+      type: terraform-k8s-pod
+      properties:
+        name: tf-sample-pod
+        namespace: ___NAMESPACE___
+        image: nginx:1.25-alpine
diff --git a/test/e2e-addon-test/testdata/definitions/terraform_pod_component.yaml b/test/e2e-addon-test/testdata/definitions/terraform_pod_component.yaml
new file mode 100644
index 00000000..a5c0859f
--- /dev/null
+++ b/test/e2e-addon-test/testdata/definitions/terraform_pod_component.yaml
@@ -0,0 +1,65 @@
+apiVersion: core.oam.dev/v1beta1
+kind: ComponentDefinition
+metadata:
+  name: terraform-k8s-pod
+  namespace: vela-system
+  annotations:
+    definition.oam.dev/description: Terraform configuration to create a Kubernetes Pod via the kubernetes provider
+  labels:
+    type: terraform
+spec:
+  workload:
+    definition:
+      apiVersion: terraform.core.oam.dev/v1beta1
+      kind: Configuration
+  schematic:
+    terraform:
+      configuration: |
+        terraform {
+          required_providers {
+            kubernetes = {
+              source  = "hashicorp/kubernetes"
+              version = "~> 2.27"
+            }
+          }
+        }
+
+        # In-cluster provider auth (terraform-controller should run in cluster and inject)
+        provider "kubernetes" {}
+
+        resource "kubernetes_pod" "example" {
+          metadata {
+            name      = var.name
+            namespace = var.namespace
+            labels = {
+              app = "tf-sample"
+            }
+          }
+          spec {
+            container {
+              image = var.image
+              name  = "nginx"
+              port {
+                container_port = 80
+              }
+            }
+          }
+        }
+
+        output "POD_NAME" {
+          value = kubernetes_pod.example.metadata[0].name
+        }
+
+        variable "name" {
+          type = string
+          description = "Name of the Pod to create"
+        }
+        variable "namespace" {
+          type = string
+          description = "Namespace in which to create the Pod"
+        }
+        variable "image" {
+          type    = string
+          default = "nginx:1.25-alpine"
+          description = "Container image"
+        }
diff --git a/test/e2e-addon-test/testdata/workflow/workflowrun_nginx.yaml b/test/e2e-addon-test/testdata/workflow/workflowrun_nginx.yaml
new file mode 100644
index 00000000..6a1f06d5
--- /dev/null
+++ b/test/e2e-addon-test/testdata/workflow/workflowrun_nginx.yaml
@@ -0,0 +1,13 @@
+apiVersion: core.oam.dev/v1alpha1
+kind: WorkflowRun
+metadata:
+  name: deploy-nginx
+  namespace: default
+spec:
+  workflowSpec:
+    steps:
+      - name: apply-nginx-deployment
+        type: apply-deployment
+        properties:
+          image: nginx:latest
+          replicas: 1 
\ No newline at end of file
diff --git a/test/e2e-test/definition_output_validation_test.go b/test/e2e-test/definition_output_validation_test.go
new file mode 100644
index 00000000..567dbff2
--- /dev/null
+++ b/test/e2e-test/definition_output_validation_test.go
@@ -0,0 +1,1188 @@
+/*
+ Copyright 2021. The KubeVela Authors.
+
+ Licensed 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 controllers_test
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/oam/util"
+)
+
+var _ = Describe("Definition Output Validation E2E tests", func() {
+	ctx := context.Background()
+
+	var namespace string
+	var ns corev1.Namespace
+
+	BeforeEach(func() {
+		namespace = randomNamespaceName("def-output-validation")
+		ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
+
+		Eventually(func() error {
+			return k8sClient.Create(ctx, &ns)
+		}, time.Second*3, time.Microsecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
+	})
+
+	AfterEach(func() {
+		By("Clean up resources after a test")
+		k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
+		k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
+		k8sClient.DeleteAllOf(ctx, &v1beta1.PolicyDefinition{}, client.InNamespace(namespace))
+		k8sClient.DeleteAllOf(ctx, &v1beta1.WorkflowStepDefinition{}, client.InNamespace(namespace))
+
+		By(fmt.Sprintf("Delete the entire namespace %s", ns.Name))
+		Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
+	})
+
+	Context("Test validation for outputs with non-existent CRDs", func() {
+
+		It("Should reject ComponentDefinition with non-existent CRD in outputs", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-with-invalid-output",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	nonExistentResource: {
+		apiVersion: "custom.io/v1alpha1"
+		kind: "NonExistentResource"
+		metadata: name: parameter.name + "-custom"
+		spec: {
+			foo: "bar"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept ComponentDefinition with only valid resources in outputs", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-with-valid-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{
+				port: 80
+				targetPort: 8080
+			}]
+		}
+	}
+	configmap: {
+		apiVersion: "v1"
+		kind: "ConfigMap"
+		metadata: name: parameter.name + "-config"
+		data: {
+			config: "some-config"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, componentDef)).Should(Succeed())
+		})
+
+		It("Should reject TraitDefinition with non-existent CRD in outputs", func() {
+			traitDef := &v1beta1.TraitDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "TraitDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-trait-with-invalid-output",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.TraitDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	replicas: int
+}
+
+outputs: {
+	hpa: {
+		apiVersion: "autoscaling/v2"
+		kind: "HorizontalPodAutoscaler"
+		metadata: name: context.name + "-hpa"
+		spec: {
+			scaleTargetRef: {
+				apiVersion: "apps/v1"
+				kind: "Deployment"
+				name: context.name
+			}
+			minReplicas: parameter.replicas
+			maxReplicas: parameter.replicas * 2
+		}
+	}
+	customResource: {
+		apiVersion: "nonexistent.io/v1"
+		kind: "NonExistentCRD"
+		metadata: name: context.name + "-custom"
+		spec: {
+			data: "test"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, traitDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept TraitDefinition with valid resources", func() {
+			traitDef := &v1beta1.TraitDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "TraitDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-trait-with-valid-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.TraitDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	replicas: int
+}
+
+patch: {
+	spec: replicas: parameter.replicas
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, traitDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, traitDef)).Should(Succeed())
+		})
+
+		It("Should reject PolicyDefinition with non-existent CRD in outputs", func() {
+			policyDef := &v1beta1.PolicyDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "PolicyDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-policy-with-invalid-output",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.PolicyDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	namespace: string
+}
+
+output: {
+	apiVersion: "v1"
+	kind: "Namespace"
+	metadata: name: parameter.namespace
+}
+
+outputs: {
+	invalidResource: {
+		apiVersion: "custom.io/v1beta1"
+		kind: "CustomPolicy"
+		metadata: name: parameter.namespace + "-policy"
+		spec: {
+			enabled: true
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, policyDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept PolicyDefinition with valid resources", func() {
+			policyDef := &v1beta1.PolicyDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "PolicyDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-policy-with-valid-output",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.PolicyDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	namespace: string
+}
+
+output: {
+	apiVersion: "v1"
+	kind: "Namespace"
+	metadata: name: parameter.namespace
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, policyDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, policyDef)).Should(Succeed())
+		})
+
+		It("Should handle definitions with mixed valid and non-K8s resources", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-with-mixed-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{port: 80}]
+		}
+	}
+	customData: {
+		field1: "value1"
+		field2: "value2"
+		nested: {
+			data: "some-data"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, componentDef)).Should(Succeed())
+		})
+
+		It("Should handle update operations with validation", func() {
+			// First create a valid definition
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-update-validation",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: "app"
+				image: "nginx"
+			}]
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Try to update with invalid output
+			Eventually(func() error {
+				var existing v1beta1.ComponentDefinition
+				if err := k8sClient.Get(ctx, client.ObjectKey{Name: componentDef.Name, Namespace: namespace}, &existing); err != nil {
+					return err
+				}
+				existing.Spec.Schematic.CUE.Template = `
+parameter: {
+	name: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: "app"
+				image: "nginx"
+			}]
+		}
+	}
+}
+
+outputs: {
+	invalidCRD: {
+		apiVersion: "nonexistent.io/v1"
+		kind: "NonExistentResource"
+		metadata: name: parameter.name
+		spec: {}
+	}
+}`
+				return k8sClient.Update(ctx, &existing)
+			}, time.Second*5, time.Millisecond*500).Should(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, componentDef)).Should(Succeed())
+		})
+
+		It("Should reject ComponentDefinition with multiple invalid CRDs", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-multiple-invalid",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+outputs: {
+	validService: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{port: 80}]
+		}
+	}
+	invalidCRD1: {
+		apiVersion: "custom.io/v1alpha1"
+		kind: "CustomResource"
+		metadata: name: parameter.name + "-custom1"
+		spec: {foo: "bar"}
+	}
+	invalidCRD2: {
+		apiVersion: "another.io/v1beta1"
+		kind: "AnotherResource"
+		metadata: name: parameter.name + "-custom2"
+		spec: {enabled: true}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should handle definitions with complex CUE expressions", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-cue-expressions",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+import "strings"
+
+parameter: {
+	name: string
+	image: string
+	enableService: bool | *false
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: {
+		name: strings.ToLower(parameter.name)
+		labels: {
+			app: parameter.name
+			version: "v1"
+		}
+	}
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+if parameter.enableService {
+	outputs: service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: parameter.name + "-svc"
+		spec: {
+			selector: app: parameter.name
+			ports: [{port: 80, targetPort: 8080}]
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, componentDef)).Should(Succeed())
+		})
+
+		It("Should reject TraitDefinition with mixed valid and invalid outputs", func() {
+			traitDef := &v1beta1.TraitDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "TraitDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-trait-mixed-validity",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.TraitDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	replicas: int | *2
+	cpu: string | *"100m"
+	memory: string | *"128Mi"
+}
+
+outputs: {
+	// Valid resources
+	service: {
+		apiVersion: "v1"
+		kind: "Service"
+		metadata: name: context.name + "-svc"
+		spec: {
+			selector: app: context.name
+			ports: [{
+				port: 80
+				targetPort: 8080
+			}]
+		}
+	}
+	configmap: {
+		apiVersion: "v1"
+		kind: "ConfigMap"
+		metadata: name: context.name + "-config"
+		data: {
+			cpu: parameter.cpu
+			memory: parameter.memory
+		}
+	}
+	// Invalid CRD - should cause failure
+	customMonitor: {
+		apiVersion: "monitoring.custom.io/v1alpha1"
+		kind: "ServiceMonitor"
+		metadata: name: context.name + "-monitor"
+		spec: {
+			selector: {
+				matchLabels: {
+					app: context.name
+				}
+			}
+			endpoints: [{
+				port: "metrics"
+				interval: "30s"
+			}]
+		}
+	}
+	// Non-K8s object (should be ignored)
+	metadata: {
+		version: "1.0.0"
+		features: ["monitoring", "scaling"]
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, traitDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept PolicyDefinition with only standard Kubernetes resources", func() {
+			policyDef := &v1beta1.PolicyDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "PolicyDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-policy-standard-resources",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.PolicyDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	namespace: string
+	enabled: bool | *true
+	labels: {...} | *{}
+}
+
+output: {
+	apiVersion: "v1"
+	kind: "Namespace"
+	metadata: {
+		name: parameter.namespace
+		labels: parameter.labels
+	}
+}
+
+outputs: {
+	networkPolicy: {
+		apiVersion: "networking.k8s.io/v1"
+		kind: "NetworkPolicy"
+		metadata: {
+			name: parameter.namespace + "-default-deny"
+			namespace: parameter.namespace
+		}
+		spec: {
+			podSelector: {}
+			policyTypes: ["Ingress", "Egress"]
+		}
+	}
+	resourceQuota: {
+		apiVersion: "v1"
+		kind: "ResourceQuota"
+		metadata: {
+			name: parameter.namespace + "-quota"
+			namespace: parameter.namespace
+		}
+		spec: {
+			hard: {
+				"requests.cpu": "4"
+				"requests.memory": "8Gi"
+				"limits.cpu": "8"
+				"limits.memory": "16Gi"
+				"pods": "10"
+			}
+		}
+	}
+	limitRange: {
+		apiVersion: "v1"
+		kind: "LimitRange"
+		metadata: {
+			name: parameter.namespace + "-limits"
+			namespace: parameter.namespace
+		}
+		spec: {
+			limits: [{
+				type: "Container"
+				default: {
+					cpu: "100m"
+					memory: "128Mi"
+				}
+				defaultRequest: {
+					cpu: "50m"
+					memory: "64Mi"
+				}
+			}]
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, policyDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, policyDef)).Should(Succeed())
+		})
+
+		It("Should validate definitions with empty outputs", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-empty-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	image: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: parameter.name
+				image: parameter.image
+			}]
+		}
+	}
+}
+
+// Empty outputs should be valid
+outputs: {}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, componentDef)).Should(Succeed())
+		})
+
+		It("Should reject WorkflowStepDefinition with non-existent CRD in outputs", func() {
+			workflowStepDef := &v1beta1.WorkflowStepDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "WorkflowStepDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-workflowstep-with-invalid-output",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.WorkflowStepDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	namespace: string
+	name: string
+}
+
+output: {
+	apiVersion: "v1"
+	kind: "ConfigMap"
+	metadata: {
+		name: parameter.name
+		namespace: parameter.namespace
+	}
+	data: {
+		status: "created"
+	}
+}
+
+outputs: {
+	invalidStep: {
+		apiVersion: "workflow.custom.io/v1alpha1"
+		kind: "WorkflowStep"
+		metadata: name: parameter.name + "-step"
+		spec: {
+			type: "custom"
+			enabled: true
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, workflowStepDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept WorkflowStepDefinition with valid resources", func() {
+			workflowStepDef := &v1beta1.WorkflowStepDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "WorkflowStepDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-workflowstep-with-valid-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.WorkflowStepDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	namespace: string
+	name: string
+	data: {...}
+}
+
+output: {
+	apiVersion: "v1"
+	kind: "ConfigMap"
+	metadata: {
+		name: parameter.name
+		namespace: parameter.namespace
+	}
+	data: parameter.data
+}
+
+outputs: {
+	secret: {
+		apiVersion: "v1"
+		kind: "Secret"
+		metadata: {
+			name: parameter.name + "-secret"
+			namespace: parameter.namespace
+		}
+		type: "Opaque"
+		data: {
+			key: "dmFsdWU="  // base64 encoded "value"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, workflowStepDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, workflowStepDef)).Should(Succeed())
+		})
+
+		It("Should reject WorkflowStepDefinition with mixed valid and invalid resources", func() {
+			workflowStepDef := &v1beta1.WorkflowStepDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "WorkflowStepDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-workflowstep-mixed-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.WorkflowStepDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+	namespace: string
+}
+
+output: {
+	apiVersion: "batch/v1"
+	kind: "Job"
+	metadata: {
+		name: parameter.name
+		namespace: parameter.namespace
+	}
+	spec: {
+		template: {
+			spec: {
+				containers: [{
+					name: "job"
+					image: "busybox"
+					command: ["echo", "hello"]
+				}]
+				restartPolicy: "Never"
+			}
+		}
+	}
+}
+
+outputs: {
+	// Valid resource
+	cronJob: {
+		apiVersion: "batch/v1"
+		kind: "CronJob"
+		metadata: {
+			name: parameter.name + "-cron"
+			namespace: parameter.namespace
+		}
+		spec: {
+			schedule: "*/5 * * * *"
+			jobTemplate: {
+				spec: {
+					template: {
+						spec: {
+							containers: [{
+								name: "cron"
+								image: "busybox"
+								command: ["echo", "cron"]
+							}]
+							restartPolicy: "Never"
+						}
+					}
+				}
+			}
+		}
+	}
+	// Invalid custom resource
+	customScheduler: {
+		apiVersion: "scheduler.custom.io/v1beta1"
+		kind: "CustomScheduler"
+		metadata: {
+			name: parameter.name + "-scheduler"
+		}
+		spec: {
+			interval: "5m"
+			action: "notify"
+		}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, workflowStepDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+
+		It("Should accept WorkflowStepDefinition without outputs", func() {
+			workflowStepDef := &v1beta1.WorkflowStepDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "WorkflowStepDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-workflowstep-no-outputs",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.WorkflowStepDefinitionSpec{
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	message: string
+	delay: int | *1
+}
+
+// This workflow step just processes data without creating resources
+processedData: {
+	message: parameter.message
+	timestamp: "2024-01-01T00:00:00Z"
+	processed: true
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, workflowStepDef)
+			Expect(err).NotTo(HaveOccurred())
+
+			// Clean up
+			Expect(k8sClient.Delete(ctx, workflowStepDef)).Should(Succeed())
+		})
+
+		It("Should reject ComponentDefinition with invalid apiVersion format", func() {
+			componentDef := &v1beta1.ComponentDefinition{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ComponentDefinition",
+					APIVersion: "core.oam.dev/v1beta1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-comp-invalid-apiversion",
+					Namespace: namespace,
+				},
+				Spec: v1beta1.ComponentDefinitionSpec{
+					Workload: common.WorkloadTypeDescriptor{
+						Definition: common.WorkloadGVK{
+							APIVersion: "apps/v1",
+							Kind:       "Deployment",
+						},
+					},
+					Schematic: &common.Schematic{
+						CUE: &common.CUE{
+							Template: `
+parameter: {
+	name: string
+}
+
+output: {
+	apiVersion: "apps/v1"
+	kind: "Deployment"
+	metadata: name: parameter.name
+	spec: {
+		selector: matchLabels: app: parameter.name
+		template: {
+			metadata: labels: app: parameter.name
+			spec: containers: [{
+				name: "nginx"
+				image: "nginx:latest"
+			}]
+		}
+	}
+}
+
+outputs: {
+	invalidResource: {
+		apiVersion: "invalid-format-no-slash"
+		kind: "SomeResource"
+		metadata: name: parameter.name
+		spec: {}
+	}
+}`,
+						},
+					},
+				},
+			}
+
+			err := k8sClient.Create(ctx, componentDef)
+			Expect(err).To(HaveOccurred())
+			Expect(err.Error()).To(ContainSubstring("resource type not found on cluster"))
+		})
+	})
+})
diff --git a/test/e2e-test/definition_revision_test.go b/test/e2e-test/definition_revision_test.go
index 63db5e17..b437011e 100644
--- a/test/e2e-test/definition_revision_test.go
+++ b/test/e2e-test/definition_revision_test.go
@@ -930,7 +930,7 @@ outputs: service: {
 }
 
 outputs: ingress: {
-	apiVersion: "networking.k8s.io/v1beta1"
+	apiVersion: "networking.k8s.io/v1"
 	kind:       "Ingress"
 	metadata:
 		name: context.name
@@ -941,9 +941,14 @@ outputs: ingress: {
 				paths: [
 					for k, v in parameter.http {
 						path: k
+						pathType: "Prefix"
 						backend: {
-							serviceName: context.name
-							servicePort: v
+							service: {
+								name: context.name
+								port: {
+									number: v
+								}
+							}
 						}
 					},
 				]