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

opendefensecloud / solution-arsenal / 24497764971

16 Apr 2026 07:28AM UTC coverage: 72.258% (+0.2%) from 72.044%
24497764971

push

github

web-flow
fix(deps): update module sigs.k8s.io/structured-merge-diff/v6 to v6.4.0 (#429)

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[sigs.k8s.io/structured-merge-diff/v6](https://redirect.github.com/kubernetes-sigs/structured-merge-diff)
| `v6.3.2` → `v6.4.0` |
![age](https://developer.mend.io/api/mc/badges/age/go/sigs.k8s.io%2fstructured-merge-diff%2fv6/v6.4.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/sigs.k8s.io%2fstructured-merge-diff%2fv6/v6.3.2/v6.4.0?slim=true)
|

---

### Release Notes

<details>
<summary>kubernetes-sigs/structured-merge-diff
(sigs.k8s.io/structured-merge-diff/v6)</summary>

###
[`v6.4.0`](https://redirect.github.com/kubernetes-sigs/structured-merge-diff/compare/v6.3.2...v6.4.0)

[Compare
Source](https://redirect.github.com/kubernetes-sigs/structured-merge-diff/compare/v6.3.2...v6.4.0)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/opendefensecloud/solution-arsenal).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMjAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjEyMC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

2029 of 2808 relevant lines covered (72.26%)

28.1 hits per line

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

77.78
/pkg/controller/profile_controller.go
1
// Copyright 2026 BWI GmbH and Solution Arsenal contributors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package controller
5

6
import (
7
        "context"
8
        "fmt"
9

10
        corev1 "k8s.io/api/core/v1"
11
        apierrors "k8s.io/apimachinery/pkg/api/errors"
12
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
        "k8s.io/apimachinery/pkg/labels"
14
        "k8s.io/apimachinery/pkg/runtime"
15
        "k8s.io/client-go/tools/events"
16
        ctrl "sigs.k8s.io/controller-runtime"
17
        "sigs.k8s.io/controller-runtime/pkg/client"
18
        "sigs.k8s.io/controller-runtime/pkg/handler"
19
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
20

21
        solarv1alpha1 "go.opendefense.cloud/solar/api/solar/v1alpha1"
22
)
23

24
// ProfileReconciler reconciles a Profile object.
25
// It evaluates the Profile's TargetSelector against all Targets in the namespace
26
// and creates/deletes ReleaseBindings accordingly.
27
type ProfileReconciler struct {
28
        client.Client
29
        Scheme   *runtime.Scheme
30
        Recorder events.EventRecorder
31
        // WatchNamespace restricts reconciliation to this namespace.
32
        WatchNamespace string
33
}
34

35
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles,verbs=get;list;watch
36
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles/status,verbs=get;update;patch
37
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releasebindings,verbs=get;list;watch;create;update;patch;delete
38
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=targets,verbs=get;list;watch
39
//+kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
40
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
41

42
// Reconcile evaluates the Profile's TargetSelector and ensures matching ReleaseBindings exist.
43
func (r *ProfileReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
25✔
44
        log := ctrl.LoggerFrom(ctx)
25✔
45

25✔
46
        log.V(1).Info("Profile is being reconciled", "req", req)
25✔
47

25✔
48
        if r.WatchNamespace != "" && req.Namespace != r.WatchNamespace {
37✔
49
                return ctrl.Result{}, nil
12✔
50
        }
12✔
51

52
        // Fetch Profile
53
        profile := &solarv1alpha1.Profile{}
13✔
54
        if err := r.Get(ctx, req.NamespacedName, profile); err != nil {
13✔
55
                if apierrors.IsNotFound(err) {
×
56
                        return ctrl.Result{}, nil
×
57
                }
×
58

59
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get Profile")
×
60
        }
61

62
        // Evaluate TargetSelector against all Targets
63
        selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
13✔
64
        if err != nil {
13✔
65
                log.Error(err, "invalid targetSelector in Profile")
×
66

×
67
                return ctrl.Result{}, nil
×
68
        }
×
69

70
        targetList := &solarv1alpha1.TargetList{}
13✔
71
        if err := r.List(ctx, targetList,
13✔
72
                client.InNamespace(profile.Namespace),
13✔
73
                client.MatchingLabelsSelector{Selector: selector},
13✔
74
        ); err != nil {
13✔
75
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to list Targets")
×
76
        }
×
77

78
        // Build set of desired ReleaseBindings (one per matching target)
79
        desiredTargets := map[string]bool{}
13✔
80
        for _, target := range targetList.Items {
28✔
81
                desiredTargets[target.Name] = true
15✔
82
        }
15✔
83

84
        // List existing ReleaseBindings owned by this Profile
85
        existingBindings := &solarv1alpha1.ReleaseBindingList{}
13✔
86
        if err := r.List(ctx, existingBindings,
13✔
87
                client.InNamespace(profile.Namespace),
13✔
88
                client.MatchingFields{"metadata.ownerReferences.name": profile.Name},
13✔
89
        ); err != nil {
26✔
90
                // Field index may not be available; fall back to listing all and filtering
13✔
91
                allBindings := &solarv1alpha1.ReleaseBindingList{}
13✔
92
                if err := r.List(ctx, allBindings, client.InNamespace(profile.Namespace)); err != nil {
13✔
93
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to list ReleaseBindings")
×
94
                }
×
95

96
                existingBindings = &solarv1alpha1.ReleaseBindingList{}
13✔
97

13✔
98
                for i := range allBindings.Items {
23✔
99
                        if metav1.IsControlledBy(&allBindings.Items[i], profile) {
20✔
100
                                existingBindings.Items = append(existingBindings.Items, allBindings.Items[i])
10✔
101
                        }
10✔
102
                }
103
        }
104

105
        // Delete ReleaseBindings for targets that no longer match
106
        existingTargets := map[string]*solarv1alpha1.ReleaseBinding{}
13✔
107
        for i := range existingBindings.Items {
23✔
108
                rb := &existingBindings.Items[i]
10✔
109
                existingTargets[rb.Spec.TargetRef.Name] = rb
10✔
110

10✔
111
                if !desiredTargets[rb.Spec.TargetRef.Name] {
11✔
112
                        log.V(1).Info("Deleting ReleaseBinding for unmatched target", "target", rb.Spec.TargetRef.Name)
1✔
113
                        if err := r.Delete(ctx, rb); err != nil && !apierrors.IsNotFound(err) {
1✔
114
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to delete ReleaseBinding")
×
115
                        }
×
116

117
                        r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Deleted", "Delete",
1✔
118
                                "Deleted ReleaseBinding for target %s", rb.Spec.TargetRef.Name)
1✔
119
                }
120
        }
121

122
        // Create ReleaseBindings for new matching targets
123
        for _, target := range targetList.Items {
28✔
124
                if _, exists := existingTargets[target.Name]; exists {
24✔
125
                        continue
9✔
126
                }
127

128
                rb := &solarv1alpha1.ReleaseBinding{
6✔
129
                        ObjectMeta: metav1.ObjectMeta{
6✔
130
                                // We need to truncated the name: 57 (input) + 1 (-) + 5 (appended by generated) = 63 (max chars allowed)
6✔
131
                                GenerateName: truncateName(fmt.Sprintf("%s-%s", profile.Name, target.Name), 57) + "-",
6✔
132
                                Namespace:    profile.Namespace,
6✔
133
                        },
6✔
134
                        Spec: solarv1alpha1.ReleaseBindingSpec{
6✔
135
                                TargetRef:  corev1.LocalObjectReference{Name: target.Name},
6✔
136
                                ReleaseRef: profile.Spec.ReleaseRef,
6✔
137
                        },
6✔
138
                }
6✔
139
                if err := ctrl.SetControllerReference(profile, rb, r.Scheme); err != nil {
6✔
140
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to set controller reference on ReleaseBinding")
×
141
                }
×
142

143
                if err := r.Create(ctx, rb); err != nil {
6✔
144
                        if apierrors.IsAlreadyExists(err) {
×
145
                                continue
×
146
                        }
147

148
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to create ReleaseBinding")
×
149
                }
150

151
                log.V(1).Info("Created ReleaseBinding for target", "target", target.Name)
6✔
152
                r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Created", "Create",
6✔
153
                        "Created ReleaseBinding for target %s", target.Name)
6✔
154
        }
155

156
        // Update status
157
        original := profile.DeepCopy()
13✔
158
        profile.Status.MatchedTargets = len(targetList.Items)
13✔
159
        if profile.Status.MatchedTargets != original.Status.MatchedTargets {
19✔
160
                if err := r.Status().Update(ctx, profile); err != nil {
6✔
161
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to update Profile status")
×
162
                }
×
163
        }
164

165
        return ctrl.Result{}, nil
13✔
166
}
167

168
// SetupWithManager sets up the controller with the Manager.
169
func (r *ProfileReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
170
        return ctrl.NewControllerManagedBy(mgr).
1✔
171
                For(&solarv1alpha1.Profile{}).
1✔
172
                Owns(&solarv1alpha1.ReleaseBinding{}).
1✔
173
                Watches(
1✔
174
                        &solarv1alpha1.Target{},
1✔
175
                        handler.EnqueueRequestsFromMapFunc(r.mapTargetToProfiles),
1✔
176
                ).
1✔
177
                Complete(r)
1✔
178
}
1✔
179

180
// mapTargetToProfiles maps a Target to all Profiles in the same namespace that might match it.
181
func (r *ProfileReconciler) mapTargetToProfiles(ctx context.Context, obj client.Object) []reconcile.Request {
136✔
182
        log := ctrl.LoggerFrom(ctx)
136✔
183

136✔
184
        target, ok := obj.(*solarv1alpha1.Target)
136✔
185
        if !ok {
136✔
186
                return nil
×
187
        }
×
188

189
        profileList := &solarv1alpha1.ProfileList{}
136✔
190
        if err := r.List(ctx, profileList, client.InNamespace(target.Namespace)); err != nil {
136✔
191
                log.Error(err, "failed to list Profiles for Target mapping")
×
192

×
193
                return nil
×
194
        }
×
195

196
        targetLabels := labels.Set(target.Labels)
136✔
197
        var requests []reconcile.Request
136✔
198

136✔
199
        for _, profile := range profileList.Items {
187✔
200
                selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
51✔
201
                if err != nil {
51✔
202
                        continue
×
203
                }
204

205
                if selector.Matches(targetLabels) {
90✔
206
                        requests = append(requests, reconcile.Request{
39✔
207
                                NamespacedName: client.ObjectKeyFromObject(&profile),
39✔
208
                        })
39✔
209
                }
39✔
210
        }
211

212
        return requests
136✔
213
}
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