Skip to content

Feat: Add corporate certificates to Build APIs#2107

Open
sayan-biswas wants to merge 1 commit intoshipwright-io:mainfrom
sayan-biswas:certificates
Open

Feat: Add corporate certificates to Build APIs#2107
sayan-biswas wants to merge 1 commit intoshipwright-io:mainfrom
sayan-biswas:certificates

Conversation

@sayan-biswas
Copy link
Copy Markdown

@sayan-biswas sayan-biswas commented Feb 18, 2026

Changes:

  • Added APIs to allow user to define custom Root CAs in Build and BuildRun APIs

Submitter Checklist

  • Includes tests if functionality changed/was added
  • Includes docs if changes are user-facing
  • Set a kind label on this PR
  • Release notes block has been filled in, or marked NONE

See the contributor guide
for details on coding conventions, github and prow interactions, and the code review process.

Release Notes

Custom CA certificated can now be provided in `Build` and `BuildRun` under `CABundle` property.

@openshift-ci openshift-ci Bot added release-note Label for when a PR has specified a release note do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Feb 18, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Feb 18, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign saschaschwarze0 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@pull-request-size pull-request-size Bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Feb 18, 2026
@sayan-biswas sayan-biswas force-pushed the certificates branch 2 times, most recently from fe07158 to b4af1ae Compare February 23, 2026 15:22
@sayan-biswas
Copy link
Copy Markdown
Author

/retest

@sayan-biswas sayan-biswas marked this pull request as ready for review April 6, 2026 05:41
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 6, 2026
@openshift-ci openshift-ci Bot requested review from hasanawad94 and karanibm6 April 6, 2026 05:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for corporate/custom Root CA certificates to the Build and BuildRun APIs. The feature allows users to specify CA bundles via Secret or ConfigMap references at both the Build and BuildRun levels, with the BuildRun specification taking precedence. The certificates are mounted into workload containers and relevant environment variables are configured.

Changes:

  • Added CA bundle API types (CABundle, SourceObjectKeySelector) for Build/BuildRun specifications
  • Implemented CA bundle validation logic in the validate package
  • Implemented CA bundle volume and environment variable injection for TaskRun/PipelineRun execution
  • Added CA bundle parameter definitions to task specifications
  • Enhanced error handling in taskrun_generator.go to properly check errors from called functions

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/apis/build/v1beta1/cabundle.go New API types for CA bundle references
pkg/apis/build/v1beta1/build_types.go Added CABundle field to BuildSpec and new BuildReason constant
pkg/apis/build/v1beta1/buildrun_types.go Added CABundle field to BuildRunSpec
pkg/cabundle/cabundle.go Core CA bundle validation and volume/environment variable generation
pkg/cabundle/cabundle_test.go Comprehensive tests for CA bundle handling
pkg/cabundle/suite_test.go Test suite setup
pkg/validate/cabundle.go Validation logic for Build CA bundle references
pkg/validate/validate.go Added Certificates constant and validation case
pkg/reconciler/buildrun/resources/cabundle.go TaskRun/PipelineRun certificate injection
pkg/reconciler/buildrun/resources/taskrun.go Added paramCABundle constant
pkg/reconciler/buildrun/resources/resource_builders.go CA bundle parameter specifications and values
pkg/reconciler/buildrun/resources/taskrun_generator.go Enhanced error handling and certificate injection
pkg/reconciler/buildrun/buildrun.go Added CA bundle validation to reconciliation
deploy/crds/shipwright.io_builds.yaml Updated Build CRD
deploy/crds/shipwright.io_buildruns.yaml Updated BuildRun CRD
test/utils/v1beta1/pipelinerun.go Added copyright header

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/reconciler/buildrun/resources/resource_builders.go Outdated
Comment thread pkg/validate/validate.go Outdated
Comment thread pkg/cabundle/cabundle.go Outdated
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 13, 2026
@sayan-biswas sayan-biswas requested a review from Copilot April 13, 2026 15:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/cabundle/cabundle.go Outdated
Comment thread pkg/cabundle/cabundle.go Outdated
Comment thread pkg/cabundle/cabundle.go Outdated
Comment thread pkg/cabundle/cabundle.go Outdated
Comment thread pkg/validate/cabundle.go
Comment thread pkg/reconciler/buildrun/resources/cabundle.go Outdated
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 16, 2026
@sayan-biswas sayan-biswas requested a review from Copilot April 20, 2026 03:10
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/cabundle/cabundle.go
Comment thread pkg/cabundle/cabundle.go
Comment thread pkg/validate/validate.go Outdated
Comment thread pkg/reconciler/buildrun/resources/resource_builders.go Outdated
Comment thread pkg/reconciler/buildrun/resources/resource_builders.go
Comment thread pkg/apis/build/v1beta1/cabundle.go
Comment thread pkg/validate/cabundle.go
Comment thread pkg/apis/build/v1beta1/build_types.go
Comment thread pkg/reconciler/buildrun/resources/cabundle.go
Comment thread pkg/reconciler/buildrun/resources/taskrun_generator.go
@pull-request-size pull-request-size Bot removed the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Apr 20, 2026
@pull-request-size pull-request-size Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Apr 20, 2026
@sayan-biswas sayan-biswas force-pushed the certificates branch 2 times, most recently from 57586d0 to e912647 Compare April 27, 2026 10:56
Copy link
Copy Markdown
Member

