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

opendefensecloud / solution-arsenal / 25343901139

04 May 2026 09:14PM UTC coverage: 70.607% (-2.1%) from 72.737%
25343901139

push

github

web-flow
feat: poc implementation resource grants for common use cases (#474)

## What
Implements a ResourceGrant CRD enabling three cross-namespace reference
patterns: Profile→Target, Target→Registry, and Release→ComponentVersion
Closes #314

## Testing
Integration and e2e Tests were added

## Notes for reviewers
- New CRD: ResourceGrant
- ReleaseSpec gains componentVersionNamespace (optional string).
Same-namespace behaviour is unchanged.
- TargetSpec gains renderRegistryNamespace (optional string).
Same-namespace behaviour is unchanged.


## Checklist
- [x] Tests added/updated
- [x] No breaking changes (or upgrade path documented above)
- [x] Readable commit history (squashed and cleaned up as desired)
- [x] AI code review considered and comments resolved


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## New Features

- Added `ResourceGrant` API resource to authorize cross-namespace
resource access
- Releases can now resolve ComponentVersions from different namespaces
- ReleaseBindings can target Targets in different namespaces
- Targets can reference render Registries from different namespaces
- Profile matching now supports selecting Targets across namespaces

## Documentation

- Updated API reference with `ResourceGrant` specification and new
namespace field documentation

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

214 of 372 new or added lines in 4 files covered. (57.53%)

17 existing lines in 2 files now uncovered.

2258 of 3198 relevant lines covered (70.61%)

42.52 hits per line

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

80.14
/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=core,resources=events,verbs=create;patch
46
//+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch
47

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

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

25✔
55
        if r.WatchNamespace != "" && req.Namespace != r.WatchNamespace {
26✔
56
                return ctrlResult, nil
1✔
57
        }
1✔
58

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

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

69
        cvNamespace := res.Namespace
21✔
70
        if res.Spec.ComponentVersionNamespace != "" {
29✔
71
                cvNamespace = res.Spec.ComponentVersionNamespace
8✔
72
        }
8✔
73

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

94
                        return ctrlResult, nil
4✔
95
                }
96
        }
97

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

119
                        return ctrlResult, nil
5✔
120
                }
121

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

125
        // ComponentVersion found — set resolved condition
126
        changed := apimeta.SetStatusCondition(&res.Status.Conditions, metav1.Condition{
12✔
127
                Type:               ConditionTypeComponentVersionResolved,
12✔
128
                Status:             metav1.ConditionTrue,
12✔
129
                ObservedGeneration: res.Generation,
12✔
130
                Reason:             "Resolved",
12✔
131
                Message:            "ComponentVersion resolved: " + cv.Name,
12✔
132
        })
12✔
133
        if changed {
18✔
134
                if err := r.Status().Update(ctx, res); err != nil {
6✔
135
                        return ctrlResult, errLogAndWrap(log, err, "failed to update status")
×
136
                }
×
137
        }
138

139
        return ctrlResult, nil
12✔
140
}
141

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

155
        return false, nil
4✔
156
}
157

158
// SetupWithManager sets up the controller with the Manager.
159
func (r *ReleaseReconciler) SetupWithManager(mgr ctrl.Manager) error {
1✔
160
        return ctrl.NewControllerManagedBy(mgr).
1✔
161
                For(&solarv1alpha1.Release{}).
1✔
162
                Watches(
1✔
163
                        &solarv1alpha1.ComponentVersion{},
1✔
164
                        handler.EnqueueRequestsFromMapFunc(r.mapComponentVersionToReleases),
1✔
165
                ).
1✔
166
                Watches(
1✔
167
                        &solarv1alpha1.ReferenceGrant{},
1✔
168
                        handler.EnqueueRequestsFromMapFunc(r.mapReferenceGrantToReleases),
1✔
169
                ).
1✔
170
                Complete(r)
1✔
171
}
1✔
172

173
// mapComponentVersionToReleases enqueues all Releases that reference this ComponentVersion.
174
func (r *ReleaseReconciler) mapComponentVersionToReleases(ctx context.Context, obj client.Object) []reconcile.Request {
6✔
175
        log := ctrl.LoggerFrom(ctx)
6✔
176

6✔
177
        releaseList := &solarv1alpha1.ReleaseList{}
6✔
178
        if err := r.List(ctx, releaseList); err != nil {
6✔
NEW
179
                log.Error(err, "failed to list Releases for ComponentVersion mapping")
×
NEW
180

×
NEW
181
                return nil
×
NEW
182
        }
×
183

184
        var requests []reconcile.Request
6✔
185

6✔
186
        for _, rel := range releaseList.Items {
29✔
187
                cvNs := rel.Namespace
23✔
188
                if rel.Spec.ComponentVersionNamespace != "" {
23✔
NEW
189
                        cvNs = rel.Spec.ComponentVersionNamespace
×
NEW
190
                }
×
191
                if rel.Spec.ComponentVersionRef.Name == obj.GetName() && cvNs == obj.GetNamespace() {
23✔
NEW
192
                        requests = append(requests, reconcile.Request{
×
NEW
193
                                NamespacedName: client.ObjectKeyFromObject(&rel),
×
NEW
194
                        })
×
NEW
195
                }
×
196
        }
197

198
        return requests
6✔
199
}
200

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

8✔
206
        grant, ok := obj.(*solarv1alpha1.ReferenceGrant)
8✔
207
        if !ok {
8✔
NEW
208
                return nil
×
NEW
209
        }
×
210

211
        if !grantsComponentVersionResource(grant) {
12✔
212
                return nil
4✔
213
        }
4✔
214

215
        var requests []reconcile.Request
4✔
216

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

×
NEW
225
                        continue
×
226
                }
227
                for _, rel := range releaseList.Items {
5✔
228
                        if rel.Spec.ComponentVersionNamespace == grant.Namespace {
2✔
229
                                requests = append(requests, reconcile.Request{
1✔
230
                                        NamespacedName: client.ObjectKeyFromObject(&rel),
1✔
231
                                })
1✔
232
                        }
1✔
233
                }
234
        }
235

236
        return requests
4✔
237
}
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