This is an automated email from the ASF dual-hosted git repository.

squakez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit bb4a4955c6841f9928ba30286ad885aafa78075c
Author: AllanAlmeida <[email protected]>
AuthorDate: Tue Sep 22 11:16:12 2026 -0300

    Fix #6778: Improve denied Kamelet diagnostics
    
    Generated-by: OpenAI Codex
---
 pkg/trait/kamelets.go                  |  4 +--
 pkg/trait/kamelets_test.go             | 66 ++++++++++++++++++++++++++++++++--
 pkg/util/kubernetes/permission_test.go | 36 +++++++++++++++++++
 3 files changed, 101 insertions(+), 5 deletions(-)

diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 6b3c16133..dad678579 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -234,8 +234,8 @@ func (t *kameletsTrait) calculateNamespaces(e *Environment, 
defaultNamespaces ..
                        return nil, err
                }
                if !ok {
-                       return nil, fmt.Errorf("cross-namespace Integration 
reference authorization denied for the ServiceAccount %s and resources 
kamelets",
-                               e.Integration.Spec.ServiceAccountName)
+                       return nil, fmt.Errorf("cross-namespace Integration 
reference authorization denied for the ServiceAccount %s and Kamelet %s in 
namespace %s",
+                               e.Integration.Spec.ServiceAccountName, 
getKameletKey(kml), ns)
                }
        }
 
diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go
index 91652f4dd..d471d4ed0 100644
--- a/pkg/trait/kamelets_test.go
+++ b/pkg/trait/kamelets_test.go
@@ -18,11 +18,14 @@ limitations under the License.
 package trait
 
 import (
+       "context"
        "encoding/json"
+       "errors"
        "testing"
 
        v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
        traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait"
+       camelclient "github.com/apache/camel-k/v2/pkg/client"
 
        "github.com/apache/camel-k/v2/pkg/internal"
        "github.com/apache/camel-k/v2/pkg/util/camel"
@@ -32,9 +35,21 @@ import (
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime"
+       kubernetesfake "k8s.io/client-go/kubernetes/fake"
+       authorizationclientv1 
"k8s.io/client-go/kubernetes/typed/authorization/v1"
+       k8stesting "k8s.io/client-go/testing"
        "k8s.io/utils/ptr"
 )
 
+type authorizationClient struct {
+       camelclient.Client
+       authorization authorizationclientv1.AuthorizationV1Interface
+}
+
+func (c *authorizationClient) AuthorizationV1() 
authorizationclientv1.AuthorizationV1Interface {
+       return c.authorization
+}
+
 func TestConfigurationNoKameletsUsed(t *testing.T) {
        trait, environment := createKameletsTestEnvironment(`
 - from:
@@ -772,7 +787,12 @@ func TestKameletNamespaceParameter(t *testing.T) {
 
 func TestCalculateKameletNamespaces(t *testing.T) {
        namespaces, err := calculateNamespaces(
-               []string{"my-kamelet", "my-kamelet?kameletNamespace=ns1", 
"my-kamelet?kameletVersion=v2&kameletNamespace=ns2"},
+               []string{
+                       "my-kamelet",
+                       "my-kamelet?kameletNamespace=ns1",
+                       "another-kamelet?kameletNamespace=ns1",
+                       "my-kamelet?kameletVersion=v2&kameletNamespace=ns2",
+               },
        )
        require.NoError(t, err)
        assert.Len(t, namespaces, 2)
@@ -780,6 +800,15 @@ func TestCalculateKameletNamespaces(t *testing.T) {
        assert.Contains(t, namespaces, "ns2")
 }
 
+func TestCalculateKameletNamespacesInvalidReference(t *testing.T) {
+       trait, environment := createKameletsTestEnvironment("")
+       trait.List = "invalid%reference?kameletNamespace=ns1"
+
+       namespaces, err := trait.calculateNamespaces(environment)
+       require.ErrorContains(t, err, "could not parse kamelet namespace")
+       assert.Nil(t, namespaces)
+}
+
 func TestKameletMultiNamespace(t *testing.T) {
        flow := `
 - from:
@@ -835,7 +864,7 @@ func TestKameletMultiNamespace(t *testing.T) {
        err = trait.Apply(environment)
        require.Error(t, err)
        assert.Equal(t, "cross-namespace Integration reference authorization 
denied for the ServiceAccount unauth-sa "+
-               "and resources kamelets", err.Error())
+               "and Kamelet extra in namespace ns1", err.Error())
        // Now we should good to go
        environment.Integration.Namespace = "default"
        environment.Integration.Spec.ServiceAccountName = "cross-ns-sa"
@@ -870,7 +899,38 @@ func TestKameletMultiNamespaceDeniedResource(t *testing.T) 
{
        err = trait.Apply(environment)
        require.Error(t, err)
        assert.Equal(t, "cross-namespace Integration reference authorization 
denied for the ServiceAccount cross-ns-sa "+
-               "and resources kamelets", err.Error())
+               "and Kamelet restricted-kamelet in namespace ns1", err.Error())
+}
+
+func TestKameletMultiNamespacePermissionCheckError(t *testing.T) {
+       flow := `
+- from:
+    uri: kamelet:timer
+    steps:
+    - to: kamelet:extra?kameletNamespace=ns1
+`
+       trait, environment := createKameletsTestEnvironment(flow)
+       environment.Ctx = context.Background()
+       environment.Integration.Namespace = "default"
+       environment.Integration.Spec.ServiceAccountName = "cross-ns-sa"
+
+       authorizationError := errors.New("subject access review failed")
+       client := kubernetesfake.NewSimpleClientset()
+       client.PrependReactor("create", "subjectaccessreviews", 
func(k8stesting.Action) (bool, runtime.Object, error) {
+               return true, nil, authorizationError
+       })
+       environment.Client = &authorizationClient{
+               Client:        environment.Client,
+               authorization: client.AuthorizationV1(),
+       }
+
+       enabled, condition, err := trait.Configure(environment)
+       require.NoError(t, err)
+       assert.True(t, enabled)
+       assert.Nil(t, condition)
+
+       err = trait.Apply(environment)
+       require.ErrorIs(t, err, authorizationError)
 }
 
 func TestKameletMultiNamespaceMissing(t *testing.T) {
diff --git a/pkg/util/kubernetes/permission_test.go 
b/pkg/util/kubernetes/permission_test.go
index 10ed4f878..1d4182584 100644
--- a/pkg/util/kubernetes/permission_test.go
+++ b/pkg/util/kubernetes/permission_test.go
@@ -19,10 +19,13 @@ package kubernetes
 
 import (
        "context"
+       "errors"
        "testing"
 
        authorizationv1 "k8s.io/api/authorization/v1"
+       apierrors "k8s.io/apimachinery/pkg/api/errors"
        "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/schema"
        "k8s.io/client-go/kubernetes/fake"
        k8stesting "k8s.io/client-go/testing"
 
@@ -61,3 +64,36 @@ func TestCheckServiceAccountPermissionByResourceName(t 
*testing.T) {
        require.NoError(t, err)
        require.False(t, allowed)
 }
+
+func TestCheckServiceAccountPermissionForbidden(t *testing.T) {
+       client := fake.NewSimpleClientset()
+       client.PrependReactor("create", "subjectaccessreviews", 
func(k8stesting.Action) (bool, runtime.Object, error) {
+               return true, nil, apierrors.NewForbidden(
+                       schema.GroupResource{Group: "authorization.k8s.io", 
Resource: "subjectaccessreviews"},
+                       "",
+                       errors.New("forbidden"),
+               )
+       })
+
+       allowed, err := CheckServiceAccountPermission(
+               context.Background(), client, 
"system:serviceaccount:source:integration",
+               "camel.apache.org", "kamelets", "target", "denied-kamelet", 
"get",
+       )
+       require.NoError(t, err)
+       require.False(t, allowed)
+}
+
+func TestCheckServiceAccountPermissionError(t *testing.T) {
+       expected := errors.New("subject access review failed")
+       client := fake.NewSimpleClientset()
+       client.PrependReactor("create", "subjectaccessreviews", 
func(k8stesting.Action) (bool, runtime.Object, error) {
+               return true, nil, expected
+       })
+
+       allowed, err := CheckServiceAccountPermission(
+               context.Background(), client, 
"system:serviceaccount:source:integration",
+               "camel.apache.org", "kamelets", "target", "denied-kamelet", 
"get",
+       )
+       require.ErrorIs(t, err, expected)
+       require.False(t, allowed)
+}

Reply via email to