@avinal avinal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing, builds using TaskRuns ran successfully, but builds using PipelineRuns failed due to nil pointer error.

Apart from that, it seems deepcopygen was not rerun.

Comment on lines +51 to +55
if pipelineRun != nil {
pipelineRun.Spec.TaskRunTemplate.PodTemplate.Volumes = append(pipelineRun.Spec.TaskRunTemplate.PodTemplate.Volumes, *volume)
for _, e := range envVar {
if !hasEnvVarByName(pipelineRun.Spec.TaskRunTemplate.PodTemplate.Env, e.Name) {
pipelineRun.Spec.TaskRunTemplate.PodTemplate.Env = append(pipelineRun.Spec.TaskRunTemplate.PodTemplate.Env, e)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of issues here:

  1. While testing PipelineRun it gives a nil pointer error; it seems PodTemplate is never initialized. Need to initialize and add a nil check here. Please refer the log.
  2. Volume is not added to PipelineRun but it is added to TaskRun steps at line 47? Am I missing anything?
PipelineRun BuildRun Logs
{"level":"debug","ts":"2026-04-28T11:28:41Z","msg":"starting reconciling request from a BuildRun or TaskRun event","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","namespace":"default","name":"test-cabundle-pipelinerun-ckj5t"}
{"level":"info","ts":"2026-04-28T11:28:41Z","msg":"updating BuildRun status","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","namespace":"default","name":"test-cabundle-pipelinerun-ckj5t"}
{"level":"info","ts":"2026-04-28T11:28:41Z","msg":"falling back to default serviceAccount","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","namespace":"default"}
{"level":"debug","ts":"2026-04-28T11:28:41Z","msg":"retrieving ClusterBuildStrategy","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","namespace":"default","name":"test-cabundle"}
{"level":"error","ts":"2026-04-28T11:28:41Z","msg":"Observed a panic","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","panic":"runtime error: invalid memory address or nil pointer dereference","panicGoValue":"\"invalid memory address or nil pointer dereference\"","stacktrace":"goroutine 420 [running]:\nk8s.io/apimachinery/pkg/util/runtime.logPanic({0x233fa50, 0x13a14b22ba40}, {0x1e93ac0, 0x38302b0})\n\tk8s.io/apimachinery@v0.34.4/pkg/util/runtime/runtime.go:132 +0xbc\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile.func1()\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:198 +0x103\npanic({0x1e93ac0?, 0x38302b0?})\n\truntime/panic.go:860 +0x13a\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.addCertificates(0x0, 0x13a14a6ebb08, 0x13a14b3c7410?, 0x0?)\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/cabundle.go:52 +0x3f3\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.(*PipelineRunGenerator).ApplyInfrastructureConfiguration(0x13a14aee73e0)\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/pipelinerun_generator.go:225 +0x3d6\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.GenerateBuildRunExecutor(0x0?, 0x0?, {0x234f840?, 0x13a14ad49340?}, {0x234dff0, 0x13a14aee73e0})\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/executor_generator.go:96 +0x350\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.GeneratePipelineRun(0x13a14a7ee408, 0x13a14a6eb688, 0x13a14a6eab48, {0x13a14ac92a40, 0x7}, {0x234f840, 0x13a14ad49340})\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/pipelinerun.go:26 +0xe7\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun.(*TektonPipelineRunImageBuildRunnerFactory).CreateImageBuildRunner(0x0?, {0x233faf8, 0x13a14af7c3f0}, {0x2357d08, 0x13a14a6f54d0}, 0x7f175dd56cd8?, 0x236c818?, {0x234f840?, 0x13a14ad49340?}, 0x13a14a6eb688, ...)\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/pipelinerun_runner.go:223 +0x70\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun.(*ReconcileBuildRun).Reconcile(0x13a14a6f84c0, {0x233fa50?, 0x13a14b22ba40?}, {{{0x13a14ad09ec6?, 0x13a14b22ba40?}, {0x13a14b234120?, 0x0?}}})\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/buildrun.go:339 +0x3445\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile(0x13a14b22b9b0?, {0x233fa50?, 0x13a14b22ba40}, {{{0x13a14ad09ec6, 0x0?}, {0x13a14b234120?, 0x0?}}})\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:216 +0x165\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler(0x236c700, {0x233fa88, 0x13a14a793ea0}, {{{0x13a14ad09ec6, 0x7}, {0x13a14b234120, 0x1f}}}, 0x0)\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:461 +0x377\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem(0x236c700, {0x233fa88, 0x13a14a793ea0})\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421 +0x1f8\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1()\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296 +0x85\ncreated by sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1 in goroutine 181\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:292 +0x26b\n","stacktrace":"k8s.io/apimachinery/pkg/util/runtime.logPanic\n\tk8s.io/apimachinery@v0.34.4/pkg/util/runtime/runtime.go:142\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile.func1\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:198\nruntime.gopanic\n\truntime/panic.go:860\nruntime.panicmem\n\truntime/panic.go:336\nruntime.sigpanic\n\truntime/signal_unix.go:931\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.addCertificates\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/cabundle.go:52\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.(*PipelineRunGenerator).ApplyInfrastructureConfiguration\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/pipelinerun_generator.go:225\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.GenerateBuildRunExecutor\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/executor_generator.go:96\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources.GeneratePipelineRun\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/resources/pipelinerun.go:26\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun.(*TektonPipelineRunImageBuildRunnerFactory).CreateImageBuildRunner\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/pipelinerun_runner.go:223\ngithub.com/shipwright-io/build/pkg/reconciler/buildrun.(*ReconcileBuildRun).Reconcile\n\tgithub.com/shipwright-io/build/pkg/reconciler/buildrun/buildrun.go:339\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:216\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:461\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296"}
{"level":"error","ts":"2026-04-28T11:28:41Z","msg":"Reconciler error","controller":"buildrun-controller","object":{"name":"test-cabundle-pipelinerun-ckj5t","namespace":"default"},"namespace":"default","name":"test-cabundle-pipelinerun-ckj5t","reconcileID":"a0bcc484-435b-4990-9469-8f81ebe71764","error":"panic: runtime error: invalid memory address or nil pointer dereference [recovered]","stacktrace":"sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:474\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:421\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func1.1\n\tsigs.k8s.io/controller-runtime@v0.22.5/pkg/internal/controller/controller.go:296"}

Copy link
Copy Markdown
Author

@sayan-biswas sayan-biswas May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the error and added Volumes to pipeline.

}
}

return nil
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function always returns nil. Is that on purpose, or some error should be returned?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.. To match the other functions there. Might require in future.

Comment thread pkg/cabundle/cabundle.go
Comment on lines +70 to +81
switch o := object.(type) {
case *corev1.Secret:
data = o.Data[ca.Secret.Key]
case *corev1.ConfigMap:
data = []byte(o.Data[ca.ConfigMap.Key])
}

// Parse and validate each certificate in the PEM data
block, rest := pem.Decode(data)
if block == nil {
return fmt.Errorf("no certificate present in CA bundle")
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe in case the key doesn't exist, we should return a proper error and not rely on Decode() to finally return that "Certificate is not present". This way we will know what exactly is wrong.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the API the key field is not optional.

Comment on lines +59 to +62
Name: fmt.Sprintf("%s-%s", prefixParamsResultsVolumes, paramCABundle),
Description: "The CA Bundle file used to access secure endpoints",
Type: pipelineapi.ParamTypeString,
},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the paramCABundle is always added even if there is nothing configured, should this be inside a if paramCABundle != nil kind of block?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the login to make the parameter empty if the CA bundle is not provided.

Comment thread pkg/validate/validate.go
}

