Skip to content

Commit

Permalink
Merge pull request #175 from a-hilaly/nested-schemaless-resources
Browse files Browse the repository at this point in the history
feat: parse expressions in `x-kubernetes-preserve-unknown` fields
  • Loading branch information
michaelhtm authored Dec 29, 2024
2 parents 423d841 + 8ff3c8d commit 2c58d17
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 3 deletions.
13 changes: 10 additions & 3 deletions pkg/graph/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ func parseObject(field map[string]interface{}, schema *spec.Schema, path, expect

// Look for vendor schema extensions first
if len(schema.VendorExtensible.Extensions) > 0 {
// If the schema has the x-kubernetes-preserve-unknown-fields extension, we should not
// parse the object and return an empty list of expressions.
// If the schema has the x-kubernetes-preserve-unknown-fields extension, we need to parse
// this field using the schemaless parser. This allows us to extract CEL expressions from
// fields that don't have a strict schema definition, while still preserving any unknown
// fields. This is particularly important for handling custom resources and fields that
// may contain arbitrary nested structures with potential CEL expressions.
if enabled, ok := schema.VendorExtensible.Extensions[xKubernetesPreserveUnknownFields]; ok && enabled.(bool) {
return nil, nil
expressions, err := parseSchemalessResource(field, path)
if err != nil {
return nil, err
}
return expressions, nil
}
}

Expand Down
45 changes: 45 additions & 0 deletions pkg/graph/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ func TestParseResource(t *testing.T) {
"${value}",
},
},
"schemalessField": map[string]interface{}{
"key": "value",
"something": "${schemaless.value}",
"nestedSomething": map[string]interface{}{
"key": "value",
"nested": "${schemaless.nested.value}",
},
},
}

schema := &spec.Schema{
Expand Down Expand Up @@ -107,6 +115,16 @@ func TestParseResource(t *testing.T) {
},
},
},
"schemalessField": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
},
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-preserve-unknown-fields": true,
},
},
},
},
},
}
Expand All @@ -125,6 +143,8 @@ func TestParseResource(t *testing.T) {
{Path: "specialCharacters[\"doted.annotation.key\"]", Expressions: []string{"dotedannotationvalue"}, ExpectedType: "string", StandaloneExpression: true},
{Path: "specialCharacters[\"\"]", Expressions: []string{"emptyannotation"}, ExpectedType: "string", StandaloneExpression: true},
{Path: "specialCharacters[\"array.name.with.dots\"][0]", Expressions: []string{"value"}, ExpectedType: "string", StandaloneExpression: true},
{Path: "schemalessField.something", Expressions: []string{"schemaless.value"}, ExpectedType: "string", StandaloneExpression: true},
{Path: "schemalessField.nestedSomething.nested", Expressions: []string{"schemaless.nested.value"}, ExpectedType: "string", StandaloneExpression: true},
}

expressions, err := ParseResource(resource, schema)
Expand Down Expand Up @@ -618,6 +638,31 @@ func TestParserEdgeCases(t *testing.T) {
resource: map[string]interface{}{"name": "John", "age": 30},
expectedError: "",
},
{
name: "structured object with nested x-kubernetes-preserve-unknown-fields",
schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"id": {SchemaProps: spec.SchemaProps{Type: []string{"string"}}},
"metadata": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
},
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-preserve-unknown-fields": true,
},
},
},
},
},
},
resource: map[string]interface{}{"id": "123", "metadata": map[string]interface{}{
"name": "John", "age": 30, "test": "${test.value}",
}},
expectedError: "",
},
}

for _, tc := range testCases {
Expand Down

0 comments on commit 2c58d17

Please sign in to comment.