Repository: rh-ecosystem-edge/kernel-module-management
Pull request #1488: Combined the `Maker` interface into `ocpbuildManager`.
Author: login: ybettan
Labels: name: approved
name: lgtm
Created: 2025-05-08T12:57:02Z | Merged: 2025-05-09T03:53:50Z

Moving the `buildsign.Helper` interface to `module` package.

This interface is combining between the global build/sign section and
the kernel-mapping build/sign section, therefore, it belongs in the
`Module` package.

---

Fixes https://github.com/rh-ecosystem-edge/kernel-module-management/issues/1485
/assign @TomerNewman @yevgeny-shnaidman 

/hold
Should be rebased and merged on top of https://github.com/rh-ecosystem-edge/kernel-module-management/pull/1487

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Refactor**
  - Simplified and consolidated build template creation logic for OpenShift Builds, removing redundant code and interfaces.
  - Updated internal structure to streamline dependencies and improve maintainability.

- **Tests**
  - Enhanced and expanded test coverage for build template creation, including new scenarios and improved error handling.
  - Removed obsolete test files and mocks related to deprecated interfaces.

- **Chores**
  - Updated metadata timestamps in manifest files for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml b/bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml
index dc4f50350..c11747d55 100644
--- a/bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml
+++ b/bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml
@@ -37,7 +37,7 @@ metadata:
         }
       ]
     capabilities: Seamless Upgrades
-    createdAt: "2025-05-08T09:53:34Z"
+    createdAt: "2025-05-08T12:03:14Z"
     operatorframework.io/suggested-namespace: openshift-kmm-hub
     operators.operatorframework.io/builder: operator-sdk-v1.32.0
     operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
diff --git a/bundle/manifests/kernel-module-management.clusterserviceversion.yaml b/bundle/manifests/kernel-module-management.clusterserviceversion.yaml
index 9653465d3..e81de9d8d 100644
--- a/bundle/manifests/kernel-module-management.clusterserviceversion.yaml
+++ b/bundle/manifests/kernel-module-management.clusterserviceversion.yaml
@@ -63,7 +63,7 @@ metadata:
         }
       ]
     capabilities: Seamless Upgrades
-    createdAt: "2025-05-08T09:53:32Z"
+    createdAt: "2025-05-08T12:03:12Z"
     operatorframework.io/suggested-namespace: openshift-kmm
     operators.operatorframework.io/builder: operator-sdk-v1.32.0
     operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
