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

opendefensecloud / solution-arsenal / 27960013642

22 Jun 2026 02:26PM UTC coverage: 75.403% (-0.1%) from 75.535%
27960013642

push

github

web-flow
fix(deps): update dependencies (patch & digest) (#634)

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) | Type |
Update |
|---|---|---|---|---|---|
|
[github.com/google/go-containerregistry](https://redirect.github.com/google/go-containerregistry)
| `v0.21.6` → `v0.21.7` |
![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgoogle%2fgo-containerregistry/v0.21.7?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgoogle%2fgo-containerregistry/v0.21.6/v0.21.7?slim=true)
| require | patch |
| [node](https://redirect.github.com/nodejs/node) | `f0a08e0` →
`5e8888a` | | | stage | digest |
|
[opendefensecloud/dev-kit](https://redirect.github.com/opendefensecloud/dev-kit)
| `v1.0.10` → `v1.0.11` |
![age](https://developer.mend.io/api/mc/badges/age/github-tags/opendefensecloud%2fdev-kit/v1.0.11?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/opendefensecloud%2fdev-kit/v1.0.10/v1.0.11?slim=true)
| action | patch |
|
[release-drafter/release-drafter](https://redirect.github.com/release-drafter/release-drafter)
([changelog](https://redirect.github.com/release-drafter/release-drafter/compare/693d20e7c..ed4bc48ec))
| `693d20e` → `ed4bc48` | | | action | digest |
|
[softprops/action-gh-release](https://redirect.github.com/softprops/action-gh-release)
([changelog](https://redirect.github.com/softprops/action-gh-release/compare/b43093329..718ea10b1))
| `b430933` → `718ea10` | | | action | digest |

---

### Release Notes

<details>
<summary>google/go-containerregistry
(github.com/google/go-containerregistry)</summary>

###
[`v0.21.7`](https://redirect.github.com/google/go-containerregistry/releases/tag/v0.21.7)

[Compare... (continued)

4019 of 5330 relevant lines covered (75.4%)

51.18 hits per line

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

72.31
/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
        "slices"
10

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

23
        solarv1alpha1 "go.opendefense.cloud/solar/api/solar/v1alpha1"
24
)
25

26
// bindingTargetKey returns a stable namespace/name key for a ReleaseBinding's target reference.
27
func bindingTargetKey(rb *solarv1alpha1.ReleaseBinding) string {
18✔
28
        ns := rb.Spec.TargetNamespace
18✔
29
        if ns == "" {
34✔
30
                ns = rb.Namespace
16✔
31
        }
16✔
32

33
        return ns + "/" + rb.Spec.TargetRef.Name
18✔
34
}
35

36
// targetKey returns the namespace/name key for a Target.
37
func targetKey(t *solarv1alpha1.Target) string {
24✔
38
        return t.Namespace + "/" + t.Name
24✔
39
}
24✔
40

41
// solarGroup is the API group for all solar resources.
42
const solarGroup = "solar.opendefense.cloud"
43

44
// grantPermits returns true if the ReferenceGrant allows a resource identified by
45
// (fromGroup, fromKind, fromNamespace) to reference a resource of (toGroup, toKind)
46
// in the grant's own namespace.
47
func grantPermits(grant *solarv1alpha1.ReferenceGrant, fromGroup, fromKind, fromNamespace, toGroup, toKind string) bool {
8✔
48
        hasFrom := false
8✔
49
        for _, f := range grant.Spec.From {
16✔
50
                if f.Namespace == fromNamespace && f.Kind == fromKind && f.Group == fromGroup {
16✔
51
                        hasFrom = true
8✔
52
                        break
8✔
53
                }
54
        }
55
        if !hasFrom {
8✔
56
                return false
×
57
        }
×
58
        for _, t := range grant.Spec.To {
16✔
59
                if t.Kind == toKind && t.Group == toGroup {
16✔
60
                        return true
8✔
61
                }
8✔
62
        }
63

64
        return false
×
65
}
66

67
// grantPermitsTargetAccess returns true if the ReferenceGrant allows a Profile in
68
// fromNamespace to reference Target resources in the grant's namespace.
69
func grantPermitsTargetAccess(grant *solarv1alpha1.ReferenceGrant, fromNamespace string) bool {
2✔
70
        return grantPermits(grant, solarGroup, "Profile", fromNamespace, solarGroup, "Target")
2✔
71
}
2✔
72

73
// grantsTargetResource returns true if the ReferenceGrant includes Target in its To list.
74
func grantsTargetResource(grant *solarv1alpha1.ReferenceGrant) bool {
49✔
75
        for _, t := range grant.Spec.To {
98✔
76
                if t.Kind == "Target" && t.Group == solarGroup {
94✔
77
                        return true
45✔
78
                }
45✔
79
        }
80

81
        return false
4✔
82
}
83

84
// grantPermitsComponentVersionAccess returns true if the ReferenceGrant allows a Release
85
// in fromNamespace to reference ComponentVersion resources in the grant's namespace.
86
func grantPermitsComponentVersionAccess(grant *solarv1alpha1.ReferenceGrant, fromNamespace string) bool {
6✔
87
        return grantPermits(grant, solarGroup, "Release", fromNamespace, solarGroup, "ComponentVersion")
6✔
88
}
6✔
89

90
// grantsComponentVersionResource returns true if the ReferenceGrant includes ComponentVersion in its To list.
91
func grantsComponentVersionResource(grant *solarv1alpha1.ReferenceGrant) bool {
25✔
92
        for _, t := range grant.Spec.To {
50✔
93
                if t.Kind == "ComponentVersion" && t.Group == solarGroup {
34✔
94
                        return true
9✔
95
                }
9✔
96
        }
97

98
        return false
16✔
99
}
100

101
// ProfileReconciler reconciles a Profile object.
102
// It evaluates the Profile's TargetSelector against all Targets in the namespace
103
// and creates/deletes ReleaseBindings accordingly.
104
// Cross-namespace Targets are included when a ReferenceGrant in the target's namespace
105
// grants the Profile's namespace access to "targets".
106
type ProfileReconciler struct {
107
        client.Client
108
        Scheme   *runtime.Scheme
109
        Recorder events.EventRecorder
110
        // WatchNamespace restricts reconciliation to this namespace.
111
        WatchNamespace string
112
}
113

114
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles,verbs=get;list;watch;update;patch
115
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles/status,verbs=get;update;patch
116
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=profiles/finalizers,verbs=update
117
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releasebindings,verbs=get;list;watch;create;update;patch;delete
118
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releases,verbs=get;list;watch;update;patch
119
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releases/finalizers,verbs=update
120
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=targets,verbs=get;list;watch
121
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=referencegrants,verbs=get;list;watch
122
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
123

124
// Reconcile evaluates the Profile's TargetSelector and ensures matching ReleaseBindings exist.
125
// It also manages a deletion-protection finalizer on the referenced Release.
126
func (r *ProfileReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
92✔
127
        log := ctrl.LoggerFrom(ctx)
92✔
128

92✔
129
        log.V(1).Info("Profile is being reconciled", "req", req)
92✔
130

92✔
131
        if r.WatchNamespace != "" && req.Namespace != r.WatchNamespace {
136✔
132
                return ctrl.Result{}, nil
44✔
133
        }
44✔
134

135
        // Fetch Profile
136
        profile := &solarv1alpha1.Profile{}
48✔
137
        if err := r.Get(ctx, req.NamespacedName, profile); err != nil {
52✔
138
                if apierrors.IsNotFound(err) {
8✔
139
                        return ctrl.Result{}, nil
4✔
140
                }
4✔
141

142
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get Profile")
×
143
        }
144

145
        // Handle deletion.
146
        if !profile.DeletionTimestamp.IsZero() {
54✔
147
                // Block until all owned ReleaseBindings are fully gone from the API before unprotecting
10✔
148
                // the Release. This ensures the Release is never deletable while bindings still reference it.
10✔
149
                // The Owns() watch in SetupWithManager re-triggers this reconcile when each binding is removed.
10✔
150
                allBindings := &solarv1alpha1.ReleaseBindingList{}
10✔
151
                if err := r.List(ctx, allBindings, client.InNamespace(profile.Namespace)); err != nil {
10✔
152
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to list owned ReleaseBindings for deletion")
×
153
                }
×
154
                ownedBindings := &solarv1alpha1.ReleaseBindingList{}
10✔
155
                for i := range allBindings.Items {
16✔
156
                        if metav1.IsControlledBy(&allBindings.Items[i], profile) {
12✔
157
                                ownedBindings.Items = append(ownedBindings.Items, allBindings.Items[i])
6✔
158
                        }
6✔
159
                }
160

161
                var ownedExist bool
10✔
162
                for i := range ownedBindings.Items {
16✔
163
                        rb := &ownedBindings.Items[i]
6✔
164
                        ownedExist = true
6✔
165
                        if rb.DeletionTimestamp.IsZero() {
8✔
166
                                if err := r.Delete(ctx, rb); err != nil && !apierrors.IsNotFound(err) {
2✔
167
                                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to delete owned ReleaseBinding during Profile deletion")
×
168
                                }
×
169
                        }
170
                }
171
                if ownedExist {
16✔
172
                        // Re-triggered by Owns() watch when the last binding is fully removed.
6✔
173
                        return ctrl.Result{}, nil
6✔
174
                }
6✔
175

176
                if profile.Spec.ReleaseRef.Name != "" {
8✔
177
                        release := &solarv1alpha1.Release{}
4✔
178
                        if err := r.Get(ctx, types.NamespacedName{Name: profile.Spec.ReleaseRef.Name, Namespace: profile.Namespace}, release); err != nil {
4✔
179
                                if !apierrors.IsNotFound(err) {
×
180
                                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to get Release for finalizer cleanup")
×
181
                                }
×
182
                        } else if err := r.removeReleaseRefFinalizerIfUnreferenced(ctx, profile, release); err != nil {
4✔
183
                                return ctrl.Result{}, err
×
184
                        }
×
185
                }
186

187
                if slices.Contains(profile.Finalizers, profileFinalizer) {
8✔
188
                        latest := &solarv1alpha1.Profile{}
4✔
189
                        if err := r.Get(ctx, req.NamespacedName, latest); err != nil {
4✔
190
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get latest Profile for finalizer removal")
×
191
                        }
×
192
                        original := latest.DeepCopy()
4✔
193
                        latest.Finalizers = slices.DeleteFunc(latest.Finalizers, func(s string) bool { return s == profileFinalizer })
8✔
194
                        if err := r.Patch(ctx, latest, client.MergeFrom(original)); err != nil {
4✔
195
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to remove finalizer from Profile")
×
196
                        }
×
197
                }
198

199
                return ctrl.Result{}, nil
4✔
200
        }
201

202
        // Ensure self-finalizer exists.
203
        if !slices.Contains(profile.Finalizers, profileFinalizer) {
46✔
204
                latest := &solarv1alpha1.Profile{}
12✔
205
                if err := r.Get(ctx, req.NamespacedName, latest); err != nil {
12✔
206
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to get latest Profile for finalizer addition")
×
207
                }
×
208
                if !slices.Contains(latest.Finalizers, profileFinalizer) {
24✔
209
                        original := latest.DeepCopy()
12✔
210
                        latest.Finalizers = append(latest.Finalizers, profileFinalizer)
12✔
211
                        if err := r.Patch(ctx, latest, client.MergeFrom(original)); err != nil {
12✔
212
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to add finalizer to Profile")
×
213
                        }
×
214
                }
215
        }
216

217
        // Protect the referenced Release from deletion.
218
        if profile.Spec.ReleaseRef.Name != "" {
68✔
219
                release := &solarv1alpha1.Release{}
34✔
220
                if err := r.Get(ctx, types.NamespacedName{Name: profile.Spec.ReleaseRef.Name, Namespace: profile.Namespace}, release); err != nil {
53✔
221
                        if !apierrors.IsNotFound(err) {
19✔
222
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to get Release for protection finalizer")
×
223
                        }
×
224
                } else if !slices.Contains(release.Finalizers, releaseRefFinalizer) {
22✔
225
                        latest := release.DeepCopy()
7✔
226
                        latest.Finalizers = append(latest.Finalizers, releaseRefFinalizer)
7✔
227
                        if err := r.Patch(ctx, latest, client.MergeFromWithOptions(release, client.MergeFromWithOptimisticLock{})); err != nil {
9✔
228
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to add protection finalizer to Release")
2✔
229
                        }
2✔
230
                }
231
        }
232

233
        // Evaluate TargetSelector against all Targets
234
        selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
32✔
235
        if err != nil {
32✔
236
                log.Error(err, "invalid targetSelector in Profile")
×
237

×
238
                return ctrl.Result{}, nil
×
239
        }
×
240

241
        // Collect matching targets from the profile's own namespace
242
        sameNsTargets := &solarv1alpha1.TargetList{}
32✔
243
        if err := r.List(ctx, sameNsTargets,
32✔
244
                client.InNamespace(profile.Namespace),
32✔
245
                client.MatchingLabelsSelector{Selector: selector},
32✔
246
        ); err != nil {
32✔
247
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to list Targets")
×
248
        }
×
249

250
        allTargets := make([]solarv1alpha1.Target, 0, len(sameNsTargets.Items))
32✔
251
        allTargets = append(allTargets, sameNsTargets.Items...)
32✔
252

32✔
253
        // Collect cross-namespace targets via ReferenceGrants.
32✔
254
        // A ReferenceGrant in namespace B listing the profile's namespace in From and
32✔
255
        // "targets" in To allows this Profile to select Targets from namespace B.
32✔
256
        //
32✔
257
        // FIXME: listing all ReferenceGrants cluster-wide on every reconcile is a cache
32✔
258
        // scan only (no etcd round-trip, no host-cluster impact), but may become a
32✔
259
        // bottleneck at scale. Consider adding a field index on ReferenceGrants keyed by
32✔
260
        // the namespaces they grant access to so we can filter server-side.
32✔
261
        grantList := &solarv1alpha1.ReferenceGrantList{}
32✔
262
        if err := r.List(ctx, grantList); err != nil {
32✔
263
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to list ReferenceGrants")
×
264
        }
×
265

266
        for i := range grantList.Items {
34✔
267
                grant := &grantList.Items[i]
2✔
268
                if grant.Namespace == profile.Namespace {
2✔
269
                        // same-namespace targets already covered above
×
270
                        continue
×
271
                }
272
                if !grantPermitsTargetAccess(grant, profile.Namespace) {
2✔
273
                        continue
×
274
                }
275
                crossNsTargets := &solarv1alpha1.TargetList{}
2✔
276
                if err := r.List(ctx, crossNsTargets,
2✔
277
                        client.InNamespace(grant.Namespace),
2✔
278
                        client.MatchingLabelsSelector{Selector: selector},
2✔
279
                ); err != nil {
2✔
280
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to list cross-namespace Targets in "+grant.Namespace)
×
281
                }
×
282
                allTargets = append(allTargets, crossNsTargets.Items...)
2✔
283
        }
284

285
        // Build set of desired ReleaseBindings (one per matching target, keyed by namespace/name)
286
        desiredTargets := map[string]solarv1alpha1.Target{}
32✔
287
        for _, t := range allTargets {
56✔
288
                desiredTargets[targetKey(&t)] = t
24✔
289
        }
24✔
290

291
        // List existing ReleaseBindings owned by this Profile
292
        allBindings := &solarv1alpha1.ReleaseBindingList{}
32✔
293
        if err := r.List(ctx, allBindings, client.InNamespace(profile.Namespace)); err != nil {
32✔
294
                return ctrl.Result{}, errLogAndWrap(log, err, "failed to list ReleaseBindings")
×
295
        }
×
296
        existingBindings := &solarv1alpha1.ReleaseBindingList{}
32✔
297
        for i := range allBindings.Items {
50✔
298
                if metav1.IsControlledBy(&allBindings.Items[i], profile) {
36✔
299
                        existingBindings.Items = append(existingBindings.Items, allBindings.Items[i])
18✔
300
                }
18✔
301
        }
302

303
        // Delete ReleaseBindings for targets that no longer match
304
        existingByKey := map[string]*solarv1alpha1.ReleaseBinding{}
32✔
305
        for i := range existingBindings.Items {
50✔
306
                rb := &existingBindings.Items[i]
18✔
307
                key := bindingTargetKey(rb)
18✔
308
                existingByKey[key] = rb
18✔
309

18✔
310
                if _, desired := desiredTargets[key]; !desired {
22✔
311
                        log.V(1).Info("Deleting ReleaseBinding for unmatched target", "key", key)
4✔
312
                        if err := r.Delete(ctx, rb); err != nil && !apierrors.IsNotFound(err) {
4✔
313
                                return ctrl.Result{}, errLogAndWrap(log, err, "failed to delete ReleaseBinding")
×
314
                        }
×
315

316
                        r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Deleted", "Delete",
4✔
317
                                "Deleted ReleaseBinding for target %s", key)
4✔
318
                }
319
        }
320

321
        // Create ReleaseBindings for new matching targets
322
        for key, target := range desiredTargets {
56✔
323
                if _, exists := existingByKey[key]; exists {
38✔
324
                        continue
14✔
325
                }
326

327
                crossNs := ""
10✔
328
                if target.Namespace != profile.Namespace {
12✔
329
                        crossNs = target.Namespace
2✔
330
                }
2✔
331

332
                rb := &solarv1alpha1.ReleaseBinding{
10✔
333
                        ObjectMeta: metav1.ObjectMeta{
10✔
334
                                // We need to truncated the name: 57 (input) + 1 (-) + 5 (appended by generated) = 63 (max chars allowed)
10✔
335
                                GenerateName: truncateName(fmt.Sprintf("%s-%s", profile.Name, target.Name), 57) + "-",
10✔
336
                                Namespace:    profile.Namespace,
10✔
337
                        },
10✔
338
                        Spec: solarv1alpha1.ReleaseBindingSpec{
10✔
339
                                TargetRef:       corev1.LocalObjectReference{Name: target.Name},
10✔
340
                                TargetNamespace: crossNs,
10✔
341
                                ReleaseRef:      profile.Spec.ReleaseRef,
10✔
342
                        },
10✔
343
                }
10✔
344
                if err := ctrl.SetControllerReference(profile, rb, r.Scheme); err != nil {
10✔
345
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to set controller reference on ReleaseBinding")
×
346
                }
×
347

348
                if err := r.Create(ctx, rb); err != nil {
10✔
349
                        if apierrors.IsAlreadyExists(err) {
×
350
                                continue
×
351
                        }
352

353
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to create ReleaseBinding")
×
354
                }
355

356
                log.V(1).Info("Created ReleaseBinding for target", "key", key)
10✔
357
                r.Recorder.Eventf(profile, nil, corev1.EventTypeNormal, "Created", "Create",
10✔
358
                        "Created ReleaseBinding for target %s", key)
10✔
359
        }
360

361
        // Update status
362
        original := profile.DeepCopy()
32✔
363
        profile.Status.MatchedTargets = len(desiredTargets)
32✔
364
        if profile.Status.MatchedTargets != original.Status.MatchedTargets {
48✔
365
                if err := r.Status().Update(ctx, profile); err != nil {
25✔
366
                        return ctrl.Result{}, errLogAndWrap(log, err, "failed to update Profile status")
9✔
367
                }
9✔
368
        }
369

370
        return ctrl.Result{}, nil
23✔
371
}
372

373
// SetupWithManager sets up the controller with the Manager.
374
func (r *ProfileReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
375
        return ctrl.NewControllerManagedBy(mgr).
1✔
376
                For(&solarv1alpha1.Profile{}).
1✔
377
                Owns(&solarv1alpha1.ReleaseBinding{}).
1✔
378
                Watches(
1✔
379
                        &solarv1alpha1.Target{},
1✔
380
                        handler.EnqueueRequestsFromMapFunc(r.mapTargetToProfiles),
1✔
381
                ).
1✔
382
                Watches(
1✔
383
                        &solarv1alpha1.ReferenceGrant{},
1✔
384
                        handler.EnqueueRequestsFromMapFunc(r.mapReferenceGrantToProfiles),
1✔
385
                ).
1✔
386
                Complete(r)
1✔
387
}
1✔
388

389
// mapTargetToProfiles maps a Target to all Profiles that might match it,
390
// including Profiles in namespaces that have been granted access via ReferenceGrant.
391
func (r *ProfileReconciler) mapTargetToProfiles(ctx context.Context, obj client.Object) []reconcile.Request {
413✔
392
        log := ctrl.LoggerFrom(ctx)
413✔
393

413✔
394
        target, ok := obj.(*solarv1alpha1.Target)
413✔
395
        if !ok {
413✔
396
                return nil
×
397
        }
×
398

399
        targetLabels := labels.Set(target.Labels)
413✔
400
        var requests []reconcile.Request
413✔
401

413✔
402
        // Enqueue profiles in the target's own namespace
413✔
403
        profileList := &solarv1alpha1.ProfileList{}
413✔
404
        if err := r.List(ctx, profileList, client.InNamespace(target.Namespace)); err != nil {
413✔
405
                log.Error(err, "failed to list Profiles for Target mapping")
×
406

×
407
                return nil
×
408
        }
×
409

410
        for _, profile := range profileList.Items {
466✔
411
                selector, err := metav1.LabelSelectorAsSelector(&profile.Spec.TargetSelector)
53✔
412
                if err != nil {
53✔
413
                        continue
×
414
                }
415

416
                if selector.Matches(targetLabels) {
95✔
417
                        requests = append(requests, reconcile.Request{
42✔
418
                                NamespacedName: client.ObjectKeyFromObject(&profile),
42✔
419
                        })
42✔
420
                }
42✔
421
        }
422

423
        // Enqueue profiles in namespaces that have been granted access to targets in
424
        // this target's namespace via a ReferenceGrant.
425
        grantList := &solarv1alpha1.ReferenceGrantList{}
413✔
426
        if err := r.List(ctx, grantList, client.InNamespace(target.Namespace)); err != nil {
413✔
427
                log.Error(err, "failed to list ReferenceGrants for cross-namespace Target mapping")
×
428

×
429
                return requests
×
430
        }
×
431

432
        for i := range grantList.Items {
450✔
433
                grant := &grantList.Items[i]
37✔
434
                if !grantsTargetResource(grant) {
37✔
435
                        continue
×
436
                }
437
                for _, from := range grant.Spec.From {
74✔
438
                        if from.Namespace == target.Namespace || from.Kind != "Profile" {
74✔
439
                                continue
37✔
440
                        }
441
                        fromProfiles := &solarv1alpha1.ProfileList{}
×
442
                        if err := r.List(ctx, fromProfiles, client.InNamespace(from.Namespace)); err != nil {
×
443
                                log.Error(err, "failed to list Profiles in granted namespace", "namespace", from.Namespace)
×
444
                                continue
×
445
                        }
446
                        for _, p := range fromProfiles.Items {
×
447
                                selector, err := metav1.LabelSelectorAsSelector(&p.Spec.TargetSelector)
×
448
                                if err != nil {
×
449
                                        continue
×
450
                                }
451
                                if selector.Matches(targetLabels) {
×
452
                                        requests = append(requests, reconcile.Request{
×
453
                                                NamespacedName: client.ObjectKeyFromObject(&p),
×
454
                                        })
×
455
                                }
×
456
                        }
457
                }
458
        }
459

460
        return requests
413✔
461
}
462

463
// mapReferenceGrantToProfiles enqueues all Profiles in the namespaces listed in
464
// a ReferenceGrant's From field, allowing them to re-evaluate cross-namespace matches.
465
func (r *ProfileReconciler) mapReferenceGrantToProfiles(ctx context.Context, obj client.Object) []reconcile.Request {
12✔
466
        log := ctrl.LoggerFrom(ctx)
12✔
467

12✔
468
        grant, ok := obj.(*solarv1alpha1.ReferenceGrant)
12✔
469
        if !ok {
12✔
470
                return nil
×
471
        }
×
472

473
        if !grantsTargetResource(grant) {
16✔
474
                return nil
4✔
475
        }
4✔
476

477
        var requests []reconcile.Request
8✔
478
        for _, from := range grant.Spec.From {
16✔
479
                if from.Kind != "Profile" || from.Group != solarGroup {
12✔
480
                        continue
4✔
481
                }
482
                profiles := &solarv1alpha1.ProfileList{}
4✔
483
                if err := r.List(ctx, profiles, client.InNamespace(from.Namespace)); err != nil {
4✔
484
                        log.Error(err, "failed to list Profiles for ReferenceGrant mapping", "namespace", from.Namespace)
×
485
                        continue
×
486
                }
487
                for _, p := range profiles.Items {
5✔
488
                        requests = append(requests, reconcile.Request{
1✔
489
                                NamespacedName: client.ObjectKeyFromObject(&p),
1✔
490
                        })
1✔
491
                }
1✔
492
        }
493

494
        return requests
8✔
495
}
496

497
// removeReleaseRefFinalizerIfUnreferenced removes releaseRefFinalizer from release when no active
498
// Profile or ReleaseBinding (excluding the deleting Profile and its owned ReleaseBindings) still
499
// references it.
500
func (r *ProfileReconciler) removeReleaseRefFinalizerIfUnreferenced(ctx context.Context, deletingProfile *solarv1alpha1.Profile, release *solarv1alpha1.Release) error {
4✔
501
        if !slices.Contains(release.Finalizers, releaseRefFinalizer) {
4✔
502
                return nil
×
503
        }
×
504

505
        // Count Profiles (excluding self) referencing this Release.
506
        profileList := &solarv1alpha1.ProfileList{}
4✔
507
        if err := r.List(ctx, profileList,
4✔
508
                client.InNamespace(release.Namespace),
4✔
509
                client.MatchingFields{indexProfileByReleaseName: release.Name},
4✔
510
        ); err != nil {
4✔
511
                return errLogAndWrap(ctrl.LoggerFrom(ctx), err, "failed to list Profiles for Release finalizer check")
×
512
        }
×
513

514
        for _, p := range profileList.Items {
8✔
515
                if p.Name == deletingProfile.Name {
8✔
516
                        continue
4✔
517
                }
518
                if !p.DeletionTimestamp.IsZero() {
×
519
                        continue
×
520
                }
521

522
                return nil
×
523
        }
524

525
        // Count ReleaseBindings (excluding those owned by the deleting Profile) referencing this Release.
526
        bindingList := &solarv1alpha1.ReleaseBindingList{}
4✔
527
        if err := r.List(ctx, bindingList,
4✔
528
                client.InNamespace(release.Namespace),
4✔
529
                client.MatchingFields{indexReleaseBindingReleaseName: release.Name},
4✔
530
        ); err != nil {
4✔
531
                return errLogAndWrap(ctrl.LoggerFrom(ctx), err, "failed to list ReleaseBindings for Release finalizer check")
×
532
        }
×
533

534
        for _, rb := range bindingList.Items {
4✔
535
                if metav1.IsControlledBy(&rb, deletingProfile) {
×
536
                        continue // owned by the Profile being deleted; K8s GC will remove these
×
537
                }
538
                if !rb.DeletionTimestamp.IsZero() {
×
539
                        continue
×
540
                }
541

542
                // Check if this binding's owner Profile is also being deleted (concurrent deletion).
543
                ownerRef := metav1.GetControllerOf(&rb)
×
544
                if ownerRef != nil && ownerRef.Kind == "Profile" && ownerRef.APIVersion == solarv1alpha1.SchemeGroupVersion.String() {
×
545
                        ownerProfile := &solarv1alpha1.Profile{}
×
546
                        err := r.Get(ctx, types.NamespacedName{Name: ownerRef.Name, Namespace: rb.Namespace}, ownerProfile)
×
547
                        if apierrors.IsNotFound(err) || (err == nil && !ownerProfile.DeletionTimestamp.IsZero()) {
×
548
                                continue // owner Profile is gone or being deleted, this binding will be GC'd
×
549
                        }
550
                        if err != nil {
×
551
                                return errLogAndWrap(ctrl.LoggerFrom(ctx), err, "failed to check owner Profile for concurrent deletion")
×
552
                        }
×
553
                }
554

555
                return nil
×
556
        }
557

558
        freshRelease := &solarv1alpha1.Release{}
4✔
559
        if err := r.Get(ctx, client.ObjectKeyFromObject(release), freshRelease); err != nil {
4✔
560
                if apierrors.IsNotFound(err) {
×
561
                        return nil
×
562
                }
×
563

564
                return errLogAndWrap(ctrl.LoggerFrom(ctx), err, "failed to get latest Release for finalizer removal")
×
565
        }
566
        original := freshRelease.DeepCopy()
4✔
567
        freshRelease.Finalizers = slices.DeleteFunc(freshRelease.Finalizers, func(s string) bool { return s == releaseRefFinalizer })
11✔
568
        if err := r.Patch(ctx, freshRelease, client.MergeFromWithOptions(original, client.MergeFromWithOptimisticLock{})); err != nil {
4✔
569
                return errLogAndWrap(ctrl.LoggerFrom(ctx), err, "failed to remove protection finalizer from Release")
×
570
        }
×
571

572
        ctrl.LoggerFrom(ctx).V(1).Info("Removed protection finalizer from Release", "release", release.Name)
4✔
573

4✔
574
        return nil
4✔
575
}
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