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

opendefensecloud / solution-arsenal / 26082569265

19 May 2026 07:22AM UTC coverage: 72.298% (-0.2%) from 72.542%
26082569265

push

github

web-flow
chore(deps): update module ginkgo to v2.29.0 (#527)

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [ginkgo](https://redirect.github.com/onsi/ginkgo) | `v2.28.3` →
`v2.29.0` |
![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fonsi%2fginkgo%2fv2%2fginkgo/v2.29.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fonsi%2fginkgo%2fv2%2fginkgo/v2.28.3/v2.29.0?slim=true)
|

---

### Release Notes

<details>
<summary>onsi/ginkgo (ginkgo)</summary>

###
[`v2.29.0`](https://redirect.github.com/onsi/ginkgo/releases/tag/v2.29.0)

[Compare
Source](https://redirect.github.com/onsi/ginkgo/compare/v2.28.3...v2.29.0)

#### 2.29.0

`GinkgoHelperGo` makes it easier to write test helpers that need to run
in goroutines. Specifically, it makes managing the failure state and
capturing failure panics correctly straightforward.

`ginkgo outline` now includes entries defined in `DescribeTableSubtree`

</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:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzkuMyIsInVwZGF0ZWRJblZlciI6IjQzLjE4Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

2375 of 3285 relevant lines covered (72.3%)

22.2 hits per line

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

80.95
/pkg/controller/release_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

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

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

23
const (
24
        ConditionTypeComponentVersionResolved = "ComponentVersionResolved"
25
)
26

27
// ReleaseReconciler reconciles a Release object.
28
// It validates that the referenced ComponentVersion exists and sets status conditions.
29
// Rendering is handled by the Target controller.
30
type ReleaseReconciler struct {
31
        client.Client
32
        Scheme   *runtime.Scheme
33
        Recorder events.EventRecorder
34
        // WatchNamespace restricts reconciliation to this namespace.
35
        // Should be empty in production (watches all namespaces).
36
        // Intended for use in integration tests only.
37
        // See: https://book.kubebuilder.io/reference/envtest#testing-considerations
38
        WatchNamespace string
39
}
40

41
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releases,verbs=get;list;watch;create;update;patch;delete
42
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=releases/status,verbs=get;update;patch
43
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=componentversions,verbs=get;list;watch
44
//+kubebuilder:rbac:groups=solar.opendefense.cloud,resources=referencegrants,verbs=get;list;watch
45
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
46

47
// Reconcile validates the Release by resolving its ComponentVersion reference.
48
func (r *ReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
43✔
49
        log := ctrl.LoggerFrom(ctx)
43✔
50
        ctrlResult := ctrl.Result{}
43✔
51

43✔
52
        log.V(1).Info("Release is being reconciled", "req", req)
43✔
53

43✔
54
        if r.WatchNamespace != "" && req.Namespace != r.WatchNamespace {
47✔
55
                return ctrlResult, nil
4✔
56
        }
4✔
57

58
        // Fetch the Release instance
59
        res := &solarv1alpha1.Release{}
39✔
60
        if err := r.Get(ctx, req.NamespacedName, res); err != nil {
42✔
61
                if apierrors.IsNotFound(err) {
6✔
62
                        return ctrlResult, nil
3✔
63
                }
3✔
64

65
                return ctrlResult, errLogAndWrap(log, err, "failed to get object")
×
66
        }
67

68
        cvNamespace := res.Namespace
36✔
69
        if res.Spec.ComponentVersionNamespace != "" {
43✔
70
                cvNamespace = res.Spec.ComponentVersionNamespace
7✔
71
        }
7✔
72

73
        // For cross-namespace references, verify a ReferenceGrant permits it.
74
        if cvNamespace != res.Namespace {
43✔
75
                granted, err := r.componentVersionGranted(ctx, res, cvNamespace)
7✔
76
                if err != nil {
7✔
77
                        return ctrlResult, errLogAndWrap(log, err, "failed to check ReferenceGrant for cross-namespace ComponentVersion")
×
78
                }
×
79
                if !granted {
10✔
80
                        changed := apimeta.SetStatusCondition(&res.Status.Conditions, metav1.Condition{
3✔
81
                                Type:               ConditionTypeComponentVersionResolved,
3✔
82
                                Status:             metav1.ConditionFalse,
3✔
83
                                ObservedGeneration: res.Generation,
3✔
84
                                Reason:             "NotGranted",
3✔
85
                                Message:            "no ReferenceGrant permits access to ComponentVersion in namespace " + cvNamespace,
3✔
86
                        })
3✔
87
                        if changed {
5✔
88
                                if err := r.Status().Update(ctx, res); err != nil {
2✔
89
                                        return ctrlResult, errLogAndWrap(log, err, "failed to update status")
×
90
                                }
×
91
                        }
92

93
                        return ctrlResult, nil
3✔
94
                }
95
        }
96

97
        // Resolve ComponentVersion
98
        cvRef := types.NamespacedName{
33✔
99
                Name:      res.Spec.ComponentVersionRef.Name,
33✔
100
                Namespace: cvNamespace,
33✔
101
        }
33✔
102
        cv := &solarv1alpha1.ComponentVersion{}
33✔
103
        if err := r.Get(ctx, cvRef, cv); err != nil {
36✔
104
                if apierrors.IsNotFound(err) {
6✔
105
                        changed := apimeta.SetStatusCondition(&res.Status.Conditions, metav1.Condition{
3✔
106
                                Type:               ConditionTypeComponentVersionResolved,
3✔
107
                                Status:             metav1.ConditionFalse,
3✔
108
                                ObservedGeneration: res.Generation,
3✔
109
                                Reason:             "NotFound",
3✔
110
                                Message:            "ComponentVersion not found: " + res.Spec.ComponentVersionRef.Name,
3✔
111
                        })
3✔
112
                        if changed {
5✔
113
                                if err := r.Status().Update(ctx, res); err != nil {
2✔
114
                                        return ctrlResult, errLogAndWrap(log, err, "failed to update status")
×
115
                                }
×
116
                        }
117

118
                        return ctrlResult, nil
3✔
119
                }
120

121
                return ctrlResult, errLogAndWrap(log, err, "failed to get ComponentVersion")
×
122
        }
123

124
        // ComponentVersion found — set resolved condition and effective unique name.
125
        effectiveUniqueName := res.Spec.UniqueName
30✔
126
        if effectiveUniqueName == "" {
32✔
127
                effectiveUniqueName = cv.Spec.ComponentRef.Name
2✔
128
        }
2✔
129

130
        condChanged := apimeta.SetStatusCondition(&res.Status.Conditions, metav1.Condition{
30✔
131
                Type:               ConditionTypeComponentVersionResolved,
30✔
132
                Status:             metav1.ConditionTrue,
30✔
133
                ObservedGeneration: res.Generation,
30✔
134
                Reason:             "Resolved",
30✔
135
                Message:            "ComponentVersion resolved: " + cv.Name,
30✔
136
        })
30✔
137
        nameChanged := res.Status.EffectiveUniqueName != effectiveUniqueName
30✔
138
        if condChanged || nameChanged {
45✔
139
                res.Status.EffectiveUniqueName = effectiveUniqueName
15✔
140
                if err := r.Status().Update(ctx, res); err != nil {
15✔
141
                        return ctrlResult, errLogAndWrap(log, err, "failed to update status")
×
142
                }
×
143
        }
144

145
        return ctrlResult, nil
30✔
146
}
147

148
// componentVersionGranted returns true if a ReferenceGrant in cvNamespace permits
149
// the given Release to reference a ComponentVersion there.
150
func (r *ReleaseReconciler) componentVersionGranted(ctx context.Context, release *solarv1alpha1.Release, cvNamespace string) (bool, error) {
7✔
151
        grantList := &solarv1alpha1.ReferenceGrantList{}
7✔
152
        if err := r.List(ctx, grantList, client.InNamespace(cvNamespace)); err != nil {
7✔
153
                return false, err
×
154
        }
×
155
        for i := range grantList.Items {
11✔
156
                if grantPermitsComponentVersionAccess(&grantList.Items[i], release.Namespace) {
8✔
157
                        return true, nil
4✔
158
                }
4✔
159
        }
160

161
        return false, nil
3✔
162
}
163

164
// SetupWithManager sets up the controller with the Manager.
165
func (r *ReleaseReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
166
        return ctrl.NewControllerManagedBy(mgr).
1✔
167
                For(&solarv1alpha1.Release{}).
1✔
168
                Watches(
1✔
169
                        &solarv1alpha1.ComponentVersion{},
1✔
170
                        handler.EnqueueRequestsFromMapFunc(r.mapComponentVersionToReleases),
1✔
171
                ).
1✔
172
                Watches(
1✔
173
                        &solarv1alpha1.ReferenceGrant{},
1✔
174
                        handler.EnqueueRequestsFromMapFunc(r.mapReferenceGrantToReleases),
1✔
175
                ).
1✔
176
                Complete(r)
1✔
177
}
1✔
178

179
// mapComponentVersionToReleases enqueues all Releases that reference this ComponentVersion.
180
func (r *ReleaseReconciler) mapComponentVersionToReleases(ctx context.Context, obj client.Object) []reconcile.Request {
12✔
181
        log := ctrl.LoggerFrom(ctx)
12✔
182

12✔
183
        releaseList := &solarv1alpha1.ReleaseList{}
12✔
184
        if err := r.List(ctx, releaseList); err != nil {
12✔
185
                log.Error(err, "failed to list Releases for ComponentVersion mapping")
×
186

×
187
                return nil
×
188
        }
×
189

190
        var requests []reconcile.Request
12✔
191

12✔
192
        for _, rel := range releaseList.Items {
112✔
193
                cvNs := rel.Namespace
100✔
194
                if rel.Spec.ComponentVersionNamespace != "" {
100✔
195
                        cvNs = rel.Spec.ComponentVersionNamespace
×
196
                }
×
197
                if rel.Spec.ComponentVersionRef.Name == obj.GetName() && cvNs == obj.GetNamespace() {
100✔
198
                        requests = append(requests, reconcile.Request{
×
199
                                NamespacedName: client.ObjectKeyFromObject(&rel),
×
200
                        })
×
201
                }
×
202
        }
203

204
        return requests
12✔
205
}
206

207
// mapReferenceGrantToReleases enqueues Releases whose cross-namespace ComponentVersion
208
// reference is covered by the changed ReferenceGrant.
209
func (r *ReleaseReconciler) mapReferenceGrantToReleases(ctx context.Context, obj client.Object) []reconcile.Request {
8✔
210
        log := ctrl.LoggerFrom(ctx)
8✔
211

8✔
212
        grant, ok := obj.(*solarv1alpha1.ReferenceGrant)
8✔
213
        if !ok {
8✔
214
                return nil
×
215
        }
×
216

217
        if !grantsComponentVersionResource(grant) {
12✔
218
                return nil
4✔
219
        }
4✔
220

221
        var requests []reconcile.Request
4✔
222

4✔
223
        for _, from := range grant.Spec.From {
8✔
224
                if from.Kind != "Release" || from.Group != solarGroup {
4✔
225
                        continue
×
226
                }
227
                releaseList := &solarv1alpha1.ReleaseList{}
4✔
228
                if err := r.List(ctx, releaseList, client.InNamespace(from.Namespace)); err != nil {
4✔
229
                        log.Error(err, "failed to list Releases for ReferenceGrant mapping", "namespace", from.Namespace)
×
230

×
231
                        continue
×
232
                }
233
                for _, rel := range releaseList.Items {
5✔
234
                        if rel.Spec.ComponentVersionNamespace == grant.Namespace {
2✔
235
                                requests = append(requests, reconcile.Request{
1✔
236
                                        NamespacedName: client.ObjectKeyFromObject(&rel),
1✔
237
                                })
1✔
238
                        }
1✔
239
                }
240
        }
241

242
        return requests
4✔
243
}
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