diff --git a/internal/buildsign/ocpbuild/common.go b/internal/buildsign/ocpbuild/common.go
new file mode 100644
index 000000000..da02d7b6c
--- /dev/null
+++ b/internal/buildsign/ocpbuild/common.go
@@ -0,0 +1,52 @@
+package ocpbuild
+
+import (
+	buildv1 "github.com/openshift/api/build/v1"
+	kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/utils/ptr"
+)
+
+const dtkBuildArg = "DTK_AUTO"
+
+func envVarsFromKMMBuildArgs(args []kmmv1beta1.BuildArg) []v1.EnvVar {
+	if args == nil {
+		return nil
+	}
+
+	ev := make([]v1.EnvVar, 0, len(args))
+
+	for _, ba := range args {
+		ev = append(ev, v1.EnvVar{Name: ba.Name, Value: ba.Value})
+	}
+
+	return ev
+}
+
+func buildVolumesFromBuildSecrets(secrets []v1.LocalObjectReference) []buildv1.BuildVolume {
+	if secrets == nil {
+		return nil
+	}
+
+	vols := make([]buildv1.BuildVolume, 0, len(secrets))
+
+	for _, s := range secrets {
+		bv := buildv1.BuildVolume{
+			Name: "secret-" + s.Name,
+			Source: buildv1.BuildVolumeSource{
+				Type: buildv1.BuildVolumeSourceTypeSecret,
+				Secret: &v1.SecretVolumeSource{
+					SecretName: s.Name,
+					Optional:   ptr.To(false),
+				},
+			},
+			Mounts: []buildv1.BuildVolumeMount{
+				{DestinationPath: "/run/secrets/" + s.Name},
+			},
+		}
+
+		vols = append(vols, bv)
+	}
+
+	return vols
+}
diff --git a/internal/buildsign/ocpbuild/maker.go b/internal/buildsign/ocpbuild/maker.go
deleted file mode 100644
index 81cbc39ad..000000000
--- a/internal/buildsign/ocpbuild/maker.go
+++ /dev/null
@@ -1,231 +0,0 @@
-package ocpbuild
-
-import (
-	"context"
-	"fmt"
-	"strings"
-
-	"github.com/mitchellh/hashstructure/v2"
-	buildv1 "github.com/openshift/api/build/v1"
-	kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/constants"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/module"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/syncronizedmap"
-	corev1 "k8s.io/api/core/v1"
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/utils/ptr"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
-)
-
-const (
-	dtkBuildArg = "DTK_AUTO"
-)
-
-//go:generate mockgen -source=maker.go -package=ocpbuild -destination=mock_maker.go Maker
-
-type maker interface {
-	makeBuildTemplate(
-		ctx context.Context,
-		mld *api.ModuleLoaderData,
-		pushImage bool,
-		owner metav1.Object,
-	) (*buildv1.Build, error)
-}
-
-type makerImpl struct {
-	client             client.Client
-	combiner           module.Combiner
-	ocpbuildManager    ocpbuildManager
-	kernelOsDtkMapping syncronizedmap.KernelOsDtkMapping
-	scheme             *runtime.Scheme
-}
-
-func newMaker(client client.Client,
-	combiner module.Combiner,
-	ocpbuildManager ocpbuildManager,
-	kernelOsDtkMapping syncronizedmap.KernelOsDtkMapping,
-	scheme *runtime.Scheme) maker {
-	return &makerImpl{
-		client:             client,
-		combiner:           combiner,
-		ocpbuildManager:    ocpbuildManager,
-		kernelOsDtkMapping: kernelOsDtkMapping,
-		scheme:             scheme,
-	}
-}
-
-func (m *makerImpl) makeBuildTemplate(
-	ctx context.Context,
-	mld *api.ModuleLoaderData,
-	pushImage bool,
-	owner metav1.Object,
-) (*buildv1.Build, error) {
-
-	kmmBuild := mld.Build
-	containerImage := mld.ContainerImage
-	kernelVersion := mld.KernelVersion
-
-	// if build AND sign are specified, then we will build an intermediate image
-	// and let sign produce the final image specified in spec.moduleLoader.container.km.containerImage
-	if module.ShouldBeSigned(mld) {
-		containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
-	}
-
-	overrides := []kmmv1beta1.BuildArg{
-		{
-			Name:  "KERNEL_VERSION",
-			Value: kernelVersion,
-		},
-		{
-			Name:  "KERNEL_FULL_VERSION",
-			Value: kernelVersion,
-		},
-		{
-			Name:  "MOD_NAME",
-			Value: mld.Name,
-		},
-		{
-			Name:  "MOD_NAMESPACE",
-			Value: mld.Namespace,
-		},
-	}
-
-	dockerfileData, err := m.getDockerfileData(ctx, kmmBuild, mld.Namespace)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get dockerfile data from configmap: %v", err)
-	}
-
-	if strings.Contains(dockerfileData, dtkBuildArg) {
-
-		dtkImage, err := m.kernelOsDtkMapping.GetImage(kernelVersion)
-		if err != nil {
-			return nil, fmt.Errorf("could not get DTK image for kernel %v: %v", kernelVersion, err)
-		}
-		overrides = append(overrides, kmmv1beta1.BuildArg{Name: dtkBuildArg, Value: dtkImage})
-	}
-
-	buildArgs := m.combiner.ApplyBuildArgOverrides(
-		kmmBuild.BuildArgs,
-		overrides...,
-	)
-
-	buildTarget := buildv1.BuildOutput{
-		To: &v1.ObjectReference{
-			Kind: "DockerImage",
-			Name: containerImage,
-		},
-		PushSecret: mld.ImageRepoSecret,
-	}
-	if !pushImage {
-		buildTarget = buildv1.BuildOutput{}
-	}
-
-	sourceConfig := buildv1.BuildSource{
-		Dockerfile: &dockerfileData,
-		Type:       buildv1.BuildSourceDockerfile,
-	}
-
-	sourceConfigHash, err := hashstructure.Hash(sourceConfig, hashstructure.FormatV2, nil)
-	if err != nil {
-		return nil, fmt.Errorf("could not hash Build's Buildsource template: %v", err)
-	}
-
-	selector := mld.Selector
-	if len(mld.Build.Selector) != 0 {
-		selector = mld.Build.Selector
-	}
-
-	bc := buildv1.Build{
-		ObjectMeta: metav1.ObjectMeta{
-			GenerateName: mld.Name + "-build-",
-			Namespace:    mld.Namespace,
-			Labels:       m.ocpbuildManager.ocpbuildLabels(mld.Name, mld.KernelNormalizedVersion, ocpbuildTypeBuild),
-			Annotations:  m.ocpbuildManager.ocpbuildAnnotations(sourceConfigHash),
-			Finalizers:   []string{constants.GCDelayFinalizer, constants.JobEventFinalizer},
-		},
-		Spec: buildv1.BuildSpec{
-			CommonSpec: buildv1.CommonSpec{
-				ServiceAccount: constants.OCPBuilderServiceAccountName,
-				Source:         sourceConfig,
-				Strategy: buildv1.BuildStrategy{
-					Type: buildv1.DockerBuildStrategyType,
-					DockerStrategy: &buildv1.DockerBuildStrategy{
-						BuildArgs:  envVarsFromKMMBuildArgs(buildArgs),
-						Volumes:    buildVolumesFromBuildSecrets(kmmBuild.Secrets),
-						PullSecret: mld.ImageRepoSecret,
-					},
-				},
-				Output:         buildTarget,
-				NodeSelector:   selector,
-				MountTrustedCA: ptr.To(true),
-			},
-		},
-	}
-
-	if err := controllerutil.SetControllerReference(owner, &bc, m.scheme); err != nil {
-		return nil, fmt.Errorf("could not set the owner reference: %v", err)
-	}
-
-	return &bc, nil
-}
-
-func (m *makerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
-	dockerfileCM := &corev1.ConfigMap{}
-	namespacedName := types.NamespacedName{Name: buildConfig.DockerfileConfigMap.Name, Namespace: namespace}
-	err := m.client.Get(ctx, namespacedName, dockerfileCM)
-	if err != nil {
-		return "", fmt.Errorf("failed to get dockerfile ConfigMap %s: %v", namespacedName, err)
-	}
-	data, ok := dockerfileCM.Data[constants.DockerfileCMKey]
-	if !ok {
-		return "", fmt.Errorf("invalid Dockerfile ConfigMap %s format, %s key is missing", namespacedName, constants.DockerfileCMKey)
-	}
-	return data, nil
-}
-
-func envVarsFromKMMBuildArgs(args []kmmv1beta1.BuildArg) []v1.EnvVar {
-	if args == nil {
-		return nil
-	}
-
-	ev := make([]v1.EnvVar, 0, len(args))
-
-	for _, ba := range args {
-		ev = append(ev, v1.EnvVar{Name: ba.Name, Value: ba.Value})
-	}
-
-	return ev
-}
-
-func buildVolumesFromBuildSecrets(secrets []v1.LocalObjectReference) []buildv1.BuildVolume {
-	if secrets == nil {
-		return nil
-	}
-
-	vols := make([]buildv1.BuildVolume, 0, len(secrets))
-
-	for _, s := range secrets {
-		bv := buildv1.BuildVolume{
-			Name: "secret-" + s.Name,
-			Source: buildv1.BuildVolumeSource{
-				Type: buildv1.BuildVolumeSourceTypeSecret,
-				Secret: &v1.SecretVolumeSource{
-					SecretName: s.Name,
-					Optional:   ptr.To(false),
-				},
-			},
-			Mounts: []buildv1.BuildVolumeMount{
-				{DestinationPath: "/run/secrets/" + s.Name},
-			},
-		}
-
-		vols = append(vols, bv)
-	}
-
-	return vols
-}
diff --git a/internal/buildsign/ocpbuild/maker_test.go b/internal/buildsign/ocpbuild/maker_test.go
deleted file mode 100644
index e55ab4d58..000000000
--- a/internal/buildsign/ocpbuild/maker_test.go
+++ /dev/null
@@ -1,369 +0,0 @@
-package ocpbuild
-
-import (
-	"context"
-	"errors"
-	"fmt"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/mitchellh/hashstructure/v2"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	buildv1 "github.com/openshift/api/build/v1"
-	"go.uber.org/mock/gomock"
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/utils/ptr"
-	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
-
-	kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/client"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/constants"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/module"
-	"github.com/rh-ecosystem-edge/kernel-module-management/internal/syncronizedmap"
-)
-
-var _ = Describe("maker_makeBuildTemplate", func() {
-	const (
-		containerImage = "container-image"
-		dockerFile     = "FROM some-image"
-		moduleName     = "some-name"
-		namespace      = "some-namespace"
-		targetKernel   = "target-kernel"
-	)
-
-	var (
-		ctrl                   *gomock.Controller
-		clnt                   *client.MockClient
-		maker                  maker
-		mockCombiner           *module.MockCombiner
-		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
-		mockOCPBuildManager    *MockocpbuildManager
-		ctx                    context.Context
-	)
-
-	BeforeEach(func() {
-		ctrl = gomock.NewController(GinkgoT())
-		clnt = client.NewMockClient(ctrl)
-		mockCombiner = module.NewMockCombiner(ctrl)
-		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
-		mockOCPBuildManager = NewMockocpbuildManager(ctrl)
-		maker = newMaker(clnt, mockCombiner, mockOCPBuildManager, mockKernelOSDTKMapping, scheme)
-		ctx = context.Background()
-	})
-
-	AfterEach(func() {
-		ctrl.Finish()
-	})
-
-	dockerfileConfigMap := v1.LocalObjectReference{Name: "configMapName"}
-	dockerfileCMData := map[string]string{constants.DockerfileCMKey: dockerFile}
-
-	DescribeTable("should set fields correctly", func(
-		buildSecrets []v1.LocalObjectReference,
-		imagePullSecret *v1.LocalObjectReference,
-		useBuildSelector bool) {
-		nodeSelector := map[string]string{"label-key": "label-value"}
-
-		buildArgs := []kmmv1beta1.BuildArg{
-			{
-				Name:  "arg-1",
-				Value: "value-1",
-			},
-			{
-				Name:  "arg-2",
-				Value: "value-2",
-			},
-		}
-
-		irs := v1.LocalObjectReference{Name: "push-secret"}
-
-		mld := api.ModuleLoaderData{
-			Name:           moduleName,
-			Namespace:      namespace,
-			ContainerImage: containerImage,
-			Build: &kmmv1beta1.Build{
-				BuildArgs:           buildArgs,
-				DockerfileConfigMap: &dockerfileConfigMap,
-				Secrets:             buildSecrets,
-			},
-			ImageRepoSecret:         &irs,
-			Selector:                nodeSelector,
-			KernelVersion:           targetKernel,
-			KernelNormalizedVersion: targetKernel,
-			Owner: &kmmv1beta1.Module{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      moduleName,
-					Namespace: namespace,
-				},
-			},
-		}
-
-		if useBuildSelector {
-			mld.Selector = nil
-			mld.Build.Selector = nodeSelector
-		}
-
-		overrides := []kmmv1beta1.BuildArg{
-			{Name: "KERNEL_VERSION", Value: targetKernel},
-			{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
-			{Name: "MOD_NAME", Value: moduleName},
-			{Name: "MOD_NAMESPACE", Value: namespace},
-		}
-
-		expected := buildv1.Build{
-			ObjectMeta: metav1.ObjectMeta{
-				GenerateName: moduleName + "-build-",
-				Namespace:    namespace,
-				OwnerReferences: []metav1.OwnerReference{
-					{
-						APIVersion:         "kmm.sigs.x-k8s.io/v1beta1",
-						Kind:               "Module",
-						Name:               moduleName,
-						Controller:         ptr.To(true),
-						BlockOwnerDeletion: ptr.To(true),
-					},
-				},
-				Finalizers: []string{constants.GCDelayFinalizer, constants.JobEventFinalizer},
-			},
-			Spec: buildv1.BuildSpec{
-				CommonSpec: buildv1.CommonSpec{
-					ServiceAccount: "builder",
-					Source: buildv1.BuildSource{
-						Dockerfile: ptr.To(dockerFile),
-						Type:       buildv1.BuildSourceDockerfile,
-					},
-					Strategy: buildv1.BuildStrategy{
-						Type: buildv1.DockerBuildStrategyType,
-						DockerStrategy: &buildv1.DockerBuildStrategy{
-							BuildArgs: append(
-								envVarsFromKMMBuildArgs(buildArgs),
-								v1.EnvVar{Name: "KERNEL_VERSION", Value: targetKernel},
-								v1.EnvVar{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
-								v1.EnvVar{Name: "MOD_NAME", Value: moduleName},
-								v1.EnvVar{Name: "MOD_NAMESPACE", Value: namespace},
-							),
-							Volumes:    buildVolumesFromBuildSecrets(buildSecrets),
-							PullSecret: &irs,
-						},
-					},
-					Output: buildv1.BuildOutput{
-						To: &v1.ObjectReference{
-							Kind: "DockerImage",
-							Name: containerImage,
-						},
-						PushSecret: &irs,
-					},
-					NodeSelector:   nodeSelector,
-					MountTrustedCA: ptr.To(true),
-				},
-			},
-		}
-
-		if imagePullSecret != nil {
-			mld.ImageRepoSecret = imagePullSecret
-			expected.Spec.CommonSpec.Output.PushSecret = imagePullSecret
-			expected.Spec.Strategy.DockerStrategy.PullSecret = imagePullSecret
-		}
-
-		if len(buildSecrets) > 0 {
-
-			mld.Build.Secrets = buildSecrets
-
-			expected.Spec.CommonSpec.Strategy.DockerStrategy.Volumes = buildVolumesFromBuildSecrets(buildSecrets)
-		}
-
-		hash, err := hashstructure.Hash(expected.Spec.CommonSpec.Source, hashstructure.FormatV2, nil)
-		Expect(err).NotTo(HaveOccurred())
-		annotations := map[string]string{hashAnnotation: fmt.Sprintf("%d", hash)}
-		expected.SetAnnotations(annotations)
-		labels := map[string]string{"some label": "some value"}
-		expected.SetLabels(labels)
-
-		gomock.InOrder(
-			clnt.EXPECT().Get(ctx, types.NamespacedName{Name: dockerfileConfigMap.Name, Namespace: mld.Namespace}, gomock.Any()).DoAndReturn(
-				func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
-					cm.Data = dockerfileCMData
-					return nil
-				},
-			),
-			mockCombiner.EXPECT().ApplyBuildArgOverrides(buildArgs, overrides).Return(
-				append(buildArgs,
-					kmmv1beta1.BuildArg{Name: "KERNEL_VERSION", Value: targetKernel},
-					kmmv1beta1.BuildArg{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
-					kmmv1beta1.BuildArg{Name: "MOD_NAME", Value: moduleName},
-					kmmv1beta1.BuildArg{Name: "MOD_NAMESPACE", Value: namespace}),
-			),
-			mockOCPBuildManager.EXPECT().ocpbuildLabels(moduleName, targetKernel, ocpbuildTypeBuild).Return(labels),
-			mockOCPBuildManager.EXPECT().ocpbuildAnnotations(hash).Return(annotations),
-		)
-
-		bc, err := maker.makeBuildTemplate(ctx, &mld, true, mld.Owner)
-		Expect(err).NotTo(HaveOccurred())
-
-		Expect(
-			cmp.Diff(&expected, bc),
-		).To(
-			BeEmpty(),
-		)
-	},
-		Entry(
-			"no secrets at all",
-			[]v1.LocalObjectReference{},
-			nil,
-			false,
-		),
-		Entry(
-			"no secrets at all with build.Selector property",
-			[]v1.LocalObjectReference{},
-			nil,
-			true,
-		),
-		Entry(
-			"only buildSecrets",
-			[]v1.LocalObjectReference{{Name: "s1"}},
-			nil,
-			false,
-		),
-		Entry(
-			"only imagePullSecrets",
-			[]v1.LocalObjectReference{},
-			&v1.LocalObjectReference{Name: "pull-push-secret"},
-			false,
-		),
-		Entry(
-			"buildSecrets and imagePullSecrets",
-			[]v1.LocalObjectReference{{Name: "s1"}},
-			&v1.LocalObjectReference{Name: "pull-push-secret"},
-			false,
-		),
-	)
-
-	Context(fmt.Sprintf("using %s", dtkBuildArg), func() {
-		It("should fail if we couldn't get the DTK image", func() {
-
-			gomock.InOrder(
-				clnt.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(
-					func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
-						dockerfileData := fmt.Sprintf("FROM %s", dtkBuildArg)
-						cm.Data = map[string]string{constants.DockerfileCMKey: dockerfileData}
-						return nil
-					},
-				),
-				mockKernelOSDTKMapping.EXPECT().GetImage(gomock.Any()).Return("", errors.New("random error")),
-			)
-
-			mld := api.ModuleLoaderData{
-				Build: &kmmv1beta1.Build{
-					DockerfileConfigMap: &dockerfileConfigMap,
-				},
-			}
-			_, err := maker.makeBuildTemplate(ctx, &mld, false, mld.Owner)
-			Expect(err).To(HaveOccurred())
-		})
-
-		It(fmt.Sprintf("should add a build arg if %s is used in the Dockerfile", dtkBuildArg), func() {
-
-			const dtkImage = "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:111"
-
-			buildArgs := []kmmv1beta1.BuildArg{
-				{
-					Name:  dtkBuildArg,
-					Value: dtkImage,
-				},
-			}
-
-			gomock.InOrder(
-				clnt.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(
-					func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
-						dockerfileData := fmt.Sprintf("FROM %s", dtkBuildArg)
-						cm.Data = map[string]string{constants.DockerfileCMKey: dockerfileData}
-						return nil
-					},
-				),
-				mockKernelOSDTKMapping.EXPECT().GetImage(gomock.Any()).Return(dtkImage, nil),
-				mockCombiner.EXPECT().ApplyBuildArgOverrides(gomock.Any(), gomock.Any()).Return(buildArgs),
-				mockOCPBuildManager.EXPECT().ocpbuildLabels(gomock.Any(), gomock.Any(), ocpbuildTypeBuild),
-				mockOCPBuildManager.EXPECT().ocpbuildAnnotations(gomock.Any()),
-			)
-
-			mld := api.ModuleLoaderData{
-				Build: &kmmv1beta1.Build{
-					DockerfileConfigMap: &dockerfileConfigMap,
-				},
-				Owner: &kmmv1beta1.Module{},
-			}
-			bct, err := maker.makeBuildTemplate(ctx, &mld, false, mld.Owner)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(len(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs)).To(Equal(1))
-			Expect(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs[0].Name).To(Equal(buildArgs[0].Name))
-			Expect(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs[0].Value).To(Equal(buildArgs[0].Value))
-		})
-	})
-})
-
-var _ = Describe("envVarsFromKMMBuildArgs", func() {
-	It("should return nil if args is nil", func() {
-		Expect(envVarsFromKMMBuildArgs(nil)).To(BeNil())
-	})
-
-	It("should work as expected", func() {
-		args := []kmmv1beta1.BuildArg{
-			{Name: "arg1", Value: "value1"},
-			{Name: "arg2", Value: "value2"},
-		}
-
-		expected := []v1.EnvVar{
-			{Name: "arg1", Value: "value1"},
-			{Name: "arg2", Value: "value2"},
-		}
-
-		Expect(envVarsFromKMMBuildArgs(args)).To(Equal(expected))
-	})
-})
-
-var _ = Describe("buildVolumesFromBuildSecrets", func() {
-	It("should return nil if secrets is nil", func() {
-		Expect(buildVolumesFromBuildSecrets(nil)).To(BeNil())
-	})
-
-	It("should work as expected", func() {
-		secrets := []v1.LocalObjectReference{
-			{Name: "secret-1"},
-			{Name: "secret-2"},
-		}
-
-		expectedVolumes := []buildv1.BuildVolume{
-			{
-				Name: "secret-secret-1",
-				Source: buildv1.BuildVolumeSource{
-					Type: buildv1.BuildVolumeSourceTypeSecret,
-					Secret: &v1.SecretVolumeSource{
-						SecretName: "secret-1",
-						Optional:   ptr.To(false),
-					},
-				},
-				Mounts: []buildv1.BuildVolumeMount{
-					{DestinationPath: "/run/secrets/secret-1"},
-				},
-			},
-			{
-				Name: "secret-secret-2",
-				Source: buildv1.BuildVolumeSource{
-					Type: buildv1.BuildVolumeSourceTypeSecret,
-					Secret: &v1.SecretVolumeSource{
-						SecretName: "secret-2",
-						Optional:   ptr.To(false),
-					},
-				},
-				Mounts: []buildv1.BuildVolumeMount{
-					{DestinationPath: "/run/secrets/secret-2"},
-				},
-			},
-		}
-
-		Expect(buildVolumesFromBuildSecrets(secrets)).To(Equal(expectedVolumes))
-	})
-})
diff --git a/internal/buildsign/ocpbuild/manager.go b/internal/buildsign/ocpbuild/manager.go
index c0c0cc2f3..cb5622caf 100644
--- a/internal/buildsign/ocpbuild/manager.go
+++ b/internal/buildsign/ocpbuild/manager.go
@@ -22,7 +22,6 @@ import (
 
 type manager struct {
 	client          client.Client
-	maker           maker
 	signer          signer
 	ocpbuildManager ocpbuildManager
 }
@@ -32,12 +31,10 @@ func NewManager(client client.Client,
 	kernelOsDtkMapping syncronizedmap.KernelOsDtkMapping,
 	signImage string,
 	scheme *runtime.Scheme) buildsign.Manager {
-	ocpbuildManager := newOCPBuildManager(client)
-	maker := newMaker(client, combiner, ocpbuildManager, kernelOsDtkMapping, scheme)
+	ocpbuildManager := newOCPBuildManager(client, combiner, kernelOsDtkMapping, scheme)
 	signer := newSigner(client, signImage, ocpbuildManager, scheme)
 	return &manager{
 		client:          client,
-		maker:           maker,
 		signer:          signer,
 		ocpbuildManager: ocpbuildManager,
 	}
@@ -84,7 +81,7 @@ func (m *manager) Sync(ctx context.Context, mld *api.ModuleLoaderData, pushImage
 	case kmmv1beta1.BuildImage:
 		logger.Info("Building in-cluster")
 		ocpbuildType = ocpbuildTypeBuild
-		ocpbuildTemplate, err = m.maker.makeBuildTemplate(ctx, mld, pushImage, owner)
+		ocpbuildTemplate, err = m.ocpbuildManager.makeOCPBuildTemplate(ctx, mld, pushImage, owner)
 	case kmmv1beta1.SignImage:
 		logger.Info("Signing in-cluster")
 		ocpbuildType = ocpbuildTypeSign
diff --git a/internal/buildsign/ocpbuild/manager_test.go b/internal/buildsign/ocpbuild/manager_test.go
index 126352e8e..a876287da 100644
--- a/internal/buildsign/ocpbuild/manager_test.go
+++ b/internal/buildsign/ocpbuild/manager_test.go
@@ -20,7 +20,6 @@ var _ = Describe("GetStatus", func() {
 	var (
 		ctrl                *gomock.Controller
 		clnt                *client.MockClient
-		mockMaker           *Mockmaker
 		mockSigner          *Mocksigner
 		mockOCPBuildManager *MockocpbuildManager
 		mgr                 *manager
@@ -34,12 +33,10 @@ var _ = Describe("GetStatus", func() {
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		clnt = client.NewMockClient(ctrl)
-		mockMaker = NewMockmaker(ctrl)
 		mockSigner = NewMocksigner(ctrl)
 		mockOCPBuildManager = NewMockocpbuildManager(ctrl)
 		mgr = &manager{
 			client:          clnt,
-			maker:           mockMaker,
 			signer:          mockSigner,
 			ocpbuildManager: mockOCPBuildManager,
 		}
@@ -105,7 +102,6 @@ var _ = Describe("Sync", func() {
 	var (
 		ctrl                *gomock.Controller
 		clnt                *client.MockClient
-		mockMaker           *Mockmaker
 		mockSigner          *Mocksigner
 		mockOCPBuildManager *MockocpbuildManager
 		mgr                 *manager
@@ -119,12 +115,10 @@ var _ = Describe("Sync", func() {
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		clnt = client.NewMockClient(ctrl)
-		mockMaker = NewMockmaker(ctrl)
 		mockSigner = NewMocksigner(ctrl)
 		mockOCPBuildManager = NewMockocpbuildManager(ctrl)
 		mgr = &manager{
 			client:          clnt,
-			maker:           mockMaker,
 			signer:          mockSigner,
 			ocpbuildManager: mockOCPBuildManager,
 		}
@@ -140,7 +134,7 @@ var _ = Describe("Sync", func() {
 
 	It("makeBuildTemplate failed", func() {
 		By("test build action")
-		mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, true, &testMBSC).Return(nil, fmt.Errorf("some error"))
+		mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, true, &testMBSC).Return(nil, fmt.Errorf("some error"))
 		err := mgr.Sync(ctx, testMLD, true, kmmv1beta1.BuildImage, &testMBSC)
 		Expect(err).To(HaveOccurred())
 
@@ -152,7 +146,7 @@ var _ = Describe("Sync", func() {
 
 	It("GetModulePodByKernel failed", func() {
 		gomock.InOrder(
-			mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, true, &testMBSC).Return(nil, nil),
+			mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, true, &testMBSC).Return(nil, nil),
 			mockOCPBuildManager.EXPECT().getModuleOCPBuildByKernel(ctx, mbscName, mbscNamespace, kernelVersion, ocpbuildTypeBuild, &testMBSC).
 				Return(nil, fmt.Errorf("some error")),
 		)
@@ -163,7 +157,7 @@ var _ = Describe("Sync", func() {
 	It("CreateOCPBuild failed", func() {
 		testTemplate := buildv1.Build{}
 		gomock.InOrder(
-			mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
+			mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
 			mockOCPBuildManager.EXPECT().getModuleOCPBuildByKernel(ctx, mbscName, mbscNamespace, kernelVersion, ocpbuildTypeBuild, &testMBSC).
 				Return(nil, ErrNoMatchingBuild),
 			mockOCPBuildManager.EXPECT().createOCPBuild(ctx, &testTemplate).Return(fmt.Errorf("some error")),
@@ -176,7 +170,7 @@ var _ = Describe("Sync", func() {
 		testTemplate := buildv1.Build{}
 		testBuild := buildv1.Build{}
 		gomock.InOrder(
-			mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
+			mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
 			mockOCPBuildManager.EXPECT().getModuleOCPBuildByKernel(ctx, mbscName, mbscNamespace, kernelVersion, ocpbuildTypeBuild, &testMBSC).
 				Return(&testBuild, nil),
 			mockOCPBuildManager.EXPECT().isOCPBuildChanged(&testBuild, &testTemplate).Return(false, fmt.Errorf("some error")),
@@ -189,7 +183,7 @@ var _ = Describe("Sync", func() {
 		testTemplate := buildv1.Build{}
 		testBuild := buildv1.Build{}
 		gomock.InOrder(
-			mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
+			mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, true, &testMBSC).Return(&testTemplate, nil),
 			mockOCPBuildManager.EXPECT().getModuleOCPBuildByKernel(ctx, mbscName, mbscNamespace, kernelVersion, ocpbuildTypeBuild, &testMBSC).
 				Return(&testBuild, nil),
 			mockOCPBuildManager.EXPECT().isOCPBuildChanged(&testBuild, &testTemplate).Return(true, nil),
@@ -210,7 +204,7 @@ var _ = Describe("Sync", func() {
 		}
 
 		if buildAction {
-			mockMaker.EXPECT().makeBuildTemplate(ctx, testMLD, pushImage, &testMBSC).Return(&testBuildTemplate, nil)
+			mockOCPBuildManager.EXPECT().makeOCPBuildTemplate(ctx, testMLD, pushImage, &testMBSC).Return(&testBuildTemplate, nil)
 		} else {
 			mockSigner.EXPECT().makeBuildTemplate(ctx, testMLD, pushImage, &testMBSC).Return(&testBuildTemplate, nil)
 		}
@@ -246,7 +240,6 @@ var _ = Describe("GarbageCollect", func() {
 	var (
 		ctrl                *gomock.Controller
 		clnt                *client.MockClient
-		mockMaker           *Mockmaker
 		mockSigner          *Mocksigner
 		mockOCPBuildManager *MockocpbuildManager
 		mgr                 *manager
@@ -260,12 +253,10 @@ var _ = Describe("GarbageCollect", func() {
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		clnt = client.NewMockClient(ctrl)
-		mockMaker = NewMockmaker(ctrl)
 		mockSigner = NewMocksigner(ctrl)
 		mockOCPBuildManager = NewMockocpbuildManager(ctrl)
 		mgr = &manager{
 			client:          clnt,
-			maker:           mockMaker,
 			signer:          mockSigner,
 			ocpbuildManager: mockOCPBuildManager,
 		}
diff --git a/internal/buildsign/ocpbuild/mock_maker.go b/internal/buildsign/ocpbuild/mock_maker.go
deleted file mode 100644
index e507d8afb..000000000
--- a/internal/buildsign/ocpbuild/mock_maker.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Source: maker.go
-//
-// Generated by this command:
-//
-//	mockgen -source=maker.go -package=ocpbuild -destination=mock_maker.go Maker
-//
-// Package ocpbuild is a generated GoMock package.
-package ocpbuild
-
-import (
-	context "context"
-	reflect "reflect"
-
-	v1 "github.com/openshift/api/build/v1"
-	api "github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
-	gomock "go.uber.org/mock/gomock"
-	v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// Mockmaker is a mock of maker interface.
-type Mockmaker struct {
-	ctrl     *gomock.Controller
-	recorder *MockmakerMockRecorder
-}
-
-// MockmakerMockRecorder is the mock recorder for Mockmaker.
-type MockmakerMockRecorder struct {
-	mock *Mockmaker
-}
-
-// NewMockmaker creates a new mock instance.
-func NewMockmaker(ctrl *gomock.Controller) *Mockmaker {
-	mock := &Mockmaker{ctrl: ctrl}
-	mock.recorder = &MockmakerMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *Mockmaker) EXPECT() *MockmakerMockRecorder {
-	return m.recorder
-}
-
-// makeBuildTemplate mocks base method.
-func (m *Mockmaker) makeBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool, owner v10.Object) (*v1.Build, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "makeBuildTemplate", ctx, mld, pushImage, owner)
-	ret0, _ := ret[0].(*v1.Build)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// makeBuildTemplate indicates an expected call of makeBuildTemplate.
-func (mr *MockmakerMockRecorder) makeBuildTemplate(ctx, mld, pushImage, owner any) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "makeBuildTemplate", reflect.TypeOf((*Mockmaker)(nil).makeBuildTemplate), ctx, mld, pushImage, owner)
-}
diff --git a/internal/buildsign/ocpbuild/mock_ocbuildmanager.go b/internal/buildsign/ocpbuild/mock_ocbuildmanager.go
index d662c715a..4ad42b074 100644
--- a/internal/buildsign/ocpbuild/mock_ocbuildmanager.go
+++ b/internal/buildsign/ocpbuild/mock_ocbuildmanager.go
@@ -13,6 +13,7 @@ import (
 	reflect "reflect"
 
 	v1 "github.com/openshift/api/build/v1"
+	api "github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
 	gomock "go.uber.org/mock/gomock"
 	v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -128,6 +129,21 @@ func (mr *MockocpbuildManagerMockRecorder) isOCPBuildChanged(existingBuild, newB
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "isOCPBuildChanged", reflect.TypeOf((*MockocpbuildManager)(nil).isOCPBuildChanged), existingBuild, newBuild)
 }
 
+// makeOCPBuildTemplate mocks base method.
+func (m *MockocpbuildManager) makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool, owner v10.Object) (*v1.Build, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "makeOCPBuildTemplate", ctx, mld, pushImage, owner)
+	ret0, _ := ret[0].(*v1.Build)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// makeOCPBuildTemplate indicates an expected call of makeOCPBuildTemplate.
+func (mr *MockocpbuildManagerMockRecorder) makeOCPBuildTemplate(ctx, mld, pushImage, owner any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "makeOCPBuildTemplate", reflect.TypeOf((*MockocpbuildManager)(nil).makeOCPBuildTemplate), ctx, mld, pushImage, owner)
+}
+
 // ocpbuildAnnotations mocks base method.
 func (m *MockocpbuildManager) ocpbuildAnnotations(hash uint64) map[string]string {
 	m.ctrl.T.Helper()
diff --git a/internal/buildsign/ocpbuild/ocpbuildmanager.go b/internal/buildsign/ocpbuild/ocpbuildmanager.go
index 199b2381c..65c9eb283 100644
--- a/internal/buildsign/ocpbuild/ocpbuildmanager.go
+++ b/internal/buildsign/ocpbuild/ocpbuildmanager.go
@@ -4,12 +4,24 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"strings"
 
+	"github.com/mitchellh/hashstructure/v2"
 	buildv1 "github.com/openshift/api/build/v1"
+	corev1 "k8s.io/api/core/v1"
+	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/utils/ptr"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
+	kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
 	"github.com/rh-ecosystem-edge/kernel-module-management/internal/constants"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/module"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/syncronizedmap"
 )
 
 type Status string
@@ -39,15 +51,23 @@ type ocpbuildManager interface {
 	deleteOCPBuild(ctx context.Context, build *buildv1.Build) error
 	ocpbuildLabels(modName, kernelVersion, ocpbuildType string) map[string]string
 	ocpbuildAnnotations(hash uint64) map[string]string
+	makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool, owner metav1.Object) (*buildv1.Build, error)
 }
 
 type ocpbuildManagerImpl struct {
-	client client.Client
+	client             client.Client
+	combiner           module.Combiner
+	kernelOsDtkMapping syncronizedmap.KernelOsDtkMapping
+	scheme             *runtime.Scheme
 }
 
-func newOCPBuildManager(client client.Client) ocpbuildManager {
+func newOCPBuildManager(client client.Client, combiner module.Combiner, kernelOsDtkMapping syncronizedmap.KernelOsDtkMapping,
+	scheme *runtime.Scheme) ocpbuildManager {
 	return &ocpbuildManagerImpl{
-		client: client,
+		client:             client,
+		combiner:           combiner,
+		kernelOsDtkMapping: kernelOsDtkMapping,
+		scheme:             scheme,
 	}
 }
 
@@ -176,3 +196,127 @@ func moduleLabels(modName, ocpbuildType string) map[string]string {
 		constants.BuildTypeLabel:  ocpbuildType,
 	}
 }
+func (omi *ocpbuildManagerImpl) makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool,
+	owner metav1.Object) (*buildv1.Build, error) {
+
+	kmmBuild := mld.Build
+	containerImage := mld.ContainerImage
+	kernelVersion := mld.KernelVersion
+
+	// if build AND sign are specified, then we will build an intermediate image
+	// and let sign produce the final image specified in spec.moduleLoader.container.km.containerImage
+	if module.ShouldBeSigned(mld) {
+		containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
+	}
+
+	overrides := []kmmv1beta1.BuildArg{
+		{
+			Name:  "KERNEL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "KERNEL_FULL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "MOD_NAME",
+			Value: mld.Name,
+		},
+		{
+			Name:  "MOD_NAMESPACE",
+			Value: mld.Namespace,
+		},
+	}
+
+	dockerfileData, err := omi.getDockerfileData(ctx, kmmBuild, mld.Namespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get dockerfile data from configmap: %v", err)
+	}
+
+	if strings.Contains(dockerfileData, dtkBuildArg) {
+
+		dtkImage, err := omi.kernelOsDtkMapping.GetImage(kernelVersion)
+		if err != nil {
+			return nil, fmt.Errorf("could not get DTK image for kernel %v: %v", kernelVersion, err)
+		}
+		overrides = append(overrides, kmmv1beta1.BuildArg{Name: dtkBuildArg, Value: dtkImage})
+	}
+
+	buildArgs := omi.combiner.ApplyBuildArgOverrides(
+		kmmBuild.BuildArgs,
+		overrides...,
+	)
+
+	buildTarget := buildv1.BuildOutput{
+		To: &v1.ObjectReference{
+			Kind: "DockerImage",
+			Name: containerImage,
+		},
+		PushSecret: mld.ImageRepoSecret,
+	}
+	if !pushImage {
+		buildTarget = buildv1.BuildOutput{}
+	}
+
+	sourceConfig := buildv1.BuildSource{
+		Dockerfile: &dockerfileData,
+		Type:       buildv1.BuildSourceDockerfile,
+	}
+
+	sourceConfigHash, err := hashstructure.Hash(sourceConfig, hashstructure.FormatV2, nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not hash Build's Buildsource template: %v", err)
+	}
+
+	selector := mld.Selector
+	if len(mld.Build.Selector) != 0 {
+		selector = mld.Build.Selector
+	}
+
+	bc := buildv1.Build{
+		ObjectMeta: metav1.ObjectMeta{
+			GenerateName: mld.Name + "-build-",
+			Namespace:    mld.Namespace,
+			Labels:       omi.ocpbuildLabels(mld.Name, mld.KernelNormalizedVersion, ocpbuildTypeBuild),
+			Annotations:  omi.ocpbuildAnnotations(sourceConfigHash),
+			Finalizers:   []string{constants.GCDelayFinalizer, constants.JobEventFinalizer},
+		},
+		Spec: buildv1.BuildSpec{
+			CommonSpec: buildv1.CommonSpec{
+				ServiceAccount: constants.OCPBuilderServiceAccountName,
+				Source:         sourceConfig,
+				Strategy: buildv1.BuildStrategy{
+					Type: buildv1.DockerBuildStrategyType,
+					DockerStrategy: &buildv1.DockerBuildStrategy{
+						BuildArgs:  envVarsFromKMMBuildArgs(buildArgs),
+						Volumes:    buildVolumesFromBuildSecrets(kmmBuild.Secrets),
+						PullSecret: mld.ImageRepoSecret,
+					},
+				},
+				Output:         buildTarget,
+				NodeSelector:   selector,
+				MountTrustedCA: ptr.To(true),
+			},
+		},
+	}
+
+	if err := controllerutil.SetControllerReference(owner, &bc, omi.scheme); err != nil {
+		return nil, fmt.Errorf("could not set the owner reference: %v", err)
+	}
+
+	return &bc, nil
+}
+
+func (omi *ocpbuildManagerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
+	dockerfileCM := &corev1.ConfigMap{}
+	namespacedName := types.NamespacedName{Name: buildConfig.DockerfileConfigMap.Name, Namespace: namespace}
+	err := omi.client.Get(ctx, namespacedName, dockerfileCM)
+	if err != nil {
+		return "", fmt.Errorf("failed to get dockerfile ConfigMap %s: %v", namespacedName, err)
+	}
+	data, ok := dockerfileCM.Data[constants.DockerfileCMKey]
+	if !ok {
+		return "", fmt.Errorf("invalid Dockerfile ConfigMap %s format, %s key is missing", namespacedName, constants.DockerfileCMKey)
+	}
+	return data, nil
+}
diff --git a/internal/buildsign/ocpbuild/ocpbuildmanager_test.go b/internal/buildsign/ocpbuild/ocpbuildmanager_test.go
index 1e36d341e..bf14bd3fe 100644
--- a/internal/buildsign/ocpbuild/ocpbuildmanager_test.go
+++ b/internal/buildsign/ocpbuild/ocpbuildmanager_test.go
@@ -3,15 +3,24 @@ package ocpbuild
 import (
 	"context"
 	"errors"
+	"fmt"
 
+	"github.com/google/go-cmp/cmp"
+	"github.com/mitchellh/hashstructure/v2"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	buildv1 "github.com/openshift/api/build/v1"
 	kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/api"
 	"github.com/rh-ecosystem-edge/kernel-module-management/internal/client"
 	"github.com/rh-ecosystem-edge/kernel-module-management/internal/constants"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/module"
+	"github.com/rh-ecosystem-edge/kernel-module-management/internal/syncronizedmap"
 	"go.uber.org/mock/gomock"
+	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/utils/ptr"
 	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 )
@@ -20,14 +29,18 @@ var _ = Describe("getModuleOCPBuildByKernel", func() {
 	const targetKernel = "target-kernels"
 
 	var (
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl := gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockCombiner = module.NewMockCombiner(ctrl)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 
 	})
 
@@ -100,14 +113,17 @@ var _ = Describe("getModuleOCPBuilds", func() {
 	)
 
 	var (
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl := gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 
 	})
 
@@ -171,15 +187,18 @@ var _ = Describe("getModuleOCPBuilds", func() {
 var _ = Describe("deleteOCPBuild", func() {
 
 	var (
-		ctrl           *gomock.Controller
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		ctrl                   *gomock.Controller
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 	})
 
 	ctx := context.Background()
@@ -212,15 +231,18 @@ var _ = Describe("deleteOCPBuild", func() {
 
 var _ = Describe("createOCPBuild", func() {
 	var (
-		ctrl           *gomock.Controller
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		ctrl                   *gomock.Controller
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 	})
 
 	It("good flow", func() {
@@ -249,15 +271,18 @@ var _ = Describe("createOCPBuild", func() {
 
 var _ = Describe("getOCPBuildStatus", func() {
 	var (
-		ctrl           *gomock.Controller
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		ctrl                   *gomock.Controller
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 	})
 
 	DescribeTable("should return the correct status depending on the build status",
@@ -283,15 +308,18 @@ var _ = Describe("getOCPBuildStatus", func() {
 
 var _ = Describe("isOCPBuildChanged", func() {
 	var (
-		ctrl           *gomock.Controller
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		ctrl                   *gomock.Controller
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 	})
 
 	DescribeTable("should detect if a build has changed",
@@ -324,15 +352,19 @@ var _ = Describe("isOCPBuildChanged", func() {
 
 var _ = Describe("ocpbuildLabels", func() {
 	var (
-		ctrl           *gomock.Controller
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		ctrl                   *gomock.Controller
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl = gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockCombiner = module.NewMockCombiner(ctrl)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 	})
 
 	It("get build labels", func() {
@@ -353,3 +385,276 @@ var _ = Describe("ocpbuildLabels", func() {
 		Expect(labels).To(Equal(expected))
 	})
 })
+
+var _ = Describe("makeOCPBuildTemplate", func() {
+	const (
+		containerImage = "container-image"
+		dockerFile     = "FROM some-image"
+		moduleName     = "some-name"
+		namespace      = "some-namespace"
+		targetKernel   = "target-kernel"
+	)
+
+	var (
+		ctrl                   *gomock.Controller
+		clnt                   *client.MockClient
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
+		ctx                    context.Context
+		obm                    ocpbuildManager
+	)
+
+	BeforeEach(func() {
+		ctrl = gomock.NewController(GinkgoT())
+		clnt = client.NewMockClient(ctrl)
+		mockCombiner = module.NewMockCombiner(ctrl)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		ctx = context.Background()
+		obm = newOCPBuildManager(clnt, mockCombiner, mockKernelOSDTKMapping, scheme)
+	})
+
+	AfterEach(func() {
+		ctrl.Finish()
+	})
+
+	dockerfileConfigMap := v1.LocalObjectReference{Name: "configMapName"}
+	dockerfileCMData := map[string]string{constants.DockerfileCMKey: dockerFile}
+
+	DescribeTable("should set fields correctly", func(
+		buildSecrets []v1.LocalObjectReference,
+		imagePullSecret *v1.LocalObjectReference,
+		useBuildSelector bool) {
+		nodeSelector := map[string]string{"label-key": "label-value"}
+
+		buildArgs := []kmmv1beta1.BuildArg{
+			{
+				Name:  "arg-1",
+				Value: "value-1",
+			},
+			{
+				Name:  "arg-2",
+				Value: "value-2",
+			},
+		}
+
+		irs := v1.LocalObjectReference{Name: "push-secret"}
+
+		mld := api.ModuleLoaderData{
+			Name:           moduleName,
+			Namespace:      namespace,
+			ContainerImage: containerImage,
+			Build: &kmmv1beta1.Build{
+				BuildArgs:           buildArgs,
+				DockerfileConfigMap: &dockerfileConfigMap,
+				Secrets:             buildSecrets,
+			},
+			ImageRepoSecret:         &irs,
+			Selector:                nodeSelector,
+			KernelVersion:           targetKernel,
+			KernelNormalizedVersion: targetKernel,
+			Owner: &kmmv1beta1.Module{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      moduleName,
+					Namespace: namespace,
+				},
+			},
+		}
+
+		if useBuildSelector {
+			mld.Selector = nil
+			mld.Build.Selector = nodeSelector
+		}
+
+		overrides := []kmmv1beta1.BuildArg{
+			{Name: "KERNEL_VERSION", Value: targetKernel},
+			{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
+			{Name: "MOD_NAME", Value: moduleName},
+			{Name: "MOD_NAMESPACE", Value: namespace},
+		}
+
+		expected := buildv1.Build{
+			ObjectMeta: metav1.ObjectMeta{
+				GenerateName: moduleName + "-build-",
+				Namespace:    namespace,
+				OwnerReferences: []metav1.OwnerReference{
+					{
+						APIVersion:         "kmm.sigs.x-k8s.io/v1beta1",
+						Kind:               "Module",
+						Name:               moduleName,
+						Controller:         ptr.To(true),
+						BlockOwnerDeletion: ptr.To(true),
+					},
+				},
+				Finalizers: []string{constants.GCDelayFinalizer, constants.JobEventFinalizer},
+				Labels:     obm.ocpbuildLabels(mld.Name, mld.KernelNormalizedVersion, ocpbuildTypeBuild),
+			},
+			Spec: buildv1.BuildSpec{
+				CommonSpec: buildv1.CommonSpec{
+					ServiceAccount: "builder",
+					Source: buildv1.BuildSource{
+						Dockerfile: ptr.To(dockerFile),
+						Type:       buildv1.BuildSourceDockerfile,
+					},
+					Strategy: buildv1.BuildStrategy{
+						Type: buildv1.DockerBuildStrategyType,
+						DockerStrategy: &buildv1.DockerBuildStrategy{
+							BuildArgs: append(
+								envVarsFromKMMBuildArgs(buildArgs),
+								v1.EnvVar{Name: "KERNEL_VERSION", Value: targetKernel},
+								v1.EnvVar{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
+								v1.EnvVar{Name: "MOD_NAME", Value: moduleName},
+								v1.EnvVar{Name: "MOD_NAMESPACE", Value: namespace},
+							),
+							Volumes:    buildVolumesFromBuildSecrets(buildSecrets),
+							PullSecret: &irs,
+						},
+					},
+					Output: buildv1.BuildOutput{
+						To: &v1.ObjectReference{
+							Kind: "DockerImage",
+							Name: containerImage,
+						},
+						PushSecret: &irs,
+					},
+					NodeSelector:   nodeSelector,
+					MountTrustedCA: ptr.To(true),
+				},
+			},
+		}
+
+		if imagePullSecret != nil {
+			mld.ImageRepoSecret = imagePullSecret
+			expected.Spec.CommonSpec.Output.PushSecret = imagePullSecret
+			expected.Spec.Strategy.DockerStrategy.PullSecret = imagePullSecret
+		}
+
+		if len(buildSecrets) > 0 {
+
+			mld.Build.Secrets = buildSecrets
+
+			expected.Spec.CommonSpec.Strategy.DockerStrategy.Volumes = buildVolumesFromBuildSecrets(buildSecrets)
+		}
+
+		hash, err := hashstructure.Hash(expected.Spec.CommonSpec.Source, hashstructure.FormatV2, nil)
+		Expect(err).NotTo(HaveOccurred())
+
+		annotations := map[string]string{hashAnnotation: fmt.Sprintf("%d", hash)}
+		expected.SetAnnotations(annotations)
+
+		gomock.InOrder(
+			clnt.EXPECT().Get(ctx, types.NamespacedName{Name: dockerfileConfigMap.Name, Namespace: mld.Namespace}, gomock.Any()).DoAndReturn(
+				func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
+					cm.Data = dockerfileCMData
+					return nil
+				},
+			),
+			mockCombiner.EXPECT().ApplyBuildArgOverrides(buildArgs, overrides).Return(
+				append(buildArgs,
+					kmmv1beta1.BuildArg{Name: "KERNEL_VERSION", Value: targetKernel},
+					kmmv1beta1.BuildArg{Name: "KERNEL_FULL_VERSION", Value: targetKernel},
+					kmmv1beta1.BuildArg{Name: "MOD_NAME", Value: moduleName},
+					kmmv1beta1.BuildArg{Name: "MOD_NAMESPACE", Value: namespace}),
+			),
+		)
+
+		bc, err := obm.makeOCPBuildTemplate(ctx, &mld, true, mld.Owner)
+		Expect(err).NotTo(HaveOccurred())
+
+		Expect(
+			cmp.Diff(&expected, bc),
+		).To(
+			BeEmpty(),
+		)
+	},
+		Entry(
+			"no secrets at all",
+			[]v1.LocalObjectReference{},
+			nil,
+			false,
+		),
+		Entry(
+			"no secrets at all with build.Selector property",
+			[]v1.LocalObjectReference{},
+			nil,
+			true,
+		),
+		Entry(
+			"only buildSecrets",
+			[]v1.LocalObjectReference{{Name: "s1"}},
+			nil,
+			false,
+		),
+		Entry(
+			"only imagePullSecrets",
+			[]v1.LocalObjectReference{},
+			&v1.LocalObjectReference{Name: "pull-push-secret"},
+			false,
+		),
+		Entry(
+			"buildSecrets and imagePullSecrets",
+			[]v1.LocalObjectReference{{Name: "s1"}},
+			&v1.LocalObjectReference{Name: "pull-push-secret"},
+			false,
+		),
+	)
+
+	Context(fmt.Sprintf("using %s", dtkBuildArg), func() {
+		It("should fail if we couldn't get the DTK image", func() {
+
+			gomock.InOrder(
+				clnt.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(
+					func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
+						dockerfileData := fmt.Sprintf("FROM %s", dtkBuildArg)
+						cm.Data = map[string]string{constants.DockerfileCMKey: dockerfileData}
+						return nil
+					},
+				),
+				mockKernelOSDTKMapping.EXPECT().GetImage(gomock.Any()).Return("", errors.New("random error")),
+			)
+
+			mld := api.ModuleLoaderData{
+				Build: &kmmv1beta1.Build{
+					DockerfileConfigMap: &dockerfileConfigMap,
+				},
+			}
+			_, err := obm.makeOCPBuildTemplate(ctx, &mld, false, mld.Owner)
+			Expect(err).To(HaveOccurred())
+		})
+
+		It(fmt.Sprintf("should add a build arg if %s is used in the Dockerfile", dtkBuildArg), func() {
+
+			const dtkImage = "quay.io/openshift-release-dev/ocp-v4.0-art-dev@sha256:111"
+
+			buildArgs := []kmmv1beta1.BuildArg{
+				{
+					Name:  dtkBuildArg,
+					Value: dtkImage,
+				},
+			}
+
+			gomock.InOrder(
+				clnt.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(
+					func(_ interface{}, _ interface{}, cm *v1.ConfigMap, _ ...ctrlclient.GetOption) error {
+						dockerfileData := fmt.Sprintf("FROM %s", dtkBuildArg)
+						cm.Data = map[string]string{constants.DockerfileCMKey: dockerfileData}
+						return nil
+					},
+				),
+				mockKernelOSDTKMapping.EXPECT().GetImage(gomock.Any()).Return(dtkImage, nil),
+				mockCombiner.EXPECT().ApplyBuildArgOverrides(gomock.Any(), gomock.Any()).Return(buildArgs),
+			)
+
+			mld := api.ModuleLoaderData{
+				Build: &kmmv1beta1.Build{
+					DockerfileConfigMap: &dockerfileConfigMap,
+				},
+				Owner: &kmmv1beta1.Module{},
+			}
+			bct, err := obm.makeOCPBuildTemplate(ctx, &mld, false, mld.Owner)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(len(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs)).To(Equal(1))
+			Expect(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs[0].Name).To(Equal(buildArgs[0].Name))
+			Expect(bct.Spec.CommonSpec.Strategy.DockerStrategy.BuildArgs[0].Value).To(Equal(buildArgs[0].Value))
+		})
+	})
+})


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>internal/buildsign/ocpbuild/ocpbuildmanager.go (1)</summary><blockquote>

`266-269`: **Minor typo in error message**

`Buildsource` → `BuildSource` for clarity.

```diff
-    return nil, fmt.Errorf("could not hash Build's Buildsource template: %v", err)
+    return nil, fmt.Errorf("could not hash Build's BuildSource template: %v", err)
```

</blockquote></details>
<details>
<summary>internal/buildsign/ocpbuild/ocpbuildmanager_test.go (1)</summary><blockquote>

`538-543`: **Hash comparison in tests may falsely succeed due to pointer dereferencing rules**

`hashstructure` dereferences pointers, so using two different `*string` values with the same underlying string is fine.  
However, if the library behaviour changes, these tests could start failing unexpectedly. Consider hashing a plain struct (or the dereferenced string) to make the expectation independent of pointer semantics.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between fe18132234a0125013ad972f190534478a0a7641 and 70dc75fcfe34c11a8381b18a5e7c52078a194832.

</details>

<details>
<summary>📒 Files selected for processing (19)</summary>

* `bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml` (1 hunks)
* `bundle/manifests/kernel-module-management.clusterserviceversion.yaml` (1 hunks)
* `cmd/manager-hub/main.go` (4 hunks)
* `cmd/manager/main.go` (3 hunks)
* `internal/buildsign/mock_helper.go` (0 hunks)
* `internal/buildsign/ocpbuild/common.go` (1 hunks)
* `internal/buildsign/ocpbuild/maker.go` (0 hunks)
* `internal/buildsign/ocpbuild/maker_test.go` (0 hunks)
* `internal/buildsign/ocpbuild/manager.go` (2 hunks)
* `internal/buildsign/ocpbuild/manager_test.go` (6 hunks)
* `internal/buildsign/ocpbuild/mock_maker.go` (0 hunks)
* `internal/buildsign/ocpbuild/mock_ocbuildmanager.go` (2 hunks)
* `internal/buildsign/ocpbuild/ocpbuildmanager.go` (3 hunks)
* `internal/buildsign/ocpbuild/ocpbuildmanager_test.go` (9 hunks)
* `internal/module/combiner.go` (4 hunks)
* `internal/module/combiner_test.go` (7 hunks)
* `internal/module/kernelmapper.go` (3 hunks)
* `internal/module/kernelmapper_test.go` (2 hunks)
* `internal/module/mock_combiner.go` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (4)</summary>

* internal/buildsign/mock_helper.go
* internal/buildsign/ocpbuild/mock_maker.go
* internal/buildsign/ocpbuild/maker_test.go
* internal/buildsign/ocpbuild/maker.go

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (8)</summary>

<details>
<summary>internal/module/combiner_test.go (2)</summary><blockquote>

<details>
<summary>internal/module/combiner.go (2)</summary>

* `Combiner` (13-17)
* `NewCombiner` (21-23)

</details>
<details>
<summary>vendor/github.com/onsi/ginkgo/v2/core_dsl.go (3)</summary>

* `BeforeEach` (706-708)
* `It` (553-555)
* `Describe` (494-496)

</details>

</blockquote></details>
<details>
<summary>cmd/manager-hub/main.go (3)</summary><blockquote>

<details>
<summary>internal/module/combiner.go (1)</summary>

* `NewCombiner` (21-23)

</details>
<details>
<summary>internal/build/ocpbuild/maker.go (1)</summary>

* `NewMaker` (51-58)

</details>
<details>
<summary>internal/module/kernelmapper.go (1)</summary>

* `NewKernelMapper` (26-30)

</details>

</blockquote></details>
<details>
<summary>cmd/manager/main.go (3)</summary><blockquote>

<details>
<summary>internal/module/combiner.go (1)</summary>

* `NewCombiner` (21-23)

</details>
<details>
<summary>internal/module/kernelmapper.go (1)</summary>

* `NewKernelMapper` (26-30)

</details>
<details>
<summary>internal/buildsign/ocpbuild/manager.go (1)</summary>

* `NewManager` (29-41)

</details>

</blockquote></details>
<details>
<summary>internal/module/combiner.go (1)</summary><blockquote>

<details>
<summary>api/v1beta1/module_types.go (2)</summary>

* `BuildArg` (25-28)
* `Sign` (74-92)

</details>

</blockquote></details>
<details>
<summary>internal/buildsign/ocpbuild/common.go (1)</summary><blockquote>

<details>
<summary>api/v1beta1/module_types.go (1)</summary>

* `BuildArg` (25-28)

</details>

</blockquote></details>
<details>
<summary>internal/module/kernelmapper.go (2)</summary><blockquote>

<details>
<summary>internal/module/combiner.go (1)</summary>

* `Combiner` (13-17)

</details>
<details>
<summary>api/v1beta1/module_types.go (2)</summary>

* `Build` (47-72)
* `Sign` (74-92)

</details>

</blockquote></details>
<details>
<summary>internal/buildsign/ocpbuild/manager.go (2)</summary><blockquote>

<details>
<summary>internal/module/combiner.go (1)</summary>

* `Combiner` (13-17)

</details>
<details>
<summary>internal/buildsign/manager.go (1)</summary>

* `Manager` (14-19)

</details>

</blockquote></details>
<details>
<summary>internal/module/mock_combiner.go (2)</summary><blockquote>

<details>
<summary>api/v1beta1/module_types.go (2)</summary>

* `BuildArg` (25-28)
* `Sign` (74-92)

</details>
<details>
<summary>vendor/go.uber.org/mock/gomock/call.go (1)</summary>

* `Call` (25-45)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Analyze (go)

</details>

<details>
<summary>🔇 Additional comments (32)</summary><blockquote>

<details>
<summary>bundle/manifests/kernel-module-management.clusterserviceversion.yaml (1)</summary>

`66-66`: **Update to metadata timestamp.**

This is a routine update to the `createdAt` timestamp in the ClusterServiceVersion manifest, reflecting the latest build time.

</details>
<details>
<summary>bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml (1)</summary>

`40-40`: **Update to metadata timestamp.**

This timestamp update is consistent with the change in the corresponding non-hub ClusterServiceVersion manifest, ensuring both manifests have synchronized metadata.

</details>
<details>
<summary>cmd/manager-hub/main.go (3)</summary>

`123-123`: **Interface refactoring - renamed and moved from `buildsign` to `module` package.**

The interface has been renamed from `Helper` to `Combiner` and moved to the `module` package, which makes sense given its functionality that spans both build/sign sections and kernel-mapping sections.

---

`135-135`: **Updated parameter to use the new `Combiner` interface.**

The method call has been updated to use the new `buildSignCombiner` variable instead of the previous `buildSignHelperAPI`, maintaining functional equivalence while using the new interface.

---

`149-149`: **Updated parameter to `module.NewKernelMapper`.**

The parameter passed to `module.NewKernelMapper` has been updated to use the new `buildSignCombiner` variable, maintaining the same functionality with the refactored interface.

</details>
<details>
<summary>cmd/manager/main.go (3)</summary>

`131-131`: **Refactored to use the new `module.Combiner` interface.**

Replaced `buildsign.NewHelper()` with `module.NewCombiner()`, aligning with the PR's goal of moving the interface to the `module` package where it better fits conceptually.

---

`141-141`: **Updated the `NewKernelMapper` call to use the refactored interface.**

The parameter has been changed from `buildSignHelperAPI` to `buildSignCombinerAPI`, maintaining the same functionality while using the new interface name.

---

`219-219`: **Updated the `buildsignocpbuild.NewManager` call with the new interface.**

The `buildSignCombinerAPI` is now passed to the manager constructor instead of the previous helper interface, ensuring consistent use of the refactored interface throughout the codebase.

</details>
<details>
<summary>internal/module/combiner_test.go (1)</summary>

`1-1`: **Interface rename migration successfully completed.**

All references to `Helper` have been consistently renamed to `Combiner`, with variable names updated from `h` to `c`. The method calls remain the same but are now invoked on the `Combiner` instance rather than the `Helper` instance. The test logic remains intact, showing good refactoring discipline.



Also applies to: 15-15, 18-18, 26-26, 35-35, 52-52, 60-60, 63-63, 103-103, 119-119, 123-123, 134-134

</details>
<details>
<summary>internal/module/kernelmapper_test.go (1)</summary>

`154-160`: **Successfully migrated from MockHelper to MockCombiner.**

The dependency on `buildsign.MockHelper` has been properly replaced with the new `module.MockCombiner`. All related variable declarations and test expectations have been updated consistently, while preserving the test behavior and assertions.



Also applies to: 162-166, 226-233

</details>
<details>
<summary>internal/buildsign/ocpbuild/manager_test.go (1)</summary>

`137-137`: **Successfully migrated method calls to ocpbuildManager.**

All calls to `mockMaker.makeBuildTemplate` have been correctly replaced with `mockOCPBuildManager.makeOCPBuildTemplate`. This change aligns with the PR objective of moving functionality from the `buildsign.Helper` interface into the `module` package.



Also applies to: 149-149, 160-160, 173-173, 186-186, 207-207

</details>
<details>
<summary>internal/buildsign/ocpbuild/mock_ocbuildmanager.go (1)</summary>

`16-16`: **Successfully added makeOCPBuildTemplate method to mockOCPBuildManager.**

The new method `makeOCPBuildTemplate` has been properly added to the mock with appropriate parameter and return types. The API package has been correctly imported to support the moduleLoaderData parameter type.



Also applies to: 132-145

</details>
<details>
<summary>internal/module/combiner.go (7)</summary>

`1-1`: **Package name change aligns with the PR goal.**

The package name change from `buildsign` to `module` correctly implements the goal stated in the PR objectives: moving the `buildsign.Helper` interface into the `module` package.

---

`11-11`: **Updated mockgen directive for the renamed interface.**

The `go:generate` directive has been appropriately updated to reflect the new source file name, package, and destination mock file.

---

`13-17`: **Interface renamed from `Helper` to `Combiner`.**

The interface rename better reflects its purpose of combining functionality from both global and kernel-mapping build/sign sections. Method signatures remain unchanged, preserving compatibility while improving naming.

---

`19-23`: **Implementation struct and constructor renamed to match interface.**

The implementation struct and constructor function have been renamed from `helper` to `combiner` and from `NewHelper()` to `NewCombiner()` respectively, maintaining consistency with the interface name.

---

`25-48`: **Updated receiver name in `ApplyBuildArgOverrides` method.**

The method implementation remains unchanged except for the receiver name change from `(m *helper)` to `(c *combiner)`, which maintains consistency with the renamed struct.

---

`50-68`: **Updated receiver name in `GetRelevantBuild` method.**

The method implementation remains unchanged except for the receiver name change, preserving the existing logic while ensuring naming consistency.

---

`70-109`: **Updated receiver name in `GetRelevantSign` method.**

The method implementation logic is preserved with only the receiver name updated, ensuring the interface relocation doesn't impact existing functionality.

</details>
<details>
<summary>internal/buildsign/ocpbuild/manager.go (4)</summary>

`18-18`: **Added import for the new module package.**

Import for the `module` package is added to reference the new `Combiner` interface, replacing the previous dependency on the buildsign.Helper interface.

---

`30-31`: **Updated constructor parameter from helper to combiner.**

The `NewManager` function now accepts a `module.Combiner` instead of the previous `buildsign.Helper`, aligning with the interface relocation and renaming in the PR.

---

`34-34`: **Updated ocpbuildManager initialization to use the new combiner interface.**

The `ocpbuildManager` is now initialized with the combiner parameter instead of a maker parameter, reflecting the architectural change where ocpbuildManager directly uses the combiner interface.

---

`84-84`: **Build template creation now uses ocpbuildManager directly.**

The call to create the OpenShift build template has been changed from using the removed `maker` abstraction to directly calling `makeOCPBuildTemplate` on the `ocpbuildManager`. This simplifies the architecture by removing an unnecessary abstraction layer.

</details>
<details>
<summary>internal/module/kernelmapper.go (5)</summary>

`26-29`: **Updated KernelMapper constructor to use the new Combiner interface.**

The `NewKernelMapper` constructor now accepts a `Combiner` instead of a `buildsign.Helper`, properly integrating with the renamed and relocated interface.

---

`56-58`: **Updated kernelMapperHelper struct to use the new Combiner interface.**

The `kernelMapperHelper` struct field type has been changed from `buildsign.Helper` to `Combiner`, maintaining consistency with the interface relocation.

---

`60-64`: **Updated helper constructor to use the new field type and name.**

The constructor for `kernelMapperHelper` has been updated to accept and store a `Combiner` parameter instead of a `buildsign.Helper`, ensuring proper initialization.

---

`92-92`: **Updated method call to use the new field name.**

The call to `GetRelevantBuild` now uses the new field name `buildSignCombiner` instead of the previous `buildSignHelper`, maintaining correct functionality.

---

`97-97`: **Updated method call to use the new field name for sign configuration.**

The call to `GetRelevantSign` now uses the new field name `buildSignCombiner`, preserving the existing behavior with the renamed interface.

</details>
<details>
<summary>internal/buildsign/ocpbuild/common.go (3)</summary>

`10-11`: **Defined constant for DTK build argument.**

This constant defines the build argument name used for DTK (Developer Toolkit) auto-injection in OpenShift builds.

---

`12-24`: **Utility function to convert build arguments to environment variables.**

This function cleanly converts KMM build arguments into Kubernetes environment variables for use in OpenShift builds. The implementation correctly handles nil input by returning nil.

---

`26-52`: **Utility function to convert secret references to build volumes.**

This function effectively maps Kubernetes secret references to OpenShift build volumes with appropriate mounts. It uses a consistent naming pattern for volumes and mount paths, and handles nil input gracefully.

</details>
<details>
<summary>internal/module/mock_combiner.go (1)</summary>

`1-88`: **Generated file — no manual issues**

`mock_combiner.go` is auto-generated by `mockgen`; manual changes are neither required nor recommended.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-08T13:03:25Z

Review comments:
diff_hunk: @@ -176,3 +196,127 @@ func moduleLabels(modName, ocpbuildType string) map[string]string {
 		constants.BuildTypeLabel:  ocpbuildType,
 	}
 }
+func (omi *ocpbuildManagerImpl) makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool,
+	owner metav1.Object) (*buildv1.Build, error) {
+
+	kmmBuild := mld.Build
+	containerImage := mld.ContainerImage
+	kernelVersion := mld.KernelVersion
+
+	// if build AND sign are specified, then we will build an intermediate image
+	// and let sign produce the final image specified in spec.moduleLoader.container.km.containerImage
+	if module.ShouldBeSigned(mld) {
+		containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
+	}
+
+	overrides := []kmmv1beta1.BuildArg{
+		{
+			Name:  "KERNEL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "KERNEL_FULL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "MOD_NAME",
+			Value: mld.Name,
+		},
+		{
+			Name:  "MOD_NAMESPACE",
+			Value: mld.Namespace,
+		},
+	}
+
+	dockerfileData, err := omi.getDockerfileData(ctx, kmmBuild, mld.Namespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get dockerfile data from configmap: %v", err)
+	}
+
+	if strings.Contains(dockerfileData, dtkBuildArg) {
+
+		dtkImage, err := omi.kernelOsDtkMapping.GetImage(kernelVersion)
+		if err != nil {
+			return nil, fmt.Errorf("could not get DTK image for kernel %v: %v", kernelVersion, err)
+		}
+		overrides = append(overrides, kmmv1beta1.BuildArg{Name: dtkBuildArg, Value: dtkImage})
+	}
+
+	buildArgs := omi.combiner.ApplyBuildArgOverrides(
+		kmmBuild.BuildArgs,
+		overrides...,
+	)
+
+	buildTarget := buildv1.BuildOutput{
+		To: &v1.ObjectReference{
+			Kind: "DockerImage",
+			Name: containerImage,
+		},
+		PushSecret: mld.ImageRepoSecret,
+	}
+	if !pushImage {
+		buildTarget = buildv1.BuildOutput{}
+	}
+
+	sourceConfig := buildv1.BuildSource{
+		Dockerfile: &dockerfileData,
+		Type:       buildv1.BuildSourceDockerfile,
+	}
+
+	sourceConfigHash, err := hashstructure.Hash(sourceConfig, hashstructure.FormatV2, nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not hash Build's Buildsource template: %v", err)
+	}
+
+	selector := mld.Selector
+	if len(mld.Build.Selector) != 0 {
+		selector = mld.Build.Selector
+	}
+
+	bc := buildv1.Build{
path: internal/buildsign/ocpbuild/ocpbuildmanager.go
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Nil-pointer risk when `mld.Build` is absent**

`mld.Build.Selector` is accessed without checking that `mld.Build` itself is non-nil.  
While current callers always supply a `Build`, the public signature does not guarantee this and a future call could trigger a panic.

```diff
-selector := mld.Selector
-if len(mld.Build.Selector) != 0 {
-    selector = mld.Build.Selector
-}
+selector := mld.Selector
+if mld.Build != nil && len(mld.Build.Selector) != 0 {
+    selector = mld.Build.Selector
+}
```

Consider returning an explicit error when `mld.Build == nil` – the template cannot be rendered without build settings anyway.  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
	selector := mld.Selector
	if mld.Build != nil && len(mld.Build.Selector) != 0 {
		selector = mld.Build.Selector
	}

	bc := buildv1.Build{
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T13:03:23Z
author_association: NONE
diff_hunk: @@ -176,3 +196,127 @@
 		constants.BuildTypeLabel:  ocpbuildType,
 	}
 }
+func (omi *ocpbuildManagerImpl) makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool,
+	owner metav1.Object) (*buildv1.Build, error) {
+
+	kmmBuild := mld.Build
+	containerImage := mld.ContainerImage
+	kernelVersion := mld.KernelVersion
+
+	// if build AND sign are specified, then we will build an intermediate image
+	// and let sign produce the final image specified in spec.moduleLoader.container.km.containerImage
+	if module.ShouldBeSigned(mld) {
+		containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
+	}
+
+	overrides := []kmmv1beta1.BuildArg{
+		{
+			Name:  "KERNEL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "KERNEL_FULL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "MOD_NAME",
+			Value: mld.Name,
+		},
+		{
+			Name:  "MOD_NAMESPACE",
+			Value: mld.Namespace,
+		},
+	}
+
+	dockerfileData, err := omi.getDockerfileData(ctx, kmmBuild, mld.Namespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get dockerfile data from configmap: %v", err)
+	}
+
+	if strings.Contains(dockerfileData, dtkBuildArg) {
+
+		dtkImage, err := omi.kernelOsDtkMapping.GetImage(kernelVersion)
+		if err != nil {
+			return nil, fmt.Errorf("could not get DTK image for kernel %v: %v", kernelVersion, err)
+		}
+		overrides = append(overrides, kmmv1beta1.BuildArg{Name: dtkBuildArg, Value: dtkImage})
+	}
+
+	buildArgs := omi.combiner.ApplyBuildArgOverrides(
+		kmmBuild.BuildArgs,
+		overrides...,
+	)
+
path: internal/buildsign/ocpbuild/ocpbuildmanager.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

_⚠️ Potential issue_

**`combiner` can be `nil` → potential runtime panic**

`omi.combiner.ApplyBuildArgOverrides` is dereferenced unconditionally.  
Several unit-tests (e.g. `getModuleOCPBuilds` / `deleteOCPBuild`) construct the manager with `nil` for the `combiner` argument because those specific paths do not use it.  
If production code ever follows the `makeOCPBuildTemplate` path with a `nil` combiner, the controller will crash.

```diff
+if omi.combiner == nil {
+    return nil, fmt.Errorf("combiner dependency is nil – cannot apply build-arg overrides")
+}
 buildArgs := omi.combiner.ApplyBuildArgOverrides(
     kmmBuild.BuildArgs,
     overrides...,
 )
```

Alternatively guard in the constructor and fail fast.  
 


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    // guard against nil combiner to avoid a runtime panic
    if omi.combiner == nil {
        return nil, fmt.Errorf("combiner dependency is nil – cannot apply build-arg overrides")
    }
    buildArgs := omi.combiner.ApplyBuildArgOverrides(
        kmmBuild.BuildArgs,
        overrides...,
    )
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T13:03:24Z
author_association: NONE
diff_hunk: @@ -176,3 +196,127 @@
 		constants.BuildTypeLabel:  ocpbuildType,
 	}
 }
+func (omi *ocpbuildManagerImpl) makeOCPBuildTemplate(ctx context.Context, mld *api.ModuleLoaderData, pushImage bool,
+	owner metav1.Object) (*buildv1.Build, error) {
+
+	kmmBuild := mld.Build
+	containerImage := mld.ContainerImage
+	kernelVersion := mld.KernelVersion
+
+	// if build AND sign are specified, then we will build an intermediate image
+	// and let sign produce the final image specified in spec.moduleLoader.container.km.containerImage
+	if module.ShouldBeSigned(mld) {
+		containerImage = module.IntermediateImageName(mld.Name, mld.Namespace, containerImage)
+	}
+
+	overrides := []kmmv1beta1.BuildArg{
+		{
+			Name:  "KERNEL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "KERNEL_FULL_VERSION",
+			Value: kernelVersion,
+		},
+		{
+			Name:  "MOD_NAME",
+			Value: mld.Name,
+		},
+		{
+			Name:  "MOD_NAMESPACE",
+			Value: mld.Namespace,
+		},
+	}
+
+	dockerfileData, err := omi.getDockerfileData(ctx, kmmBuild, mld.Namespace)
+	if err != nil {
+		return nil, fmt.Errorf("failed to get dockerfile data from configmap: %v", err)
+	}
+
+	if strings.Contains(dockerfileData, dtkBuildArg) {
+
+		dtkImage, err := omi.kernelOsDtkMapping.GetImage(kernelVersion)
+		if err != nil {
+			return nil, fmt.Errorf("could not get DTK image for kernel %v: %v", kernelVersion, err)
+		}
+		overrides = append(overrides, kmmv1beta1.BuildArg{Name: dtkBuildArg, Value: dtkImage})
+	}
+
+	buildArgs := omi.combiner.ApplyBuildArgOverrides(
+		kmmBuild.BuildArgs,
+		overrides...,
+	)
+
+	buildTarget := buildv1.BuildOutput{
+		To: &v1.ObjectReference{
+			Kind: "DockerImage",
+			Name: containerImage,
+		},
+		PushSecret: mld.ImageRepoSecret,
+	}
+	if !pushImage {
+		buildTarget = buildv1.BuildOutput{}
+	}
+
+	sourceConfig := buildv1.BuildSource{
+		Dockerfile: &dockerfileData,
+		Type:       buildv1.BuildSourceDockerfile,
+	}
+
+	sourceConfigHash, err := hashstructure.Hash(sourceConfig, hashstructure.FormatV2, nil)
+	if err != nil {
+		return nil, fmt.Errorf("could not hash Build's Buildsource template: %v", err)
+	}
+
+	selector := mld.Selector
+	if len(mld.Build.Selector) != 0 {
+		selector = mld.Build.Selector
+	}
+
+	bc := buildv1.Build{
+		ObjectMeta: metav1.ObjectMeta{
+			GenerateName: mld.Name + "-build-",
+			Namespace:    mld.Namespace,
+			Labels:       omi.ocpbuildLabels(mld.Name, mld.KernelNormalizedVersion, ocpbuildTypeBuild),
+			Annotations:  omi.ocpbuildAnnotations(sourceConfigHash),
+			Finalizers:   []string{constants.GCDelayFinalizer, constants.JobEventFinalizer},
+		},
+		Spec: buildv1.BuildSpec{
+			CommonSpec: buildv1.CommonSpec{
+				ServiceAccount: constants.OCPBuilderServiceAccountName,
+				Source:         sourceConfig,
+				Strategy: buildv1.BuildStrategy{
+					Type: buildv1.DockerBuildStrategyType,
+					DockerStrategy: &buildv1.DockerBuildStrategy{
+						BuildArgs:  envVarsFromKMMBuildArgs(buildArgs),
+						Volumes:    buildVolumesFromBuildSecrets(kmmBuild.Secrets),
+						PullSecret: mld.ImageRepoSecret,
+					},
+				},
+				Output:         buildTarget,
+				NodeSelector:   selector,
+				MountTrustedCA: ptr.To(true),
+			},
+		},
+	}
+
+	if err := controllerutil.SetControllerReference(owner, &bc, omi.scheme); err != nil {
+		return nil, fmt.Errorf("could not set the owner reference: %v", err)
+	}
+
+	return &bc, nil
+}
+
+func (omi *ocpbuildManagerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
+	dockerfileCM := &corev1.ConfigMap{}
+	namespacedName := types.NamespacedName{Name: buildConfig.DockerfileConfigMap.Name, Namespace: namespace}
+	err := omi.client.Get(ctx, namespacedName, dockerfileCM)
+	if err != nil {
+		return "", fmt.Errorf("failed to get dockerfile ConfigMap %s: %v", namespacedName, err)
+	}
+	data, ok := dockerfileCM.Data[constants.DockerfileCMKey]
+	if !ok {
+		return "", fmt.Errorf("invalid Dockerfile ConfigMap %s format, %s key is missing", namespacedName, constants.DockerfileCMKey)
path: internal/buildsign/ocpbuild/ocpbuildmanager.go
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`getDockerfileData` dereferences `buildConfig.DockerfileConfigMap` without a nil-check**

When `Build.DockerfileConfigMap` is not set the code panics while forming the `NamespacedName`.

```diff
-func (omi *ocpbuildManagerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
+func (omi *ocpbuildManagerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
+    if buildConfig == nil || buildConfig.DockerfileConfigMap == nil {
+        return "", fmt.Errorf("buildConfig or DockerfileConfigMap is nil")
+    }
```

This also makes the function contract explicit.  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
func (omi *ocpbuildManagerImpl) getDockerfileData(ctx context.Context, buildConfig *kmmv1beta1.Build, namespace string) (string, error) {
    if buildConfig == nil || buildConfig.DockerfileConfigMap == nil {
        return "", fmt.Errorf("buildConfig or DockerfileConfigMap is nil")
    }
    dockerfileCM := &corev1.ConfigMap{}
    namespacedName := types.NamespacedName{Name: buildConfig.DockerfileConfigMap.Name, Namespace: namespace}
    err := omi.client.Get(ctx, namespacedName, dockerfileCM)
    if err != nil {
        return "", fmt.Errorf("failed to get dockerfile ConfigMap %s: %v", namespacedName, err)
    }
    data, ok := dockerfileCM.Data[constants.DockerfileCMKey]
    if !ok {
        return "", fmt.Errorf("invalid Dockerfile ConfigMap %s format, %s key is missing", namespacedName, constants.DockerfileCMKey)
    }
    // ...rest of function...
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-08T13:03:24Z
author_association: NONE
diff_hunk: @@ -100,14 +113,17 @@ var _ = Describe("getModuleOCPBuilds", func() {
 	)
 
 	var (
-		mockKubeClient *client.MockClient
-		obm            ocpbuildManager
+		mockKubeClient         *client.MockClient
+		obm                    ocpbuildManager
+		mockCombiner           *module.MockCombiner
+		mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
 	)
 
 	BeforeEach(func() {
 		ctrl := gomock.NewController(GinkgoT())
 		mockKubeClient = client.NewMockClient(ctrl)
-		obm = newOCPBuildManager(mockKubeClient)
+		mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
+		obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
 
 	})
path: internal/buildsign/ocpbuild/ocpbuildmanager_test.go
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Tests initialise the manager with a `nil` combiner**

In several `BeforeEach` blocks (e.g. `getModuleOCPBuilds`, `deleteOCPBuild`) `mockCombiner` is never created, yet passed to `newOCPBuildManager`. This is safe today because those specific tests do not touch `makeOCPBuildTemplate`, but it silently violates the constructor’s contract and will start panicking once the tested path evolves.

Recommend instantiating a real mock (or a light stub) in all helpers to keep tests future-proof:

```go
mockCombiner = module.NewMockCombiner(ctrl)
obm = newOCPBuildManager(mockKubeClient, mockCombiner, mockKernelOSDTKMapping, scheme)
```

---

🏁 Script executed:

```shell
#!/bin/bash
set -e

echo "Searching for newOCPBuildManager signature..."
rg "func newOCPBuildManager" -A3

echo "Searching for module.NewMockCombiner definition..."
rg "NewMockCombiner" -n
```

Length of output: 1263

---

🏁 Script executed:

```shell
#!/bin/bash
set -e

echo "Inspecting BeforeEach around lines 95-140..."
sed -n '95,140p' internal/buildsign/ocpbuild/ocpbuildmanager_test.go
```

Length of output: 1548

---

🏁 Script executed:

```shell
#!/bin/bash
set -e

echo "Inspecting first 100 lines to find initial BeforeEach usage..."
sed -n '1,100p' internal/buildsign/ocpbuild/ocpbuildmanager_test.go
```

Length of output: 3693

---



</details>

**Initialize `mockCombiner` in all `BeforeEach` blocks**

The `Describe("getModuleOCPBuilds", ...)` (and similarly `deleteOCPBuild`) helper is passing a `nil` combiner into `newOCPBuildManager`, which currently works only because those tests don’t touch combiner logic. To prevent future panics once those code paths evolve, instantiate a real mock in every setup:

• File: `internal/buildsign/ocpbuild/ocpbuildmanager_test.go`  
  Describe("getModuleOCPBuilds", …) BeforeEach (around lines 115–128)  
• File: `internal/buildsign/ocpbuild/ocpbuildmanager_test.go`  
  Describe("deleteOCPBuild", …) BeforeEach (similar location)

Suggested diff:
```diff
 BeforeEach(func() {
     ctrl := gomock.NewController(GinkgoT())
     mockKubeClient = client.NewMockClient(ctrl)
+    mockCombiner = module.NewMockCombiner(ctrl)
     mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
     obm = newOCPBuildManager(
         mockKubeClient,
         mockCombiner,
         mockKernelOSDTKMapping,
         scheme,
     )
 })
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
var (
	mockKubeClient         *client.MockClient
	obm                    ocpbuildManager
	mockCombiner           *module.MockCombiner
	mockKernelOSDTKMapping *syncronizedmap.MockKernelOsDtkMapping
)

BeforeEach(func() {
	ctrl := gomock.NewController(GinkgoT())
	mockKubeClient = client.NewMockClient(ctrl)
	mockCombiner = module.NewMockCombiner(ctrl)
	mockKernelOSDTKMapping = syncronizedmap.NewMockKernelOsDtkMapping(ctrl)
	obm = newOCPBuildManager(
		mockKubeClient,
		mockCombiner,
		mockKernelOSDTKMapping,
		scheme,
	)
})
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits ed7ea15 to 1431033
created_at: 2025-05-08T13:03:24Z
author_association: NONE

PR comments:
user: login: netlify[bot]
created_at: 2025-05-08T12:57:08Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *openshift-kmm* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 1431033c99cfcec2d990126a5dfbe272bc75e0d8 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/openshift-kmm/deploys/681cb6af370b2b0008aec809 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-1488--openshift-kmm.netlify.app](https://deploy-preview-1488--openshift-kmm.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTE0ODgtLW9wZW5zaGlmdC1rbW0ubmV0bGlmeS5hcHAifQ.6D-6lkjJAkm66TPK7_q70JgVGeWYFIZ2TAsRGRixG8Y)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [openshift-kmm Preview](https://deploy-preview-1488--openshift-kmm.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/openshift-kmm/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-08T12:57:10Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This change removes the `maker` interface and its implementation from the `internal/buildsign/ocpbuild` package, consolidating the build template creation logic into a new `makeOCPBuildTemplate` method within the `ocpbuildManager` interface. Associated tests and mocks for `maker` are deleted or updated. Manifest timestamps are also updated.

## Changes

| File(s)                                                                                         | Change Summary                                                                                                                              |
|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml,<br>bundle/manifests/kernel-module-management.clusterserviceversion.yaml | Updated only the `createdAt` annotation timestamp in ClusterServiceVersion YAML files.                                                      |
| internal/buildsign/ocpbuild/maker.go,<br>internal/buildsign/ocpbuild/maker_test.go,<br>internal/buildsign/ocpbuild/mock_maker.go         | Deleted the `maker` interface, its implementation, its tests, and its GoMock mock.                                                         |
| internal/buildsign/ocpbuild/manager.go,<br>internal/buildsign/ocpbuild/manager_test.go           | Removed references to `maker`; replaced with calls to `ocpbuildManager.makeOCPBuildTemplate` and updated related tests accordingly.         |
| internal/buildsign/ocpbuild/ocpbuildmanager.go                                                   | Added `makeOCPBuildTemplate` and `getDockerfileData` methods to `ocpbuildManager`; updated struct and constructor for new dependencies.     |
| internal/buildsign/ocpbuild/ocpbuildmanager_test.go                                              | Added comprehensive tests for `makeOCPBuildTemplate`; updated test setup for new dependencies.                                              |
| internal/buildsign/ocpbuild/common.go                                                            | Added utility functions for converting build arguments and secrets to environment variables and build volumes.                              |
| internal/buildsign/ocpbuild/mock_ocbuildmanager.go                                               | Added a GoMock method for `makeOCPBuildTemplate` to the `MockocpbuildManager` struct.                                                      |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Manager
    participant OCPBuildManager
    participant K8sClient
    participant DTKMapping

    Manager->>OCPBuildManager: makeOCPBuildTemplate(ctx, mld, pushImage, owner)
    OCPBuildManager->>K8sClient: getDockerfileData(ctx, buildConfig, namespace)
    alt Dockerfile references DTK_AUTO
        OCPBuildManager->>DTKMapping: Get(kernelVersion)
        OCPBuildManager-->>OCPBuildManager: Add DTK image as build arg
    end
    OCPBuildManager-->>Manager: Return Build object
```

## Assessment against linked issues

| Objective                                                                                      | Addressed | Explanation                                                                                 |
|-----------------------------------------------------------------------------------------------|-----------|---------------------------------------------------------------------------------------------|
| Combine the `Maker` interface into `BuildSignPodManager` and remove the separate `Maker` logic (#1485) | ✅        |                                                                                             |
| Ensure build template creation logic is consolidated and all references updated (#1485)        | ✅        |                                                                                             |
| Remove all tests and mocks related to the old `Maker` interface (#1485)                        | ✅        |                                                                                             |

## Possibly related PRs

- [#1439](https://github.com/rh-ecosystem-edge/kernel-module-management/pull/1439): Refactors build/sign interfaces, similar to this PR's consolidation of build template logic.
- [#1444](https://github.com/rh-ecosystem-edge/kernel-module-management/pull/1444): Introduced the `ocpbuildManager` interface, which this PR now extends with build template creation.
- [#1452](https://github.com/rh-ecosystem-edge/kernel-module-management/pull/1452): Previously introduced the `maker` interface and its implementation, which are now removed in this PR.

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> - CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> 
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 70dc75fcfe34c11a8381b18a5e7c52078a194832 and 1431033c99cfcec2d990126a5dfbe272bc75e0d8.

</details>

<details>
<summary>📒 Files selected for processing (11)</summary>

* `bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml` (1 hunks)
* `bundle/manifests/kernel-module-management.clusterserviceversion.yaml` (1 hunks)
* `internal/buildsign/ocpbuild/common.go` (1 hunks)
* `internal/buildsign/ocpbuild/maker.go` (0 hunks)
* `internal/buildsign/ocpbuild/maker_test.go` (0 hunks)
* `internal/buildsign/ocpbuild/manager.go` (2 hunks)
* `internal/buildsign/ocpbuild/manager_test.go` (6 hunks)
* `internal/buildsign/ocpbuild/mock_maker.go` (0 hunks)
* `internal/buildsign/ocpbuild/mock_ocbuildmanager.go` (2 hunks)
* `internal/buildsign/ocpbuild/ocpbuildmanager.go` (3 hunks)
* `internal/buildsign/ocpbuild/ocpbuildmanager_test.go` (9 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (3)</summary>

* internal/buildsign/ocpbuild/mock_maker.go
* internal/buildsign/ocpbuild/maker_test.go
* internal/buildsign/ocpbuild/maker.go

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (2)</summary>

* bundle/manifests/kernel-module-management.clusterserviceversion.yaml
* bundle-hub/manifests/kernel-module-management-hub.clusterserviceversion.yaml

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* internal/buildsign/ocpbuild/manager.go
* internal/buildsign/ocpbuild/manager_test.go
* internal/buildsign/ocpbuild/mock_ocbuildmanager.go
* internal/buildsign/ocpbuild/common.go

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Analyze (go)

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>internal/buildsign/ocpbuild/ocpbuildmanager_test.go (1)</summary>

`389-660`: **Well-structured test coverage for makeOCPBuildTemplate**

The test suite for `makeOCPBuildTemplate` is comprehensive and covers various scenarios including:
- Different combinations of build secrets and image pull secrets
- Handling of node selectors from different sources
- Special handling of DTK build arguments
- Error cases when DTK image cannot be retrieved
- Build argument overrides

This provides good test coverage for the new functionality.

</details>
<details>
<summary>internal/buildsign/ocpbuild/ocpbuildmanager.go (1)</summary>

`199-308`: **Well-structured implementation of `makeOCPBuildTemplate`**

The method is well implemented with clear logic for:
- Handling intermediate images for signed modules
- Setting up build arguments and overrides
- Configuring the build output and source
- Setting labels, annotations, and owner references

After fixing the nil pointer issues, this will be a robust implementation.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=rh-ecosystem-edge/kernel-module-management&utm_content=1488):

> ‼️ **IMPORTANT**
> Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: openshift-ci[bot]
created_at: 2025-05-08T12:57:21Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/rh-ecosystem-edge/kernel-module-management/pull/1488#" title="Author self-approved">ybettan</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=rh-ecosystem-edge%2Fkernel-module-management).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/rh-ecosystem-edge/kernel-module-management/blob/main/OWNERS)~~ [ybettan]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: NONE
user: login: ybettan
created_at: 2025-05-08T13:51:06Z
body: /unhold
author_association: MEMBER
user: login: TomerNewman
created_at: 2025-05-09T03:49:36Z
body: /lgtm
author_association: MEMBER