diff --git a/go.mod b/go.mod index d6dedf50e1..0825da4862 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.1 require ( github.com/Masterminds/semver v1.5.0 - github.com/getkin/kin-openapi v0.111.0 + github.com/getkin/kin-openapi v0.132.0 github.com/google/go-cmp v0.7.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.6.3 @@ -24,7 +24,7 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure v1.1.0 github.com/robfig/cron v1.2.0 - github.com/stretchr/testify v1.8.3 + github.com/stretchr/testify v1.9.0 golang.org/x/mod v0.24.0 k8s.io/api v0.28.6 k8s.io/apiextensions-apiserver v0.28.6 @@ -49,10 +49,12 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/huandu/xstrings v1.3.3 // indirect - github.com/invopop/yaml v0.2.0 // indirect github.com/mitchellh/cli v1.1.5 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/posener/complete v1.2.3 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -77,9 +79,9 @@ require ( github.com/fatih/color v1.16.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect diff --git a/go.sum b/go.sum index c084860636..d071c2e3ba 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/getkin/kin-openapi v0.111.0 h1:zspOcFKBCQOY8d9Yockcbit8iVR2hco9qLaoQoj7kmw= -github.com/getkin/kin-openapi v0.111.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= +github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -85,18 +85,18 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -141,7 +141,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -208,9 +207,6 @@ github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= -github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= @@ -235,8 +231,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -283,12 +277,18 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= @@ -303,8 +303,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -325,8 +325,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -337,8 +338,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -505,7 +508,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/manifest/openapi/foundry_v2.go b/manifest/openapi/foundry_v2.go index 83377262c3..e32a2802c6 100644 --- a/manifest/openapi/foundry_v2.go +++ b/manifest/openapi/foundry_v2.go @@ -4,7 +4,6 @@ package openapi import ( - "encoding/json" "errors" "fmt" "sync" @@ -100,19 +99,19 @@ func (f *foapiv2) getTypeByID(id string, h map[string]string, ap tftypes.Attribu return nil, errors.New("invalid type reference (nil)") } - sch, err := resolveSchemaRef(swd, f.swagger.Definitions) + sch, err := resolveSchemaRef2(swd, f.swagger.Definitions) if err != nil { return nil, fmt.Errorf("failed to resolve schema: %s", err) } - return getTypeFromSchema(sch, f.recursionDepth, &(f.typeCache), f.swagger.Definitions, ap, h) + return getTypeFromSchema2(sch, f.recursionDepth, &(f.typeCache), f.swagger.Definitions, ap, h) } // buildGvkIndex builds the reverse lookup index that associates each GVK // to its corresponding string key in the swagger.Definitions map func (f *foapiv2) buildGvkIndex() error { for did, dRef := range f.swagger.Definitions { - def, err := resolveSchemaRef(dRef, f.swagger.Definitions) + def, err := resolveSchemaRef2(dRef, f.swagger.Definitions) if err != nil { return err } @@ -120,13 +119,13 @@ func (f *foapiv2) buildGvkIndex() error { if !ok { continue } - gvk := []schema.GroupVersionKind{} - err = json.Unmarshal(([]byte)(ex.(json.RawMessage)), &gvk) - if err != nil { - return fmt.Errorf("failed to unmarshall GVK from OpenAPI schema extention: %v", err) - } - for i := range gvk { - f.gkvIndex.Store(gvk[i], did) + for _, v := range ex.([]interface{}) { + mv := v.(map[string]interface{}) + f.gkvIndex.Store(schema.GroupVersionKind{ + Group: mv["group"].(string), + Version: mv["version"].(string), + Kind: mv["kind"].(string), + }, did) } } return nil diff --git a/manifest/openapi/foundry_v3.go b/manifest/openapi/foundry_v3.go index d0bd40fc01..216a1fbd66 100644 --- a/manifest/openapi/foundry_v3.go +++ b/manifest/openapi/foundry_v3.go @@ -56,11 +56,11 @@ func (f *foapiv3) GetTypeByGVK(_ schema.GroupVersionKind) (tftypes.Type, map[str sref := f.doc.Components.Schemas[""] - sch, err := resolveSchemaRef(sref, f.doc.Components.Schemas) + sch, err := resolveSchemaRef3(sref, f.doc.Components.Schemas) if err != nil { return nil, hints, fmt.Errorf("failed to resolve schema: %s", err) } - tftype, err := getTypeFromSchema(sch, 50, &(f.typeCache), f.doc.Components.Schemas, ap, hints) + tftype, err := getTypeFromSchema3(sch, 50, &(f.typeCache), f.doc.Components.Schemas, ap, hints) return tftype, hints, err } diff --git a/manifest/openapi/foundry_v3_test.go b/manifest/openapi/foundry_v3_test.go index 4e65186faa..a902f87c73 100644 --- a/manifest/openapi/foundry_v3_test.go +++ b/manifest/openapi/foundry_v3_test.go @@ -45,7 +45,7 @@ func TestNewFoundryFromSpecV3(t *testing.T) { if crd == nil || crd.Value == nil { t.Fail() } - if crd.Value.Type != "object" { + if !crd.Value.Type.Is("object") { t.Fail() } if crd.Value.Properties == nil { @@ -55,14 +55,14 @@ func TestNewFoundryFromSpecV3(t *testing.T) { if !ok { t.Fail() } - if foo.Value.Type != "string" { + if !foo.Value.Type.Is("string") { t.Fail() } bar, ok := crd.Value.Properties["bar"] if !ok { t.Fail() } - if bar.Value.Type != "number" { + if !bar.Value.Type.Is("number") { t.Fail() } } diff --git a/manifest/openapi/schema_v2.go b/manifest/openapi/schema_v2.go new file mode 100644 index 0000000000..39b96f9c3c --- /dev/null +++ b/manifest/openapi/schema_v2.go @@ -0,0 +1,256 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package openapi + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "sync" + + "github.com/getkin/kin-openapi/openapi2" + "github.com/getkin/kin-openapi/openapi3" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "github.com/hashicorp/terraform-provider-kubernetes/manifest" + "github.com/mitchellh/hashstructure" +) + +func resolveSchemaRef2(ref *openapi2.SchemaRef, defs map[string]*openapi2.SchemaRef) (*openapi2.Schema, error) { + if ref.Value != nil { + return ref.Value, nil + } + + rp := strings.Split(ref.Ref, "/") + sid := rp[len(rp)-1] + + nref, ok := defs[sid] + + if !ok { + return nil, errors.New("schema not found") + } + if nref == nil { + return nil, errors.New("nil schema reference") + } + + // These are exceptional situations that require non-standard types. + switch sid { + case "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps": + t := openapi2.Schema{ + Type: &openapi3.Types{""}, + } + return &t, nil + case "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps": + t := openapi2.Schema{ + Type: &openapi3.Types{""}, + } + return &t, nil + } + + return resolveSchemaRef2(nref, defs) +} + +func getTypeFromSchema2(elem *openapi2.Schema, stackdepth uint64, typeCache *sync.Map, defs map[string]*openapi2.SchemaRef, ap tftypes.AttributePath, th map[string]string) (tftypes.Type, error) { + if stackdepth == 0 { + // this is a hack to overcome the inability to express recursion in tftypes + return nil, errors.New("recursion runaway while generating type from OpenAPI spec") + } + + if elem == nil { + return nil, errors.New("cannot convert OpenAPI type (nil)") + } + + h, herr := hashstructure.Hash(elem, nil) + + var t tftypes.Type + + // Check if attribute type is tagged as 'x-kubernetes-preserve-unknown-fields' in OpenAPI. + // If so, we add a type hint to indicate this and return DynamicPseudoType for this attribute, + // since we have no further structural information about it. + if xpufJSON, ok := elem.Extensions[manifest.PreserveUnknownFieldsLabel]; ok { + var xpuf bool + v, err := xpufJSON.(json.RawMessage).MarshalJSON() + if err == nil { + err = json.Unmarshal(v, &xpuf) + if err == nil && xpuf { + th[ap.String()] = manifest.PreserveUnknownFieldsLabel + } + } + } + + // check if type is in cache + // HACK: this is temporarily disabled to diagnose a cache corruption issue. + // if herr == nil { + // if t, ok := typeCache.Load(h); ok { + // return t.(tftypes.Type), nil + // } + // } + switch { + case elem.Type.Is("string"): + if elem.Format == "int-or-string" { + th[ap.String()] = "io.k8s.apimachinery.pkg.util.intstr.IntOrString" + } + return tftypes.String, nil + + case elem.Type.Is("boolean"): + return tftypes.Bool, nil + + case elem.Type.Is("number"): + return tftypes.Number, nil + + case elem.Type.Is("integer"): + return tftypes.Number, nil + + case elem.Type.Is(""): + if xv, ok := elem.Extensions["x-kubernetes-int-or-string"]; ok { + xb, err := xv.(json.RawMessage).MarshalJSON() + if err != nil { + return tftypes.DynamicPseudoType, nil + } + var x bool + err = json.Unmarshal(xb, &x) + if err == nil && x { + th[ap.String()] = "io.k8s.apimachinery.pkg.util.intstr.IntOrString" + return tftypes.String, nil + } + } + return tftypes.DynamicPseudoType, nil // this is where DynamicType is set for when an attribute is tagged as 'x-kubernetes-preserve-unknown-fields' + + case elem.Type.Is("array"): + switch { + case elem.Items != nil && elem.AdditionalProperties.Has == nil: // normal array - translates to a tftypes.List + it, err := resolveSchemaRef2(elem.Items, defs) + if err != nil { + return nil, fmt.Errorf("failed to resolve schema for items: %s", err) + } + aap := ap.WithElementKeyInt(-1) + et, err := getTypeFromSchema2(it, stackdepth-1, typeCache, defs, *aap, th) + if err != nil { + return nil, err + } + if !isTypeFullyKnown(et) { + t = tftypes.Tuple{ElementTypes: []tftypes.Type{et}} + } else { + t = tftypes.List{ElementType: et} + } + if herr == nil { + typeCache.Store(h, t) + } + return t, nil + case elem.AdditionalProperties.Has != nil && *elem.AdditionalProperties.Has && elem.Items == nil: // "overriden" array - translates to a tftypes.Tuple + v2ref, err := schemaRefV3toV2(elem.AdditionalProperties.Schema) + if err != nil { + return nil, fmt.Errorf("failed to convert schema from v3 to v2: %s", err) + } + it, err := resolveSchemaRef2(v2ref, defs) + if err != nil { + return nil, fmt.Errorf("failed to resolve schema for items: %s", err) + } + aap := ap.WithElementKeyInt(-1) + et, err := getTypeFromSchema2(it, stackdepth-1, typeCache, defs, *aap, th) + if err != nil { + return nil, err + } + t = tftypes.Tuple{ElementTypes: []tftypes.Type{et}} + return t, nil + } + + case elem.Type.Is("object"): + + switch { + case elem.Properties != nil && (elem.AdditionalProperties.Has == nil || !*elem.AdditionalProperties.Has): + // this is a standard OpenAPI object + atts := make(map[string]tftypes.Type, len(elem.Properties)) + for p, v := range elem.Properties { + schema, err := resolveSchemaRef2(v, defs) + if err != nil { + return nil, fmt.Errorf("failed to resolve schema: %s", err) + } + aap := ap.WithAttributeName(p) + pType, err := getTypeFromSchema2(schema, stackdepth-1, typeCache, defs, *aap, th) + if err != nil { + return nil, err + } + atts[p] = pType + } + t = tftypes.Object{AttributeTypes: atts} + if herr == nil { + typeCache.Store(h, t) + } + return t, nil + + case elem.Properties == nil && (elem.AdditionalProperties.Has != nil && *elem.AdditionalProperties.Has): + // this is how OpenAPI defines associative arrays + v2ref, err := schemaRefV3toV2(elem.AdditionalProperties.Schema) + if err != nil { + return nil, fmt.Errorf("failed to convert schema from v3 to v2: %s", err) + } + s, err := resolveSchemaRef2(v2ref, defs) + if err != nil { + return nil, fmt.Errorf("failed to resolve schema: %s", err) + } + aap := ap.WithElementKeyString("#") + pt, err := getTypeFromSchema2(s, stackdepth-1, typeCache, defs, *aap, th) + if err != nil { + return nil, err + } + t = tftypes.Map{ElementType: pt} + if herr == nil { + typeCache.Store(h, t) + } + return t, nil + + case elem.Properties == nil && (elem.AdditionalProperties.Has == nil || !*elem.AdditionalProperties.Has): + // this is a strange case, encountered with io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1 and also io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceStatus + t = tftypes.DynamicPseudoType + if herr == nil { + typeCache.Store(h, t) + } + return t, nil + + } + } + + return nil, fmt.Errorf("unknown type: %s", elem.Type) +} + +func isTypeFullyKnown(t tftypes.Type) bool { + if t.Is(tftypes.DynamicPseudoType) { + return false + } + switch { + case t.Is(tftypes.Object{}): + for _, att := range t.(tftypes.Object).AttributeTypes { + if !isTypeFullyKnown(att) { + return false + } + } + case t.Is(tftypes.Tuple{}): + for _, ett := range t.(tftypes.Tuple).ElementTypes { + if !isTypeFullyKnown(ett) { + return false + } + } + case t.Is(tftypes.List{}): + return isTypeFullyKnown(t.(tftypes.List).ElementType) + case t.Is(tftypes.Set{}): + return isTypeFullyKnown(t.(tftypes.Set).ElementType) + case t.Is(tftypes.Map{}): + return isTypeFullyKnown(t.(tftypes.Map).ElementType) + } + return true +} + +func schemaRefV3toV2(o *openapi3.SchemaRef) (*openapi2.SchemaRef, error) { + j, err := o.MarshalJSON() + if err != nil { + return nil, err + } + r := &openapi2.SchemaRef{} + err = r.UnmarshalJSON(j) + if err != nil { + return nil, err + } + return r, nil +} diff --git a/manifest/openapi/schema.go b/manifest/openapi/schema_v3.go similarity index 68% rename from manifest/openapi/schema.go rename to manifest/openapi/schema_v3.go index 3633b96762..29432c2847 100644 --- a/manifest/openapi/schema.go +++ b/manifest/openapi/schema_v3.go @@ -16,7 +16,7 @@ import ( "github.com/mitchellh/hashstructure" ) -func resolveSchemaRef(ref *openapi3.SchemaRef, defs map[string]*openapi3.SchemaRef) (*openapi3.Schema, error) { +func resolveSchemaRef3(ref *openapi3.SchemaRef, defs map[string]*openapi3.SchemaRef) (*openapi3.Schema, error) { if ref.Value != nil { return ref.Value, nil } @@ -37,20 +37,20 @@ func resolveSchemaRef(ref *openapi3.SchemaRef, defs map[string]*openapi3.SchemaR switch sid { case "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps": t := openapi3.Schema{ - Type: "", + Type: &openapi3.Types{""}, } return &t, nil case "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.JSONSchemaProps": t := openapi3.Schema{ - Type: "", + Type: &openapi3.Types{""}, } return &t, nil } - return resolveSchemaRef(nref, defs) + return resolveSchemaRef3(nref, defs) } -func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync.Map, defs map[string]*openapi3.SchemaRef, ap tftypes.AttributePath, th map[string]string) (tftypes.Type, error) { +func getTypeFromSchema3(elem *openapi3.Schema, stackdepth uint64, typeCache *sync.Map, defs map[string]*openapi3.SchemaRef, ap tftypes.AttributePath, th map[string]string) (tftypes.Type, error) { if stackdepth == 0 { // this is a hack to overcome the inability to express recursion in tftypes return nil, errors.New("recursion runaway while generating type from OpenAPI spec") @@ -85,23 +85,23 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync // return t.(tftypes.Type), nil // } // } - switch elem.Type { - case "string": + switch { + case elem.Type.Is("string"): if elem.Format == "int-or-string" { th[ap.String()] = "io.k8s.apimachinery.pkg.util.intstr.IntOrString" } return tftypes.String, nil - case "boolean": + case elem.Type.Is("boolean"): return tftypes.Bool, nil - case "number": + case elem.Type.Is("number"): return tftypes.Number, nil - case "integer": + case elem.Type.Is("integer"): return tftypes.Number, nil - case "": + case elem.Type.Is(""): if xv, ok := elem.Extensions["x-kubernetes-int-or-string"]; ok { xb, err := xv.(json.RawMessage).MarshalJSON() if err != nil { @@ -116,15 +116,15 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync } return tftypes.DynamicPseudoType, nil // this is where DynamicType is set for when an attribute is tagged as 'x-kubernetes-preserve-unknown-fields' - case "array": + case elem.Type.Is("array"): switch { - case elem.Items != nil && elem.AdditionalProperties == nil: // normal array - translates to a tftypes.List - it, err := resolveSchemaRef(elem.Items, defs) + case elem.Items != nil && elem.AdditionalProperties.Has == nil: // normal array - translates to a tftypes.List + it, err := resolveSchemaRef3(elem.Items, defs) if err != nil { return nil, fmt.Errorf("failed to resolve schema for items: %s", err) } aap := ap.WithElementKeyInt(-1) - et, err := getTypeFromSchema(it, stackdepth-1, typeCache, defs, *aap, th) + et, err := getTypeFromSchema3(it, stackdepth-1, typeCache, defs, *aap, th) if err != nil { return nil, err } @@ -137,13 +137,13 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync typeCache.Store(h, t) } return t, nil - case elem.AdditionalProperties != nil && elem.Items == nil: // "overriden" array - translates to a tftypes.Tuple - it, err := resolveSchemaRef(elem.AdditionalProperties, defs) + case elem.AdditionalProperties.Has != nil && *elem.AdditionalProperties.Has && elem.Items == nil: // "overriden" array - translates to a tftypes.Tuple + it, err := resolveSchemaRef3(elem.AdditionalProperties.Schema, defs) if err != nil { return nil, fmt.Errorf("failed to resolve schema for items: %s", err) } aap := ap.WithElementKeyInt(-1) - et, err := getTypeFromSchema(it, stackdepth-1, typeCache, defs, *aap, th) + et, err := getTypeFromSchema3(it, stackdepth-1, typeCache, defs, *aap, th) if err != nil { return nil, err } @@ -151,19 +151,19 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync return t, nil } - case "object": + case elem.Type.Is("object"): switch { - case elem.Properties != nil && elem.AdditionalProperties == nil: + case elem.Properties != nil && (elem.AdditionalProperties.Has == nil || !*elem.AdditionalProperties.Has): // this is a standard OpenAPI object atts := make(map[string]tftypes.Type, len(elem.Properties)) for p, v := range elem.Properties { - schema, err := resolveSchemaRef(v, defs) + schema, err := resolveSchemaRef3(v, defs) if err != nil { return nil, fmt.Errorf("failed to resolve schema: %s", err) } aap := ap.WithAttributeName(p) - pType, err := getTypeFromSchema(schema, stackdepth-1, typeCache, defs, *aap, th) + pType, err := getTypeFromSchema3(schema, stackdepth-1, typeCache, defs, *aap, th) if err != nil { return nil, err } @@ -175,14 +175,14 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync } return t, nil - case elem.Properties == nil && elem.AdditionalProperties != nil: + case elem.Properties == nil && (elem.AdditionalProperties.Has != nil && *elem.AdditionalProperties.Has): // this is how OpenAPI defines associative arrays - s, err := resolveSchemaRef(elem.AdditionalProperties, defs) + s, err := resolveSchemaRef3(elem.AdditionalProperties.Schema, defs) if err != nil { return nil, fmt.Errorf("failed to resolve schema: %s", err) } aap := ap.WithElementKeyString("#") - pt, err := getTypeFromSchema(s, stackdepth-1, typeCache, defs, *aap, th) + pt, err := getTypeFromSchema3(s, stackdepth-1, typeCache, defs, *aap, th) if err != nil { return nil, err } @@ -192,7 +192,7 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync } return t, nil - case elem.Properties == nil && elem.AdditionalProperties == nil: + case elem.Properties == nil && (elem.AdditionalProperties.Has == nil || !*elem.AdditionalProperties.Has): // this is a strange case, encountered with io.k8s.apimachinery.pkg.apis.meta.v1.FieldsV1 and also io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.CustomResourceSubresourceStatus t = tftypes.DynamicPseudoType if herr == nil { @@ -205,30 +205,3 @@ func getTypeFromSchema(elem *openapi3.Schema, stackdepth uint64, typeCache *sync return nil, fmt.Errorf("unknown type: %s", elem.Type) } - -func isTypeFullyKnown(t tftypes.Type) bool { - if t.Is(tftypes.DynamicPseudoType) { - return false - } - switch { - case t.Is(tftypes.Object{}): - for _, att := range t.(tftypes.Object).AttributeTypes { - if !isTypeFullyKnown(att) { - return false - } - } - case t.Is(tftypes.Tuple{}): - for _, ett := range t.(tftypes.Tuple).ElementTypes { - if !isTypeFullyKnown(ett) { - return false - } - } - case t.Is(tftypes.List{}): - return isTypeFullyKnown(t.(tftypes.List).ElementType) - case t.Is(tftypes.Set{}): - return isTypeFullyKnown(t.(tftypes.Set).ElementType) - case t.Is(tftypes.Map{}): - return isTypeFullyKnown(t.(tftypes.Map).ElementType) - } - return true -}