diff --git a/bin/embedded_files_test/exec_script/metadata.yml b/bin/embedded_files_test/exec_script/metadata.yml new file mode 100644 index 000000000..18c89da32 --- /dev/null +++ b/bin/embedded_files_test/exec_script/metadata.yml @@ -0,0 +1,3 @@ +name: exec_script +author: hulto +description: Copies a script and executes it. diff --git a/bin/embedded_files_test/print/metadata.yml b/bin/embedded_files_test/print/metadata.yml new file mode 100644 index 000000000..d60777b89 --- /dev/null +++ b/bin/embedded_files_test/print/metadata.yml @@ -0,0 +1,3 @@ +name: print +author: hulto +description: It just prints. diff --git a/go.mod b/go.mod index b1a37341a..ed8046bfe 100644 --- a/go.mod +++ b/go.mod @@ -13,11 +13,11 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/mattn/go-sqlite3 v1.14.16 github.com/prometheus/client_golang v1.18.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/urfave/cli v1.22.5 github.com/vektah/gqlparser/v2 v2.5.10 - golang.org/x/crypto v0.14.0 - golang.org/x/net v0.17.0 + golang.org/x/crypto v0.16.0 + golang.org/x/net v0.19.0 golang.org/x/oauth2 v0.12.0 golang.org/x/sync v0.4.0 google.golang.org/grpc v1.59.0 @@ -25,6 +25,25 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) +require ( + dario.cat/mergo v1.0.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect +) + require ( ariga.io/atlas v0.14.2 // indirect cloud.google.com/go/compute v1.23.0 // indirect @@ -36,6 +55,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-git/go-git/v5 v5.11.0 github.com/go-openapi/inflect v0.19.0 // indirect github.com/google/uuid v1.3.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -57,7 +77,7 @@ require ( golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect diff --git a/go.sum b/go.sum index a4e4917f8..2ecc8adc2 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopT cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= entgo.io/contrib v0.4.5 h1:BFaOHwFLE8WZjVJadP0XHCIaxgcC1BAtUvAyw7M/GHk= entgo.io/contrib v0.4.5/go.mod h1:wpZyq2DJgthugFvDBlaqMXj9mV4/9ebyGEn7xlTVQqE= entgo.io/ent v0.12.4 h1:LddPnAyxls/O7DTXZvUGDj0NZIdGSu317+aoNLJWbD8= @@ -12,27 +14,50 @@ github.com/99designs/gqlgen v0.17.39 h1:wPTAyc2fqVjAWT5DsJ21k/lLudgnXzURwbsjVNeg github.com/99designs/gqlgen v0.17.39/go.mod h1:b62q1USk82GYIVjC60h02YguAZLqYZtvWml8KkhJps4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= @@ -40,6 +65,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -60,7 +87,14 @@ github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPD github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo= github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +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/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= @@ -71,6 +105,11 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= @@ -81,22 +120,24 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= 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/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU= @@ -105,32 +146,79 @@ github.com/vmihailenco/msgpack/v5 v5.4.0 h1:hRM0digJwyR6vll33NNAwCFguy5JuBD6jxDm github.com/vmihailenco/msgpack/v5 v5.4.0/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -143,9 +231,12 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/implants/lib/eldritch/src/assets/list_impl.rs b/implants/lib/eldritch/src/assets/list_impl.rs index 4185c3c60..9354fae83 100644 --- a/implants/lib/eldritch/src/assets/list_impl.rs +++ b/implants/lib/eldritch/src/assets/list_impl.rs @@ -23,7 +23,9 @@ mod tests { "exec_script/hello_world.bat", "exec_script/hello_world.sh", "exec_script/main.eldritch", - "print/main.eldritch" + "exec_script/metadata.yml", + "print/main.eldritch", + "print/metadata.yml", ] ); diff --git a/tavern/internal/c2/c2test/grpc.go b/tavern/internal/c2/c2test/grpc.go index f3ffe6e96..a55997215 100644 --- a/tavern/internal/c2/c2test/grpc.go +++ b/tavern/internal/c2/c2test/grpc.go @@ -55,7 +55,7 @@ func New(t *testing.T) (c2pb.C2Client, *ent.Client, func()) { baseSrv.Stop() assert.NoError(t, graph.Close()) if err := <-grpcErrCh; err != nil && !errors.Is(err, grpc.ErrServerStopped) { - t.Fatalf("failed to serve grpc") + t.Fatalf("failed to serve grpc: %v", err) } } } diff --git a/tavern/internal/graphql/generated/inputs.generated.go b/tavern/internal/graphql/generated/inputs.generated.go index 90aa66b05..3e3f82c52 100644 --- a/tavern/internal/graphql/generated/inputs.generated.go +++ b/tavern/internal/graphql/generated/inputs.generated.go @@ -110,6 +110,44 @@ func (ec *executionContext) unmarshalInputClaimTasksInput(ctx context.Context, o return it, nil } +func (ec *executionContext) unmarshalInputImportTomesFromGitInput(ctx context.Context, obj interface{}) (models.ImportTomesFromGitInput, error) { + var it models.ImportTomesFromGitInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"gitURL", "includeDirs"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "gitURL": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gitURL")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.GitURL = data + case "includeDirs": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDirs")) + data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + it.IncludeDirs = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputSubmitTaskResultInput(ctx context.Context, obj interface{}) (models.SubmitTaskResultInput, error) { var it models.SubmitTaskResultInput asMap := map[string]interface{}{} @@ -187,4 +225,9 @@ func (ec *executionContext) unmarshalInputSubmitTaskResultInput(ctx context.Cont // region ***************************** type.gotpl ***************************** +func (ec *executionContext) unmarshalNImportTomesFromGitInput2realmᚗpubᚋtavernᚋinternalᚋgraphqlᚋmodelsᚐImportTomesFromGitInput(ctx context.Context, v interface{}) (models.ImportTomesFromGitInput, error) { + res, err := ec.unmarshalInputImportTomesFromGitInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + // endregion ***************************** type.gotpl ***************************** diff --git a/tavern/internal/graphql/generated/mutation.generated.go b/tavern/internal/graphql/generated/mutation.generated.go index a40ae78ee..c283a1656 100644 --- a/tavern/internal/graphql/generated/mutation.generated.go +++ b/tavern/internal/graphql/generated/mutation.generated.go @@ -12,6 +12,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/ast" "realm.pub/tavern/internal/ent" + "realm.pub/tavern/internal/graphql/models" ) // region ************************** generated!.gotpl ************************** @@ -23,6 +24,7 @@ type MutationResolver interface { UpdateHost(ctx context.Context, hostID int, input ent.UpdateHostInput) (*ent.Host, error) CreateTag(ctx context.Context, input ent.CreateTagInput) (*ent.Tag, error) UpdateTag(ctx context.Context, tagID int, input ent.UpdateTagInput) (*ent.Tag, error) + ImportTomesFromGit(ctx context.Context, input models.ImportTomesFromGitInput) ([]*ent.Tome, error) CreateTome(ctx context.Context, input ent.CreateTomeInput) (*ent.Tome, error) UpdateTome(ctx context.Context, tomeID int, input ent.UpdateTomeInput) (*ent.Tome, error) DeleteTome(ctx context.Context, tomeID int) (int, error) @@ -102,6 +104,21 @@ func (ec *executionContext) field_Mutation_deleteTome_args(ctx context.Context, return args, nil } +func (ec *executionContext) field_Mutation_importTomesFromGit_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 models.ImportTomesFromGitInput + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNImportTomesFromGitInput2realmᚗpubᚋtavernᚋinternalᚋgraphqlᚋmodelsᚐImportTomesFromGitInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_updateBeacon_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -782,6 +799,108 @@ func (ec *executionContext) fieldContext_Mutation_updateTag(ctx context.Context, return fc, nil } +func (ec *executionContext) _Mutation_importTomesFromGit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_importTomesFromGit(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ImportTomesFromGit(rctx, fc.Args["input"].(models.ImportTomesFromGitInput)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNRole2realmᚗpubᚋtavernᚋinternalᚋgraphqlᚋmodelsᚐRole(ctx, "USER") + if err != nil { + return nil, err + } + if ec.directives.RequireRole == nil { + return nil, errors.New("directive requireRole is not implemented") + } + return ec.directives.RequireRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.([]*ent.Tome); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*realm.pub/tavern/internal/ent.Tome`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*ent.Tome) + fc.Result = res + return ec.marshalOTome2ᚕᚖrealmᚗpubᚋtavernᚋinternalᚋentᚐTomeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_importTomesFromGit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tome_id(ctx, field) + case "createdAt": + return ec.fieldContext_Tome_createdAt(ctx, field) + case "lastModifiedAt": + return ec.fieldContext_Tome_lastModifiedAt(ctx, field) + case "name": + return ec.fieldContext_Tome_name(ctx, field) + case "description": + return ec.fieldContext_Tome_description(ctx, field) + case "author": + return ec.fieldContext_Tome_author(ctx, field) + case "supportModel": + return ec.fieldContext_Tome_supportModel(ctx, field) + case "tactic": + return ec.fieldContext_Tome_tactic(ctx, field) + case "paramDefs": + return ec.fieldContext_Tome_paramDefs(ctx, field) + case "eldritch": + return ec.fieldContext_Tome_eldritch(ctx, field) + case "files": + return ec.fieldContext_Tome_files(ctx, field) + case "uploader": + return ec.fieldContext_Tome_uploader(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tome", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_importTomesFromGit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_createTome(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_createTome(ctx, field) if err != nil { @@ -1231,6 +1350,10 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "importTomesFromGit": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_importTomesFromGit(ctx, field) + }) case "createTome": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_createTome(ctx, field) diff --git a/tavern/internal/graphql/generated/root_.generated.go b/tavern/internal/graphql/generated/root_.generated.go index 1f756a40d..64b917be0 100644 --- a/tavern/internal/graphql/generated/root_.generated.go +++ b/tavern/internal/graphql/generated/root_.generated.go @@ -127,16 +127,17 @@ type ComplexityRoot struct { } Mutation struct { - CreateQuest func(childComplexity int, beaconIDs []int, input ent.CreateQuestInput) int - CreateTag func(childComplexity int, input ent.CreateTagInput) int - CreateTome func(childComplexity int, input ent.CreateTomeInput) int - DeleteTome func(childComplexity int, tomeID int) int - DropAllData func(childComplexity int) int - UpdateBeacon func(childComplexity int, beaconID int, input ent.UpdateBeaconInput) int - UpdateHost func(childComplexity int, hostID int, input ent.UpdateHostInput) int - UpdateTag func(childComplexity int, tagID int, input ent.UpdateTagInput) int - UpdateTome func(childComplexity int, tomeID int, input ent.UpdateTomeInput) int - UpdateUser func(childComplexity int, userID int, input ent.UpdateUserInput) int + CreateQuest func(childComplexity int, beaconIDs []int, input ent.CreateQuestInput) int + CreateTag func(childComplexity int, input ent.CreateTagInput) int + CreateTome func(childComplexity int, input ent.CreateTomeInput) int + DeleteTome func(childComplexity int, tomeID int) int + DropAllData func(childComplexity int) int + ImportTomesFromGit func(childComplexity int, input models.ImportTomesFromGitInput) int + UpdateBeacon func(childComplexity int, beaconID int, input ent.UpdateBeaconInput) int + UpdateHost func(childComplexity int, hostID int, input ent.UpdateHostInput) int + UpdateTag func(childComplexity int, tagID int, input ent.UpdateTagInput) int + UpdateTome func(childComplexity int, tomeID int, input ent.UpdateTomeInput) int + UpdateUser func(childComplexity int, userID int, input ent.UpdateUserInput) int } PageInfo struct { @@ -754,6 +755,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.DropAllData(childComplexity), true + case "Mutation.importTomesFromGit": + if e.complexity.Mutation.ImportTomesFromGit == nil { + break + } + + args, err := ec.field_Mutation_importTomesFromGit_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ImportTomesFromGit(childComplexity, args["input"].(models.ImportTomesFromGitInput)), true + case "Mutation.updateBeacon": if e.complexity.Mutation.UpdateBeacon == nil { break @@ -1343,6 +1356,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputHostProcessOrder, ec.unmarshalInputHostProcessWhereInput, ec.unmarshalInputHostWhereInput, + ec.unmarshalInputImportTomesFromGitInput, ec.unmarshalInputQuestOrder, ec.unmarshalInputQuestWhereInput, ec.unmarshalInputSubmitTaskResultInput, @@ -3240,6 +3254,7 @@ scalar Uint64 ### # Tome ### + importTomesFromGit(input: ImportTomesFromGitInput!,): [Tome!] @requireRole(role: USER) createTome(input: CreateTomeInput!,): Tome! @requireRole(role: USER) updateTome(tomeID: ID!, input: UpdateTomeInput!,): Tome! @requireRole(role: ADMIN) deleteTome(tomeID: ID!): ID! @requireRole(role: ADMIN) @@ -3292,6 +3307,16 @@ input SubmitTaskResultInput { """Error message captured as the result of task execution failure.""" error: String } +input ImportTomesFromGitInput { + """Specify a git URL to obtain the tomes from.""" + gitURL: String! + + """ + Optionally, specify directories to include. + Only tomes that have a main.eldritch in one of these directory prefixes will be included. + """ + includeDirs: [String!] +} `, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) diff --git a/tavern/internal/graphql/models/gqlgen_models.go b/tavern/internal/graphql/models/gqlgen_models.go index 08a2f6115..cf4eec5b9 100644 --- a/tavern/internal/graphql/models/gqlgen_models.go +++ b/tavern/internal/graphql/models/gqlgen_models.go @@ -28,6 +28,14 @@ type ClaimTasksInput struct { AgentIdentifier string `json:"agentIdentifier"` } +type ImportTomesFromGitInput struct { + // Specify a git URL to obtain the tomes from. + GitURL string `json:"gitURL"` + // Optionally, specify directories to include. + // Only tomes that have a main.eldritch in one of these directory prefixes will be included. + IncludeDirs []string `json:"includeDirs,omitempty"` +} + type SubmitTaskResultInput struct { // ID of the task to submit results for. TaskID int `json:"taskID"` diff --git a/tavern/internal/graphql/mutation.resolvers.go b/tavern/internal/graphql/mutation.resolvers.go index 704071ad5..484bcc574 100644 --- a/tavern/internal/graphql/mutation.resolvers.go +++ b/tavern/internal/graphql/mutation.resolvers.go @@ -7,11 +7,14 @@ package graphql import ( "context" "fmt" + "strings" "realm.pub/tavern/internal/auth" "realm.pub/tavern/internal/ent" "realm.pub/tavern/internal/ent/file" "realm.pub/tavern/internal/graphql/generated" + "realm.pub/tavern/internal/graphql/models" + "realm.pub/tavern/tomes" ) // DropAllData is the resolver for the dropAllData field. @@ -157,6 +160,35 @@ func (r *mutationResolver) UpdateTag(ctx context.Context, tagID int, input ent.U return r.client.Tag.UpdateOneID(tagID).SetInput(input).Save(ctx) } +// ImportTomesFromGit is the resolver for the importTomesFromGit field. +func (r *mutationResolver) ImportTomesFromGit(ctx context.Context, input models.ImportTomesFromGitInput) ([]*ent.Tome, error) { + // Ensure a schema is set (or set https:// by default) + gitURL := input.GitURL + if !strings.HasPrefix(gitURL, "http://") && !strings.HasPrefix(gitURL, "ssh://") { + gitURL = fmt.Sprintf("https://%s", gitURL) + } + + if input.IncludeDirs == nil { + return tomes.ImportFromRepo(ctx, r.client, input.GitURL) + } + + // Filter to only include provided directories + filter := func(path string) bool { + for _, prefix := range input.IncludeDirs { + // Ignore Leading / + path = strings.TrimPrefix(path, "/") + prefix = strings.TrimPrefix(prefix, "/") + + // Include if matching + if strings.HasPrefix(path, prefix) { + return true + } + } + return false + } + return tomes.ImportFromRepo(ctx, r.client, gitURL, filter) +} + // CreateTome is the resolver for the createTome field. func (r *mutationResolver) CreateTome(ctx context.Context, input ent.CreateTomeInput) (*ent.Tome, error) { var uploaderID *int diff --git a/tavern/internal/graphql/schema.graphql b/tavern/internal/graphql/schema.graphql index ec32dbc34..d0c11d6a0 100644 --- a/tavern/internal/graphql/schema.graphql +++ b/tavern/internal/graphql/schema.graphql @@ -1760,6 +1760,16 @@ input SubmitTaskResultInput { """Error message captured as the result of task execution failure.""" error: String } +input ImportTomesFromGitInput { + """Specify a git URL to obtain the tomes from.""" + gitURL: String! + + """ + Optionally, specify directories to include. + Only tomes that have a main.eldritch in one of these directory prefixes will be included. + """ + includeDirs: [String!] +} type Mutation { #### # Admin @@ -1790,6 +1800,7 @@ type Mutation { ### # Tome ### + importTomesFromGit(input: ImportTomesFromGitInput!,): [Tome!] @requireRole(role: USER) createTome(input: CreateTomeInput!,): Tome! @requireRole(role: USER) updateTome(tomeID: ID!, input: UpdateTomeInput!,): Tome! @requireRole(role: ADMIN) deleteTome(tomeID: ID!): ID! @requireRole(role: ADMIN) diff --git a/tavern/internal/graphql/schema/inputs.graphql b/tavern/internal/graphql/schema/inputs.graphql index 507210c87..a752a22fb 100644 --- a/tavern/internal/graphql/schema/inputs.graphql +++ b/tavern/internal/graphql/schema/inputs.graphql @@ -40,3 +40,13 @@ input SubmitTaskResultInput { """Error message captured as the result of task execution failure.""" error: String } +input ImportTomesFromGitInput { + """Specify a git URL to obtain the tomes from.""" + gitURL: String! + + """ + Optionally, specify directories to include. + Only tomes that have a main.eldritch in one of these directory prefixes will be included. + """ + includeDirs: [String!] +} diff --git a/tavern/internal/graphql/schema/mutation.graphql b/tavern/internal/graphql/schema/mutation.graphql index 34cbc0a8e..418792755 100644 --- a/tavern/internal/graphql/schema/mutation.graphql +++ b/tavern/internal/graphql/schema/mutation.graphql @@ -28,6 +28,7 @@ type Mutation { ### # Tome ### + importTomesFromGit(input: ImportTomesFromGitInput!,): [Tome!] @requireRole(role: USER) createTome(input: CreateTomeInput!,): Tome! @requireRole(role: USER) updateTome(tomeID: ID!, input: UpdateTomeInput!,): Tome! @requireRole(role: ADMIN) deleteTome(tomeID: ID!): ID! @requireRole(role: ADMIN) diff --git a/tavern/internal/www/schema.graphql b/tavern/internal/www/schema.graphql index ec32dbc34..d0c11d6a0 100644 --- a/tavern/internal/www/schema.graphql +++ b/tavern/internal/www/schema.graphql @@ -1760,6 +1760,16 @@ input SubmitTaskResultInput { """Error message captured as the result of task execution failure.""" error: String } +input ImportTomesFromGitInput { + """Specify a git URL to obtain the tomes from.""" + gitURL: String! + + """ + Optionally, specify directories to include. + Only tomes that have a main.eldritch in one of these directory prefixes will be included. + """ + includeDirs: [String!] +} type Mutation { #### # Admin @@ -1790,6 +1800,7 @@ type Mutation { ### # Tome ### + importTomesFromGit(input: ImportTomesFromGitInput!,): [Tome!] @requireRole(role: USER) createTome(input: CreateTomeInput!,): Tome! @requireRole(role: USER) updateTome(tomeID: ID!, input: UpdateTomeInput!,): Tome! @requireRole(role: ADMIN) deleteTome(tomeID: ID!): ID! @requireRole(role: ADMIN) diff --git a/tavern/tomes/git.go b/tavern/tomes/git.go new file mode 100644 index 000000000..ec9d8bcb7 --- /dev/null +++ b/tavern/tomes/git.go @@ -0,0 +1,253 @@ +package tomes + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/url" + "path/filepath" + "strings" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/filemode" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/storage/memory" + "gopkg.in/yaml.v3" + "realm.pub/tavern/internal/ent" + "realm.pub/tavern/internal/ent/tome" +) + +// ImportFromRepo clones a git repository from the provided URL in memory. +// It walks the directory structure, looking for 'main.eldritch' files. +// For each 'main.eldritch' file found, it's parent directory is treated as the tome's root. +// All files in that directory and it's subdirectories (recursively) aside from the reserved +// metadata.yml file are uploaded as the tome's assets. + +// Provided filters on tome paths may be used to exclude directories by returning true if the +// result should be included. +func ImportFromRepo(ctx context.Context, graph *ent.Client, gitURL string, filters ...func(path string) bool) ([]*ent.Tome, error) { + // Clone Repository (In-Memory) + storage := memory.NewStorage() + repo, err := git.CloneContext(ctx, storage, nil, &git.CloneOptions{ + URL: gitURL, + SingleBranch: true, + Depth: 1, + Tags: git.NoTags, + }) + if err != nil { + return nil, fmt.Errorf("failed to clone: %w", err) + } + + // Get HEAD + head, err := repo.Head() + if err != nil { + return nil, fmt.Errorf("failed to get repository HEAD: %w", err) + } + + // Get Commit + commit, err := repo.CommitObject(head.Hash()) + if err != nil { + return nil, fmt.Errorf("failed to get commit object (HEAD): %w", err) + } + + // Get Root File Tree + tree, err := repo.TreeObject(commit.TreeHash) + if err != nil { + return nil, fmt.Errorf("failed to get tree (%q): %w", commit.Hash, err) + } + + // Get Tome Paths + tomePaths, err := findTomePaths(tree) + if err != nil { + return nil, err + } + + // Import Tomes + namespace := parseNamespaceFromGit(gitURL) + tomes := make([]*ent.Tome, 0, len(tomePaths)) + for _, path := range tomePaths { + // Apply Filters + include := true + for _, filter := range filters { + if !filter(path) { + include = false + break + } + } + if !include { + continue + } + + // Import Tome + tome, err := importFromGitTree(ctx, repo, namespace, tree, path, graph) + if err != nil { + return nil, fmt.Errorf("failed to import tome (%q): %w", path, err) + } + tomes = append(tomes, tome) + } + + return tomes, nil +} + +// findTomePaths returns a list of valid paths to the root directory of a Tome. +// This is based on all of the 'main.eldritch' files found in the repository. +func findTomePaths(tree *object.Tree) ([]string, error) { + var tomePaths []string + walker := object.NewTreeWalker(tree, true, make(map[plumbing.Hash]bool)) + defer walker.Close() + for { + // Fetch next entry + name, _, err := walker.Next() + if err == io.EOF { + // No more entries + break + } + if err != nil { + return nil, fmt.Errorf("failed to walk repo tree: %w", err) + } + + // If 'main.eldritch' is present, the parent directory is the tome root + base := filepath.Base(name) + if base == "main.eldritch" { + // Cannot use filepath.Dir on Windows, git does not use \ separators + tomePaths = append( + tomePaths, + strings.TrimSuffix( + strings.TrimSuffix(name, base), // Get the directory name + "/", // Remove the trailing / + ), + ) + } + } + + return tomePaths, nil +} + +// ImportFromGitTree imports a tome based on the provided path +func importFromGitTree(ctx context.Context, repo *git.Repository, namespace string, root *object.Tree, path string, graph *ent.Client) (*ent.Tome, error) { + tree, err := root.Tree(path) + if err != nil { + return nil, fmt.Errorf("failed to get tome tree (%q): %w", path, err) + } + + walker := object.NewTreeWalker(tree, true, make(map[plumbing.Hash]bool)) + defer walker.Close() + + var metadata MetadataDefinition + var eldritch string + var tomeFileIDs []int + // Iterate Tome Files + for { + name, entry, err := walker.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, fmt.Errorf("failed to walk tome tree (%q): %w", name, err) + } + + // Skip Directory Files + if entry.Mode == filemode.Dir { + continue + } + + // Read File Data + blob, err := repo.BlobObject(entry.Hash) + if err != nil { + return nil, fmt.Errorf("failed to get tome blob (%q): %w", name, err) + } + reader, err := blob.Reader() + if err != nil { + return nil, fmt.Errorf("failed to get tome blob reader (%q): %w", name, err) + } + defer reader.Close() + data, err := io.ReadAll(reader) + if err != nil { + return nil, fmt.Errorf("failed to read tome file (%q): %w", name, err) + } + + // Parse metadata.yml + if filepath.Base(name) == "metadata.yml" { + if err := yaml.Unmarshal(data, &metadata); err != nil { + return nil, fmt.Errorf("failed to parse tome metadata %q: %w", name, err) + } + if err := metadata.Validate(); err != nil { + return nil, fmt.Errorf("invalid tome metadata %q: %w", name, err) + } + + continue + } + + // Parse main.eldritch + if filepath.Base(name) == "main.eldritch" { + eldritch = string(data) + continue + } + + // Upload other files + // TODO: Namespace tomes to prevent multi-repo conflicts + fileID, err := graph.File.Create(). + SetName(fmt.Sprintf("%s/%s", filepath.Base(path), name)). + SetContent(data). + OnConflict(). + UpdateNewValues(). + ID(ctx) + if err != nil { + return nil, fmt.Errorf("failed to upload tome file %q: %w", name, err) + } + tomeFileIDs = append(tomeFileIDs, fileID) + } + + // Ensure Metadata was found + if metadata.Name == "" { + return nil, fmt.Errorf("tome must include 'metadata.yml' file (%q)", path) + } + + // Ensure Eldritch not empty + if eldritch == "" { + return nil, fmt.Errorf("tome must include non-empty 'eldritch.main' file (%q)", path) + } + + // Marshal Params + paramdefs, err := json.Marshal(metadata.ParamDefs) + if err != nil { + return nil, fmt.Errorf("failed to marshal param defs for %q: %w", path, err) + } + + // Create the tome + tomeID, err := graph.Tome.Create(). + SetName(fmt.Sprintf("%s::%s", namespace, metadata.Name)). + SetDescription(metadata.Description). + SetAuthor(metadata.Author). + SetParamDefs(string(paramdefs)). + SetSupportModel(tome.SupportModelCOMMUNITY). + SetTactic(tome.Tactic(metadata.Tactic)). + SetEldritch(eldritch). + AddFileIDs(tomeFileIDs...). + OnConflict(). + UpdateNewValues(). + ID(ctx) + if err != nil { + return nil, fmt.Errorf("failed to create tome %q: %w", metadata.Name, err) + } + + return graph.Tome.Get(ctx, tomeID) +} + +// parseNamespaceFromGit attempts to return a shortend namespace for the tome based on the git URL. +// If it cannot or something goes wrong, this will return the provided git URL as the namespace. +func parseNamespaceFromGit(gitURLStr string) string { + gitURL, err := url.Parse(gitURLStr) + if err != nil { + return gitURLStr + } + + // Support more pleasant names for github + if gitURL.Host == "github.com" { + return strings.Trim(gitURL.Path, "/") + } + + return gitURLStr +} diff --git a/tavern/tomes/git_test.go b/tavern/tomes/git_test.go new file mode 100644 index 000000000..a2ae961ef --- /dev/null +++ b/tavern/tomes/git_test.go @@ -0,0 +1,44 @@ +package tomes_test + +import ( + "context" + "path/filepath" + "strings" + "testing" + + _ "github.com/mattn/go-sqlite3" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "realm.pub/tavern/internal/ent/enttest" + "realm.pub/tavern/internal/ent/tome" + "realm.pub/tavern/tomes" +) + +func TestImportFromRepo(t *testing.T) { + localGit := filepath.Join("..", "..", "..", "realm") + ctx := context.Background() + var ( + driverName = "sqlite3" + dataSourceName = "file:ent?mode=memory&cache=shared&_fk=1" + ) + graph := enttest.Open(t, driverName, dataSourceName, enttest.WithOptions()) + defer graph.Close() + + filter := func(path string) bool { + return strings.Contains(path, "example") + } + _, err := tomes.ImportFromRepo(ctx, graph, localGit, filter) + require.NoError(t, err) + + testTome := graph.Tome.Query(). + Where(tome.NameContains("example")). + OnlyX(ctx) + require.NotNil(t, testTome) + assert.Equal(t, "print(input_params['msg'])", strings.TrimSpace(testTome.Eldritch)) + assert.Equal(t, `An example tome!`, testTome.Description) + assert.Equal(t, `[{"name":"msg","label":"Message","type":"string","placeholder":"Something to print"}]`, testTome.ParamDefs) + testTomeFiles, err := testTome.Files(ctx) + assert.NoError(t, err) + assert.Len(t, testTomeFiles, 1) + assert.Equal(t, []byte("This file exists"), testTomeFiles[0].Content) +} diff --git a/tavern/tomes/parse.go b/tavern/tomes/parse.go index 2355b833e..9a3dab079 100644 --- a/tavern/tomes/parse.go +++ b/tavern/tomes/parse.go @@ -39,7 +39,8 @@ func (paramDef ParamDefinition) Validate() error { return nil } -type metadataDefinition struct { +// MetadataDefinition defines the contents that should be present in all tome metadata.yml files +type MetadataDefinition struct { Name string `yaml:"name"` Description string `yaml:"description"` Author string `yaml:"author"` @@ -48,6 +49,25 @@ type metadataDefinition struct { ParamDefs []ParamDefinition } +// Validate ensures the Tome metadata has been properly configured. +func (meta MetadataDefinition) Validate() error { + if meta.Name == "" { + return fmt.Errorf("must set 'name'") + } + if meta.Author == "" { + return fmt.Errorf("must set 'author'") + } + if meta.Description == "" { + return fmt.Errorf("must set 'description'") + } + for _, paramDef := range meta.ParamDefs { + if err := paramDef.Validate(); err != nil { + return fmt.Errorf("invalid parameter definition (%q): %w", meta.Name, err) + } + } + return nil +} + // UploadTomes traverses the provided filesystem and creates tomes using the provided graph. // Each directory at the root of the filesystem is a tome, and must contain the required // "metadata.yml" and "main.eldritch" files. You may use the tomes.FileSystem to include the @@ -78,7 +98,7 @@ func UploadTomes(ctx context.Context, graph *ent.Client, fileSystem fs.ReadDirFS continue } - var metadata metadataDefinition + var metadata MetadataDefinition var eldritch string var tomeFiles []*ent.File if err := fs.WalkDir(fileSystem, entry.Name(), func(path string, d fs.DirEntry, err error) error { @@ -101,14 +121,11 @@ func UploadTomes(ctx context.Context, graph *ent.Client, fileSystem fs.ReadDirFS if err := yaml.Unmarshal(content, &metadata); err != nil { return rollback(tx, fmt.Errorf("failed to parse %q: %w", path, err)) } - return nil - } - - // Validate Params - for _, paramDef := range metadata.ParamDefs { - if err := paramDef.Validate(); err != nil { - return rollback(tx, fmt.Errorf("failed to validate tome parameter definition: %w", err)) + // Validate Metadata + if err := metadata.Validate(); err != nil { + return rollback(tx, fmt.Errorf("invalid tome metadata %q: %w", entry.Name(), err)) } + return nil } // Parse main.eldritch @@ -132,6 +149,7 @@ func UploadTomes(ctx context.Context, graph *ent.Client, fileSystem fs.ReadDirFS return rollback(tx, fmt.Errorf("failed to parse and upload tome %q: %w", entry.Name(), err)) } + // Marshal Params paramdefs, err := json.Marshal(metadata.ParamDefs) if err != nil { return rollback(tx, fmt.Errorf("failed to parse param defs for %q: %w", metadata.Name, err)) diff --git a/tavern/tomes/parse_test.go b/tavern/tomes/parse_test.go index 64f371730..c48b803d6 100644 --- a/tavern/tomes/parse_test.go +++ b/tavern/tomes/parse_test.go @@ -23,7 +23,7 @@ func TestUploadTomes(t *testing.T) { // Assert our example tome is there require.NoError(t, tomes.UploadTomes(ctx, graph, tomes.FileSystem)) testTome := graph.Tome.Query(). - Where(tome.Name("example")). + Where(tome.NameContains("Example")). OnlyX(ctx) require.NotNil(t, testTome) assert.Equal(t, "print(input_params['msg'])", strings.TrimSpace(testTome.Eldritch))