Skip to content

Commit d876f0d

Browse files
author
Moritz Clasmeier
committed
Improve checking of availability of securityContextConfig
1 parent 2a60f6b commit d876f0d

1 file changed

Lines changed: 51 additions & 21 deletions

File tree

internal/deployer/operator_olm.go

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/stackrox/roxie/internal/k8s"
1212
"gopkg.in/yaml.v3"
13+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1314
)
1415

1516
const (
@@ -107,11 +108,21 @@ func (d *Deployer) getOperatorIndexImage() string {
107108
func (d *Deployer) createCatalogSource(ctx context.Context, indexImage string) error {
108109
d.logger.Info("Creating CatalogSource...")
109110

110-
// Check if CatalogSource CRD supports securityContextConfig (OCP 4.14+).
111-
hasSecurityContextConfig, err := d.catalogSourceSupportsSecurityContextConfig(ctx)
111+
securityContextConfigSupported, err := d.catalogSourceSupportsSecurityContextConfig(ctx)
112112
if err != nil {
113113
d.logger.Warning("Could not check CatalogSource CRD capabilities, proceeding without securityContextConfig")
114-
hasSecurityContextConfig = false
114+
securityContextConfigSupported = false
115+
}
116+
117+
catalogSourceSpec := map[string]interface{}{
118+
"sourceType": "grpc",
119+
"image": indexImage,
120+
"displayName": "StackRox Operator Index",
121+
}
122+
if securityContextConfigSupported {
123+
catalogSourceSpec["grpcPodConfig"] = map[string]interface{}{
124+
"securityContextConfig": "restricted",
125+
}
115126
}
116127

117128
catalogSource := map[string]interface{}{
@@ -121,19 +132,7 @@ func (d *Deployer) createCatalogSource(ctx context.Context, indexImage string) e
121132
"name": catalogSourceName,
122133
"namespace": operatorNamespace,
123134
},
124-
"spec": map[string]interface{}{
125-
"sourceType": "grpc",
126-
"image": indexImage,
127-
"displayName": "StackRox Operator Index",
128-
},
129-
}
130-
131-
// TODO(ROX-34499): Add security context config if supported.
132-
if hasSecurityContextConfig {
133-
spec := catalogSource["spec"].(map[string]interface{})
134-
spec["grpcPodConfig"] = map[string]interface{}{
135-
"securityContextConfig": "restricted",
136-
}
135+
"spec": catalogSourceSpec,
137136
}
138137

139138
yamlData, err := yaml.Marshal(catalogSource)
@@ -153,18 +152,49 @@ func (d *Deployer) createCatalogSource(ctx context.Context, indexImage string) e
153152
return nil
154153
}
155154

156-
// catalogSourceSupportsSecurityContextConfig checks if the CatalogSource CRD supports securityContextConfig.
155+
// catalogSourceSupportsSecurityContextConfig checks if any served CatalogSource CRD version
156+
// includes securityContextConfig in its schema.
157157
func (d *Deployer) catalogSourceSupportsSecurityContextConfig(ctx context.Context) (bool, error) {
158+
crdName := "catalogsources.operators.coreos.com"
158159
result, err := d.runKubectl(ctx, k8s.KubectlOptions{
159-
Args: []string{"get", "crd", "catalogsources.operators.coreos.com", "-o", "yaml"},
160+
Args: []string{"get", "crd", crdName, "-o", "yaml"},
160161
})
161162
if err != nil {
162163
return false, err
163164
}
164165

165-
// TODO(ROX-34499): this is overly optimistic and would incorrectly succeed if an api version
166-
// that contains this had "serving: false"
167-
return strings.Contains(result.Stdout, "securityContextConfig"), nil
166+
obj := &unstructured.Unstructured{}
167+
if err := yaml.Unmarshal([]byte(result.Stdout), &obj.Object); err != nil {
168+
return false, fmt.Errorf("failed to parse CatalogSource CRD: %w", err)
169+
}
170+
171+
// Note, we cannot use NestedSlice, because that does an implicit runtime.DeepCopyJSONValue, which fail,
172+
// because the versions slice YAML also contains unsupported types (int).
173+
versions, _, _ := unstructured.NestedFieldNoCopy(obj.Object, "spec", "versions")
174+
versionsSlice, ok := versions.([]interface{})
175+
if !ok {
176+
return false, fmt.Errorf("failed to extract spec.versions from crd %s", crdName)
177+
}
178+
179+
for _, v := range versionsSlice {
180+
version, ok := v.(map[string]interface{})
181+
if !ok {
182+
continue
183+
}
184+
served, _, _ := unstructured.NestedBool(version, "served")
185+
if !served {
186+
continue
187+
}
188+
_, found, _ := unstructured.NestedMap(version,
189+
"schema", "openAPIV3Schema", "properties", "spec",
190+
"properties", "grpcPodConfig", "properties", "securityContextConfig",
191+
)
192+
if found {
193+
return true, nil
194+
}
195+
}
196+
197+
return false, nil
168198
}
169199

170200
// createOperatorGroup creates the OperatorGroup.

0 commit comments

Comments
 (0)