diff --git a/pkg/policy/literal/literal.go b/pkg/policy/literal/literal.go index b9041cc..872f6a1 100644 --- a/pkg/policy/literal/literal.go +++ b/pkg/policy/literal/literal.go @@ -51,6 +51,24 @@ func Map(m map[string]any) (ipld.Node, error) { if err != nil { return nil, err } + for _, elem := range x { + switch e := elem.(type) { + case string: + if err := la.AssembleValue().AssignString(e); err != nil { + return nil, err + } + case map[string]any: + nestedNode, err := Map(e) + if err != nil { + return nil, err + } + if err := la.AssembleValue().AssignNode(nestedNode); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unsupported array element type: %T", elem) + } + } if err := la.Finish(); err != nil { return nil, err } diff --git a/pkg/policy/match_test.go b/pkg/policy/match_test.go index 3d21fad..da03c46 100644 --- a/pkg/policy/match_test.go +++ b/pkg/policy/match_test.go @@ -798,6 +798,31 @@ func TestPartialMatch(t *testing.T) { expectedMatch: true, expectedStmt: nil, }, + { + name: "returns true for partially present nested optional paths", + policy: MustConstruct( + And( + Equal(".required", literal.String("present")), + Any(".items", + And( + Equal(".name", literal.String("test")), + Like(".optional_id?", "ID*"), + ), + ), + ), + ), + data: map[string]interface{}{ + "required": "present", + "items": []interface{}{ + map[string]interface{}{ + "name": "test", + // optional_id is missing + }, + }, + }, + expectedMatch: true, + expectedStmt: nil, + }, } for _, tt := range tests {