Add denylist for system namespaces in targetNamespace validation#3507
Add denylist for system namespaces in targetNamespace validation#3507mvanhorn wants to merge 3 commits into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
|
||
| func (ta *CommonSpec) validate(path string) *apis.FieldError { | ||
| var errs *apis.FieldError | ||
| targetNamespace := ta.GetTargetNamespace() |
There was a problem hiding this comment.
this is cleaner than calling GetTargetNamespace() multile time
| }, | ||
| Spec: TektonResultSpec{ | ||
| CommonSpec: CommonSpec{ | ||
| TargetNamespace: "kube-system", |
There was a problem hiding this comment.
this skips validation kube-public, kube-node-lease, default, and the OpenShift openshift-operators case, without any failing test at the TektonResult level.
|
@mvanhorn thank you for you contribution, would you add the validation to pkg/apis/operator/v1alpha1/tektonscheduler_validation.go:27–41 |
There was a problem hiding this comment.
Pull request overview
Adds defense-in-depth validation to prevent installing Tekton components into well-known Kubernetes system namespaces via spec.targetNamespace, and ensures TektonResult applies the shared CommonSpec validation path so the denylist (and existing empty check) are enforced consistently.
Changes:
- Add a reserved system namespace denylist (
kube-system,kube-public,kube-node-lease,default) toCommonSpec.validate()across platforms, while preserving the OpenShift-onlyopenshift-operatorsrestriction. - Ensure
TektonResultSpec.validate()invokes the embeddedCommonSpec.validate()so TektonResult no longer bypasses shared validation. - Extend unit tests to cover denylisted namespaces and the TektonResult validation path.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pkg/apis/operator/v1alpha1/common_validation.go | Adds reserved namespace denylist enforcement to shared CommonSpec validation. |
| pkg/apis/operator/v1alpha1/common_validation_test.go | Updates CommonSpec validation tests for reserved namespace denylist (Kubernetes + one OpenShift case). |
| pkg/apis/operator/v1alpha1/tektonresult_validation.go | Ensures TektonResultSpec runs shared CommonSpec validation. |
| pkg/apis/operator/v1alpha1/tektonresult_validation_test.go | Adds a test covering TektonResult’s denylisted targetNamespace validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {name: "ns-openshift-operators", targetNamespace: "openshift-operators", err: "", isOpenshift: false}, | ||
| {name: "openshift-ns-default", targetNamespace: "default", err: "invalid value: default: spec.targetNamespace\n'default' is a reserved system namespace and is not allowed", isOpenshift: true}, | ||
| {name: "openshift-ns-openshift-operators", targetNamespace: "openshift-operators", err: "invalid value: openshift-operators: spec.targetNamespace\n'openshift-operators' namespace is not allowed", isOpenshift: true}, | ||
| {name: "openshift-ns-openshift-pipelines", targetNamespace: "openshift-pipelines", err: "", isOpenshift: true}, |
| func isReservedSystemNamespace(namespace string) bool { | ||
| for _, reservedNamespace := range reservedSystemNamespaces { |
There was a problem hiding this comment.
Minor: this loop can be simplified with slices.Contains (Go 1.21+):
return slices.Contains(reservedSystemNamespaces, namespace)
|
Done - |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3507 +/- ##
==========================================
+ Coverage 25.47% 25.51% +0.03%
==========================================
Files 449 449
Lines 23363 23374 +11
==========================================
+ Hits 5952 5963 +11
Misses 16725 16725
Partials 686 686
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
CommonSpec.validate() previously accepted any non-empty targetNamespace on Kubernetes, allowing components to be installed into well-known system namespaces such as kube-system, kube-public, kube-node-lease, or default. Add a defense-in-depth denylist that rejects those four reserved namespaces on both Kubernetes and OpenShift, while preserving the existing OpenShift-only openshift-operators rejection. Because validate() is the shared method called by every component validator, the denylist applies to all of them with no caller changes. Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
TektonResult.Validate calls TektonResultSpec.validate, which did not call the embedded CommonSpec.validate, so the new system-namespace denylist (and the pre-existing empty-field check) was bypassed for TektonResult. Wire the common validation into TektonResultSpec.validate so the denylist is enforced consistently across every CommonSpec-backed component. Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
TektonScheduler embeds CommonSpec, but Validate() only called
ts.Spec.MultiClusterConfig.validate(), so the common spec checks
(targetNamespace presence and reserved-namespace rejection) never ran.
Call ts.Spec.CommonSpec.validate("spec") the way every other component
does.
Set a valid targetNamespace in the existing scheduler validation
fixtures, and add a test asserting a reserved system namespace is now
rejected.
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
68bc9dd to
0f7b005
Compare
Changes
CommonSpec.validate()previously accepted any non-emptytargetNamespaceon Kubernetes, so a component could be told to install into a well-known system namespace such askube-system,kube-public,kube-node-lease, ordefault. On OpenShift onlyopenshift-operatorswas blocked.This adds a defense-in-depth denylist that rejects those four reserved system namespaces on both Kubernetes and OpenShift, while preserving the existing OpenShift-only
openshift-operatorsrejection. Becausevalidate()is the shared method called by every component validator, the denylist applies across components with no caller changes.While wiring this up I found that
TektonResultbypassed the shared validation entirely:TektonResult.ValidatecallsTektonResultSpec.validate, which never invoked the embeddedCommonSpec.validate. This change also calls the common validation fromTektonResultSpec.validateso the denylist (and the pre-existing empty-field check) is enforced consistently forTektonResulttoo.Tests cover the happy path, each denied namespace on both platforms, the preserved
openshift-operatorsrejection, the empty-namespace case, and theTektonResultpath.Fixes #3248
Submitter Checklist
These are the criteria that every PR should meet, please check them off as you
review them:
make test lintbefore submitting a PRSee the contribution guide for more details.
Release Notes