Skip to content

Commit 1b6ff4c

Browse files
authored
Discover private CatalogSource only if no catalog cluster permission exists (#1099)
* read catalogsource permission only for non-private ctrsource Signed-off-by: YuChen <[email protected]> * add test case for checkResAuth function in manager.go Signed-off-by: YuChen <[email protected]> * add create mock test or ODLMoperator Signed-off-by: YuChen <[email protected]> * update test case Signed-off-by: YuChen <[email protected]> --------- Signed-off-by: YuChen <[email protected]>
1 parent 5667aa0 commit 1b6ff4c

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

controllers/operator/manager.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
2828
"github.com/pkg/errors"
2929
"golang.org/x/mod/semver"
30+
authorizationv1 "k8s.io/api/authorization/v1"
3031
corev1 "k8s.io/api/core/v1"
3132
apierrors "k8s.io/apimachinery/pkg/api/errors"
3233
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -172,11 +173,19 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context
172173
if excludedCatalogSources != nil && util.Contains(excludedCatalogSources, pm.Status.CatalogSource) {
173174
continue
174175
}
176+
177+
hasCatalogPermission := m.CheckResAuth(ctx, namespace, "operators.coreos.com", "catalogsources", "get")
178+
if !hasCatalogPermission {
179+
klog.V(2).Infof("No permission to get CatalogSource %s in the namespace %s", pm.Status.CatalogSource, pm.Status.CatalogSourceNamespace)
180+
continue
181+
}
182+
// Fetch the CatalogSource if cluster permission allows
175183
catalogsource := &olmv1alpha1.CatalogSource{}
176184
if err := m.Reader.Get(ctx, types.NamespacedName{Name: pm.Status.CatalogSource, Namespace: pm.Status.CatalogSourceNamespace}, catalogsource); err != nil {
177185
klog.Warning(err)
178186
continue
179187
}
188+
180189
currentCatalog := CatalogSource{
181190
Name: pm.Status.CatalogSource,
182191
Namespace: pm.Status.CatalogSourceNamespace,
@@ -220,6 +229,28 @@ func (m *ODLMOperator) GetCatalogSourceAndChannelFromPackage(ctx context.Context
220229
}
221230
}
222231

232+
func (m *ODLMOperator) CheckResAuth(ctx context.Context, namespace, group, resource, verb string) bool {
233+
sar := &authorizationv1.SubjectAccessReview{
234+
Spec: authorizationv1.SubjectAccessReviewSpec{
235+
ResourceAttributes: &authorizationv1.ResourceAttributes{
236+
Namespace: namespace,
237+
Group: group,
238+
Resource: resource,
239+
Verb: verb,
240+
},
241+
},
242+
}
243+
if err := m.Create(ctx, sar); err != nil {
244+
return false
245+
}
246+
247+
if !sar.Status.Allowed {
248+
return false
249+
}
250+
251+
return true
252+
}
253+
223254
func channelCheck(channelName string, channelList []operatorsv1.PackageChannel) bool {
224255
for _, channel := range channelList {
225256
if channelName == channel.Name {

controllers/operator/manager_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ package operator
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"reflect"
2223
"testing"
2324

2425
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
2526
operatorsv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1"
27+
"github.com/stretchr/testify/mock"
28+
authorizationv1 "k8s.io/api/authorization/v1"
2629
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2730
"sigs.k8s.io/controller-runtime/pkg/client"
2831
)
@@ -302,10 +305,18 @@ func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) {
302305
CatalogSourceList: CatalogSourceList,
303306
}
304307

308+
mockClient := &MockClient{}
309+
305310
operator := &ODLMOperator{
306311
Reader: fakeReader,
312+
Client: mockClient,
307313
}
308314

315+
mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
316+
sar := args.Get(1).(*authorizationv1.SubjectAccessReview)
317+
sar.Status.Allowed = true
318+
})
319+
309320
registryNs := "registry-namespace"
310321
odlmCatalog := "odlm-catalog"
311322
odlmCatalogNs := "odlm-namespace"
@@ -400,6 +411,59 @@ func TestGetCatalogSourceAndChannelFromPackage(t *testing.T) {
400411

401412
}
402413

414+
type MockClient struct {
415+
mock mock.Mock
416+
client.Client
417+
}
418+
419+
func (m *MockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
420+
args := m.mock.Called(ctx, obj, opts)
421+
return args.Error(0)
422+
}
423+
424+
func TestCheckResAuth(t *testing.T) {
425+
ctx := context.TODO()
426+
427+
mockClient := &MockClient{}
428+
operator := &ODLMOperator{
429+
Client: mockClient,
430+
}
431+
432+
namespace := "test-namespace"
433+
group := "test-group"
434+
resource := "test-resource"
435+
verb := "get"
436+
437+
// Test when SubjectAccessReview is allowed
438+
mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
439+
sar := args.Get(1).(*authorizationv1.SubjectAccessReview)
440+
sar.Status.Allowed = true
441+
})
442+
443+
if !operator.CheckResAuth(ctx, namespace, group, resource, verb) {
444+
t.Errorf("Expected CheckResAuth to return true, but got false")
445+
}
446+
447+
// Test when SubjectAccessReview is not allowed
448+
mockClient.mock.ExpectedCalls = nil
449+
mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
450+
sar := args.Get(1).(*authorizationv1.SubjectAccessReview)
451+
sar.Status.Allowed = false
452+
})
453+
454+
if operator.CheckResAuth(ctx, namespace, group, resource, verb) {
455+
t.Errorf("Expected CheckResAuth to return false, but got true")
456+
}
457+
458+
// Test when Create returns an error
459+
mockClient.mock.ExpectedCalls = nil
460+
mockClient.mock.On("Create", ctx, mock.Anything, mock.Anything).Return(fmt.Errorf("create error"))
461+
462+
if operator.CheckResAuth(ctx, namespace, group, resource, verb) {
463+
t.Errorf("Expected CheckResAuth to return false, but got true")
464+
}
465+
}
466+
403467
func assertCatalogSourceAndChannel(t *testing.T, catalogSourceName, expectedCatalogSourceName, catalogSourceNs, expectedCatalogSourceNs, availableChannel, expectedAvailableChannel string) {
404468
t.Helper()
405469

0 commit comments

Comments
 (0)