// BuildRunFields runs field validations against a BuildRun to detect
// disallowed field combinations and issues
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a conflict/preference check for Build/BuildRun? For example, if cabundle is added to both Build and BuildRun. Currently, BuildRun wins because of how addCertificate function is defined. Is that intended?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The priority is BuildRun >> Build

Reference: shipwright-io/community#281

# Changes:
- Added APIs to allow user to define custom Root CAs in Build and BuildRun APIs
- Add unit tests

Signed-off-by: Sayan Biswas <sabiswas@redhat.com>
Comment on lines -86 to +96
return generateTaskSpecVolumes(
if err = generateTaskSpecVolumes(
g.taskRun.Spec.TaskSpec,
execCtx.volumeMounts,
execCtx.strategyVolumes,
execCtx.buildVolumes,
execCtx.buildRunVolumes,
)
); err != nil {
return err
}

return nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code can be left as is.

if err is nil, nil is returned and if err is not nil, err is returned, so the value of err is returned in all cases. Therefore, return generateTaskSpecVolumes( is already doing the right thing.

Suggested change
return generateTaskSpecVolumes(
if err = generateTaskSpecVolumes(
g.taskRun.Spec.TaskSpec,
execCtx.volumeMounts,
execCtx.strategyVolumes,
execCtx.buildVolumes,
execCtx.buildRunVolumes,
)
); err != nil {
return err
}
return nil
return generateTaskSpecVolumes(

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.. This part of the code was already correct. Made this change to improve the code readability and match the other function.

Comment on lines +145 to +149
if err := applyParameters(g.taskRun, g.build, g.buildRun, g.strategy); err != nil {
return err
}

return nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, the original return statement should stay as is.

Comment thread pkg/validate/cabundle.go
c.Build.Status.Reason = ptr.To[buildapi.BuildReason](buildapi.CABundleNotValid)
c.Build.Status.Message = ptr.To(err.Error())
}
return nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be return err ? Otherwise you have a function with an error return type that never returns an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note Label for when a PR has specified a release note size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants