• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / sap-btp-service-operator / 16626854236

30 Jul 2025 03:26PM UTC coverage: 79.972% (-0.2%) from 80.217%
16626854236

Pull #545

github

kerenlahav
fix lint
Pull Request #545: [BUG FIX] cred rotation is not working when binding's name is longer than 63 chars

21 of 58 new or added lines in 3 files covered. (36.21%)

4 existing lines in 2 files now uncovered.

2823 of 3530 relevant lines covered (79.97%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.43
/api/v1/servicebinding_validating_webhook.go
1
/*
2

3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package v1
18

19
import (
20
        "context"
21
        "fmt"
22
        "reflect"
23
        "time"
24

25
        "github.com/SAP/sap-btp-service-operator/api/common"
26
        "k8s.io/apimachinery/pkg/runtime"
27
        ctrl "sigs.k8s.io/controller-runtime"
28
        logf "sigs.k8s.io/controller-runtime/pkg/log"
29
        "sigs.k8s.io/controller-runtime/pkg/webhook"
30
        "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
31
)
32

33
// log is for logging in this package.
34
var servicebindinglog = logf.Log.WithName("servicebinding-resource")
35

36
func (sb *ServiceBinding) SetupWebhookWithManager(mgr ctrl.Manager) error {
×
37
        return ctrl.NewWebhookManagedBy(mgr).For(sb).WithValidator(sb).Complete()
×
38
}
×
39

40
// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
41

42
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
43
// +kubebuilder:webhook:verbs=create;update,path=/validate-services-cloud-sap-com-v1-servicebinding,mutating=false,failurePolicy=fail,groups=services.cloud.sap.com,resources=servicebindings,versions=v1,name=vservicebinding.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
44

45
var _ webhook.CustomValidator = &ServiceBinding{}
46

47
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
48
func (sb *ServiceBinding) ValidateCreate(_ context.Context, obj runtime.Object) (admission.Warnings, error) {
1✔
49
        newBinding := obj.(*ServiceBinding)
1✔
50
        servicebindinglog.Info("validate create", "name", newBinding.ObjectMeta.Name)
1✔
51
        if len(newBinding.Spec.ExternalName) > 100 {
1✔
NEW
52
                return nil, fmt.Errorf("binding's name must be less than 100 characters")
×
NEW
53
        }
×
54
        if newBinding.Spec.CredRotationPolicy != nil {
2✔
55
                if err := newBinding.validateCredRotatingConfig(); err != nil {
1✔
56
                        return nil, err
×
57
                }
×
58
        }
59
        return nil, nil
1✔
60
}
61

62
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
63
func (sb *ServiceBinding) ValidateUpdate(_ context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
1✔
64
        oldBinding := oldObj.(*ServiceBinding)
1✔
65
        newBinding := newObj.(*ServiceBinding)
1✔
66
        servicebindinglog.Info("validate update", "name", newBinding.ObjectMeta.Name)
1✔
67
        if newBinding.Spec.CredRotationPolicy != nil {
2✔
68
                if err := newBinding.validateCredRotatingConfig(); err != nil {
2✔
69
                        return nil, err
1✔
70
                }
1✔
71
        }
72
        isStale := false
1✔
73
        if oldBinding.Labels != nil {
2✔
74
                if _, ok := oldBinding.Labels[common.StaleBindingIDLabel]; ok {
2✔
75
                        if newBinding.Spec.CredRotationPolicy.Enabled {
2✔
76
                                return nil, fmt.Errorf("enabling cred rotation for rotated binding is not allowed")
1✔
77
                        }
1✔
NEW
78
                        if !newBinding.validateRotationFields(oldBinding) {
×
79
                                return nil, fmt.Errorf("modifying rotation labels is not allowed")
×
80
                        }
×
81
                        isStale = true
×
82
                }
83
        }
84

85
        if newBinding.Spec.UserInfo == nil {
2✔
86
                newBinding.Spec.UserInfo = oldBinding.Spec.UserInfo
1✔
87
        } else if !reflect.DeepEqual(newBinding.Spec.UserInfo, oldBinding.Spec.UserInfo) {
3✔
88
                return nil, fmt.Errorf("modifying spec.userInfo is not allowed")
1✔
89
        }
1✔
90

91
        isSpecChanged := newBinding.specChanged(oldBinding)
1✔
92
        if isSpecChanged && (newBinding.Status.BindingID != "" || isStale) {
2✔
93

1✔
94
                return nil, fmt.Errorf("updating service bindings is not supported")
1✔
95
        }
1✔
96
        return nil, nil
1✔
97
}
98

NEW
99
func (sb *ServiceBinding) validateRotationFields(old *ServiceBinding) bool {
×
NEW
100
        if sb.ObjectMeta.Labels == nil {
×
101
                return false
×
102
        }
×
103

NEW
104
        isValid := sb.ObjectMeta.Labels[common.StaleBindingIDLabel] == old.ObjectMeta.Labels[common.StaleBindingIDLabel] &&
×
NEW
105
                sb.ObjectMeta.Labels[common.StaleBindingRotationOfLabel] == old.ObjectMeta.Labels[common.StaleBindingRotationOfLabel]
×
NEW
106

×
NEW
107
        if len(old.ObjectMeta.Annotations[common.StaleBindingOrigBindingNameAnnotation]) > 0 {
×
NEW
108
                isValid = isValid && sb.ObjectMeta.Annotations[common.StaleBindingOrigBindingNameAnnotation] == old.ObjectMeta.Annotations[common.StaleBindingOrigBindingNameAnnotation]
×
NEW
109
        }
×
NEW
110
        return isValid
×
111
}
112

113
func (sb *ServiceBinding) specChanged(oldBinding *ServiceBinding) bool {
1✔
114
        oldSpec := oldBinding.Spec.DeepCopy()
1✔
115
        newSpec := sb.Spec.DeepCopy()
1✔
116

1✔
117
        //allow changing cred rotation config
1✔
118
        oldSpec.CredRotationPolicy = nil
1✔
119
        newSpec.CredRotationPolicy = nil
1✔
120

1✔
121
        //allow changing SecretTemplate
1✔
122
        oldSpec.SecretTemplate = ""
1✔
123
        newSpec.SecretTemplate = ""
1✔
124

1✔
125
        return !reflect.DeepEqual(oldSpec, newSpec)
1✔
126
}
1✔
127

128
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
129
func (sb *ServiceBinding) ValidateDelete(_ context.Context, _ runtime.Object) (admission.Warnings, error) {
1✔
130
        servicebindinglog.Info("validate delete", "name", sb.ObjectMeta.Name)
1✔
131

1✔
132
        // TODO(user): fill in your validation logic upon object deletion.
1✔
133
        return nil, nil
1✔
134
}
1✔
135

136
func (sb *ServiceBinding) validateCredRotatingConfig() error {
1✔
137
        _, err := time.ParseDuration(sb.Spec.CredRotationPolicy.RotatedBindingTTL)
1✔
138
        if err != nil {
2✔
139
                return err
1✔
140
        }
1✔
141
        _, err = time.ParseDuration(sb.Spec.CredRotationPolicy.RotationFrequency)
1✔
142
        if err != nil {
1✔
143
                return err
×
144
        }
×
145

146
        return nil
1✔
147
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc