Skip to content

Commit

Permalink
fix: setting secrets and configs error with aliased field names
Browse files Browse the repository at this point in the history
  • Loading branch information
wesbillman committed Jul 17, 2024
1 parent 802aa90 commit 77197d8
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 136 deletions.
127 changes: 0 additions & 127 deletions backend/controller/ingress/alias.go

This file was deleted.

2 changes: 1 addition & 1 deletion backend/controller/ingress/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func BuildRequestBody(route *dal.IngressRoute, r *http.Request, sch *schema.Sche
}
}

requestMap, err = transformFromAliasedFields(request, sch, requestMap)
requestMap, err = schema.TransformFromAliasedFields(request, sch, requestMap)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion backend/controller/ingress/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func bodyForType(typ schema.Type, sch *schema.Schema, data []byte) ([]byte, erro
return nil, fmt.Errorf("HTTP response body is not valid JSON: %w", err)
}

err = transformAliasedFields(sch, t, response, func(obj map[string]any, field *schema.Field) string {
err = schema.TransformAliasedFields(sch, t, response, func(obj map[string]any, field *schema.Field) string {
if jsonAlias, ok := field.Alias(schema.AliasKindJSON).Get(); ok && field.Name != jsonAlias {
obj[jsonAlias] = obj[field.Name]
delete(obj, field.Name)
Expand Down
121 changes: 121 additions & 0 deletions backend/schema/jsonvalidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func ValidateJSONValue(fieldType Type, path path, value any, sch *Schema) error
return nil
}

// ValidateRequestMap validates a given JSON map against the provided schema.
func ValidateRequestMap(ref *Ref, path path, request map[string]any, sch *Schema) error {
data, err := sch.ResolveMonomorphised(ref)
if err != nil {
Expand Down Expand Up @@ -249,3 +250,123 @@ func allowMissingField(field *Field) bool {
}
return false
}

func TransformAliasedFields(sch *Schema, t Type, obj any, aliaser func(obj map[string]any, field *Field) string) error {
if obj == nil {
return nil
}
switch t := t.(type) {
case *Ref:
decl, ok := sch.Resolve(t).Get()
if !ok {
return fmt.Errorf("%s: failed to resolve ref %s", t.Pos, t)
}
switch decl := decl.(type) {
case *Data:
data, err := sch.ResolveMonomorphised(t)
if err != nil {
return fmt.Errorf("%s: failed to resolve data type: %w", t.Pos, err)
}
m, ok := obj.(map[string]any)
if !ok {
return fmt.Errorf("%s: expected map, got %T", t.Pos, obj)
}
for _, field := range data.Fields {
name := aliaser(m, field)
if err := TransformAliasedFields(sch, field.Type, m[name], aliaser); err != nil {
return err
}
}
case *Enum:
if decl.IsValueEnum() {
return nil
}

// type enum
m, ok := obj.(map[string]any)
if !ok {
return fmt.Errorf("%s: expected map, got %T", t.Pos, obj)
}
name, ok := m["name"]
if !ok {
return fmt.Errorf("%s: expected type enum request to have 'name' field", t.Pos)
}
nameStr, ok := name.(string)
if !ok {
return fmt.Errorf("%s: expected 'name' field to be a string, got %T", t.Pos, name)
}

value, ok := m["value"]
if !ok {
return fmt.Errorf("%s: expected type enum request to have 'value' field", t.Pos)
}

for _, v := range decl.Variants {
if v.Name == nameStr {
if err := TransformAliasedFields(sch, v.Value.(*TypeValue).Value, value, aliaser); err != nil { //nolint:forcetypeassert
return err
}
}
}
case *TypeAlias:
return TransformAliasedFields(sch, decl.Type, obj, aliaser)
case *Config, *Database, *FSM, *Secret, *Verb, *Topic, *Subscription:
return fmt.Errorf("%s: unsupported ref type %T", t.Pos, decl)
}

case *Array:
a, ok := obj.([]any)
if !ok {
return fmt.Errorf("%s: expected array, got %T", t.Pos, obj)
}
for _, elem := range a {
if err := TransformAliasedFields(sch, t.Element, elem, aliaser); err != nil {
return err
}
}

case *Map:
m, ok := obj.(map[string]any)
if !ok {
return fmt.Errorf("%s: expected map, got %T", t.Pos, obj)
}
for key, value := range m {
if err := TransformAliasedFields(sch, t.Key, key, aliaser); err != nil {
return err
}
if err := TransformAliasedFields(sch, t.Value, value, aliaser); err != nil {
return err
}
}

case *Optional:
return TransformAliasedFields(sch, t.Type, obj, aliaser)

case *Any, *Bool, *Bytes, *Float, *Int,
*String, *Time, *Unit:
}
return nil
}

func TransformFromAliasedFields(ref *Ref, sch *Schema, request map[string]any) (map[string]any, error) {
return request, TransformAliasedFields(sch, ref, request, func(obj map[string]any, field *Field) string {
if jsonAlias, ok := field.Alias(AliasKindJSON).Get(); ok {
if _, ok := obj[field.Name]; !ok && obj[jsonAlias] != nil {
obj[field.Name] = obj[jsonAlias]
delete(obj, jsonAlias)
}
}
return field.Name
})
}

func TransformToAliasedFields(ref *Ref, sch *Schema, request map[string]any) (map[string]any, error) {
return request, TransformAliasedFields(sch, ref, request, func(obj map[string]any, field *Field) string {
if jsonAlias, ok := field.Alias(AliasKindJSON).Get(); ok && field.Name != jsonAlias {
obj[jsonAlias] = obj[field.Name]
delete(obj, field.Name)
return jsonAlias
}
return field.Name
})
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package ingress
package schema

import (
"testing"

"github.com/alecthomas/assert/v2"

"github.com/TBD54566975/ftl/backend/schema"
)

func TestTransformFromAliasedFields(t *testing.T) {
Expand All @@ -31,9 +29,9 @@ func TestTransformFromAliasedFields(t *testing.T) {
}
`

sch, err := schema.ParseString("test", schemaText)
sch, err := ParseString("test", schemaText)
assert.NoError(t, err)
actual, err := transformFromAliasedFields(&schema.Ref{Module: "test", Name: "Test"}, sch, map[string]any{
actual, err := TransformFromAliasedFields(&Ref{Module: "test", Name: "Test"}, sch, map[string]any{
"bar": "value",
"inner": map[string]any{
"foo": "value",
Expand Down Expand Up @@ -106,9 +104,9 @@ func TestTransformToAliasedFields(t *testing.T) {
}
`

sch, err := schema.ParseString("test", schemaText)
sch, err := ParseString("test", schemaText)
assert.NoError(t, err)
actual, err := transformToAliasedFields(&schema.Ref{Module: "test", Name: "Test"}, sch, map[string]any{
actual, err := TransformToAliasedFields(&Ref{Module: "test", Name: "Test"}, sch, map[string]any{
"scalar": "value",
"inner": map[string]any{
"waz": "value",
Expand Down

0 comments on commit 77197d8

Please sign in to comment.