Skip to content

Commit 0a6118a

Browse files
authored
[v2.13] Only allow listing when list verb exists (#1029)
* Fix getting cluster schema * Only allow listing when list verb exists (#1026)
1 parent 1a12f0e commit 0a6118a

File tree

6 files changed

+328
-66
lines changed

6 files changed

+328
-66
lines changed

pkg/server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func setup(ctx context.Context, server *Server) error {
211211

212212
var onSchemasHandler schemacontroller.SchemasHandlerFunc
213213
if server.SQLCache {
214-
sqlStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, server.cacheFactory, false)
214+
sqlStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, sf, server.cacheFactory, false)
215215
if err != nil {
216216
return err
217217
}

pkg/sqlcache/integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ func (i *IntegrationSuite) TestProxyStore() {
489489
cacheFactory, err := factory.NewCacheFactoryWithContext(ctx, factory.CacheFactoryOptions{})
490490
requireT.NoError(err)
491491

492-
proxyStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, cacheFactory, true)
492+
proxyStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, sf, cacheFactory, true)
493493
requireT.NoError(err)
494494
requireT.NotNil(proxyStore)
495495

@@ -682,7 +682,7 @@ func (i *IntegrationSuite) TestProvisioningManagementClusterDependencies() {
682682
cacheFactory, err := factory.NewCacheFactoryWithContext(ctx, factory.CacheFactoryOptions{})
683683
requireT.NoError(err)
684684

685-
proxyStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, cacheFactory, true)
685+
proxyStore, err := sqlproxy.NewProxyStore(ctx, cols, cf, summaryCache, summaryCache, sf, cacheFactory, true)
686686
requireT.NoError(err)
687687
requireT.NotNil(proxyStore)
688688

pkg/stores/sqlproxy/proxy_mocks_test.go

Lines changed: 54 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/stores/sqlproxy/proxy_store.go

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/rancher/steve/pkg/stores/queryhelper"
2626
"github.com/rancher/wrangler/v3/pkg/data"
2727
"github.com/rancher/wrangler/v3/pkg/kv"
28-
"github.com/rancher/wrangler/v3/pkg/schemas"
2928
"github.com/rancher/wrangler/v3/pkg/schemas/validation"
3029
"github.com/rancher/wrangler/v3/pkg/summary"
3130
"github.com/sirupsen/logrus"
@@ -224,26 +223,6 @@ var (
224223
{`id`},
225224
{`metadata`, `state`, `name`},
226225
}
227-
baseNSSchema = types.APISchema{
228-
Schema: &schemas.Schema{
229-
Attributes: map[string]interface{}{
230-
"group": "",
231-
"version": "v1",
232-
"kind": "Namespace",
233-
"resource": "namespaces",
234-
},
235-
},
236-
}
237-
mgmtClusterSchema = types.APISchema{
238-
Schema: &schemas.Schema{
239-
Attributes: map[string]interface{}{
240-
"group": "management.cattle.io",
241-
"version": "v3",
242-
"kind": "Cluster",
243-
"resource": "clusters",
244-
},
245-
},
246-
}
247226
namespaceGVK = schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Namespace"}
248227
mcioProjectGvk = schema.GroupVersionKind{Group: "management.cattle.io", Version: "v3", Kind: "Project"}
249228
pcioClusterGvk = schema.GroupVersionKind{Group: "provisioning.cattle.io", Version: "v1", Kind: "Cluster"}
@@ -351,6 +330,11 @@ type SchemaColumnSetter interface {
351330
SetColumns(ctx context.Context, schema *types.APISchema) error
352331
}
353332

333+
type SchemaCollection interface {
334+
Schema(id string) *types.APISchema
335+
ByGVK(gvk schema.GroupVersionKind) string
336+
}
337+
354338
type Cache interface {
355339
// ListByOptions returns objects according to the specified list options and partitions.
356340
// Specifically:
@@ -392,6 +376,7 @@ type Store struct {
392376
lock sync.Mutex
393377
columnSetter SchemaColumnSetter
394378
transformBuilder TransformBuilder
379+
schemas SchemaCollection
395380

396381
watchers *Watchers
397382
}
@@ -405,13 +390,14 @@ type CacheFactory interface {
405390
}
406391

407392
// NewProxyStore returns a Store implemented directly on top of kubernetes.
408-
func NewProxyStore(ctx context.Context, c SchemaColumnSetter, clientGetter ClientGetter, notifier RelationshipNotifier, scache virtualCommon.SummaryCache, factory CacheFactory, needToInitNamespaceCache bool) (*Store, error) {
393+
func NewProxyStore(ctx context.Context, c SchemaColumnSetter, clientGetter ClientGetter, notifier RelationshipNotifier, scache virtualCommon.SummaryCache, schemas SchemaCollection, factory CacheFactory, needToInitNamespaceCache bool) (*Store, error) {
409394
store := &Store{
410395
ctx: ctx,
411396
clientGetter: clientGetter,
412397
notifier: notifier,
413398
columnSetter: c,
414399
transformBuilder: virtual.NewTransformBuilder(scache),
400+
schemas: schemas,
415401
watchers: newWatchers(),
416402
}
417403

@@ -463,26 +449,34 @@ func defaultInitializeCacheFactory() (CacheFactory, error) {
463449
// namespaces and projects.
464450
func (s *Store) initializeNamespaceCache() error {
465451
buffer := WarningBuffer{}
466-
nsSchema := baseNSSchema
452+
var nsSchema *types.APISchema
453+
454+
if id := s.schemas.ByGVK(namespaceGVK); id != "" {
455+
nsSchema = s.schemas.Schema(id)
456+
}
457+
458+
if nsSchema == nil {
459+
return fmt.Errorf("namespace schema not found")
460+
}
467461

468462
// make sure any relevant columns are set to the ns schema
469-
if err := s.columnSetter.SetColumns(s.ctx, &nsSchema); err != nil {
463+
if err := s.columnSetter.SetColumns(s.ctx, nsSchema); err != nil {
470464
return fmt.Errorf("failed to set columns for proxy stores namespace informer: %w", err)
471465
}
472466

473467
// build table client
474-
client, err := s.clientGetter.TableAdminClient(nil, &nsSchema, "", &buffer)
468+
client, err := s.clientGetter.TableAdminClient(nil, nsSchema, "", &buffer)
475469
if err != nil {
476470
return err
477471
}
478472

479-
gvk := attributes.GVK(&nsSchema)
480-
fields, cols, typeGuidance := getFieldAndColInfo(&nsSchema, gvk)
473+
gvk := attributes.GVK(nsSchema)
474+
fields, cols, typeGuidance := getFieldAndColInfo(nsSchema, gvk)
481475
// get any type-specific fields that steve is interested in
482476
fields = append(fields, getFieldForGVK(gvk)...)
483477

484478
// get the type-specific transform func
485-
transformFunc := s.transformBuilder.GetTransformFunc(gvk, cols, attributes.IsCRD(&nsSchema))
479+
transformFunc := s.transformBuilder.GetTransformFunc(gvk, cols, attributes.IsCRD(nsSchema))
486480

487481
// get the ns informer
488482
tableClient := &tablelistconvert.Client{ResourceInterface: client}
@@ -1103,7 +1097,20 @@ func (s *Store) cacheForWithDeps(ctx context.Context, apiOp *types.APIRequest, a
11031097
// provisioning.cattle.io.clusters depends on information from management.cattle.io.clusters
11041098
// so we must initialize this one as well
11051099
if gvk == pcioClusterGvk {
1106-
mgmtClusterInf, err := s.cacheFor(ctx, nil, &mgmtClusterSchema)
1100+
var mgmtSchema *types.APISchema
1101+
if id := s.schemas.ByGVK(schema.GroupVersionKind{
1102+
Group: "management.cattle.io",
1103+
Version: "v3",
1104+
Kind: "Cluster",
1105+
}); id != "" {
1106+
mgmtSchema = s.schemas.Schema(id)
1107+
}
1108+
1109+
if mgmtSchema == nil {
1110+
return nil, nil, fmt.Errorf("management cluster schema not found")
1111+
}
1112+
1113+
mgmtClusterInf, err := s.cacheFor(ctx, nil, mgmtSchema)
11071114
if err != nil {
11081115
return nil, nil, err
11091116
}
@@ -1125,6 +1132,9 @@ func (s *Store) cacheForWithDeps(ctx context.Context, apiOp *types.APIRequest, a
11251132
}
11261133

11271134
func (s *Store) cacheFor(ctx context.Context, apiOp *types.APIRequest, apiSchema *types.APISchema) (*factory.Cache, error) {
1135+
if !canList(apiSchema) {
1136+
return nil, apierror.NewAPIError(validation.MethodNotAllowed, fmt.Sprintf("resource %s is not a listable resource", apiSchema.ID))
1137+
}
11281138
// warnings from inside the informer are discarded
11291139
buffer := WarningBuffer{}
11301140
client, err := s.clientGetter.TableAdminClient(apiOp, apiSchema, "", &buffer)
@@ -1147,3 +1157,13 @@ func (s *Store) cacheFor(ctx context.Context, apiOp *types.APIRequest, apiSchema
11471157
}
11481158
return inf, nil
11491159
}
1160+
1161+
func canList(schema *types.APISchema) bool {
1162+
for _, verb := range attributes.Verbs(schema) {
1163+
if verb == "list" {
1164+
return true
1165+
}
1166+
}
1167+
1168+
return false
1169+
}

0 commit comments

Comments
 (0)