diff --git a/go.mod b/go.mod index 266a4f782..d6869aec4 100644 --- a/go.mod +++ b/go.mod @@ -154,7 +154,7 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/go-git/go-git/v5 v5.14.0 // indirect + github.com/go-git/go-git/v5 v5.16.5 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/go.sum b/go.sum index 2736677bc..4949afadd 100644 --- a/go.sum +++ b/go.sum @@ -62,7 +62,6 @@ github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8 github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -224,8 +223,6 @@ github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQ github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/checkmarx/2ms/v3 v3.21.0 h1:EcabeDypNMsSidISQbziZ062HjMZQ+Hm/uOJ5AOxK8o= github.com/checkmarx/2ms/v3 v3.21.0/go.mod h1:e8f4F94MZ+iCetR/G3aw7nXdPe6TgPI92Zzk/NG1l0o= -github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA= -github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= @@ -235,8 +232,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= -github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -254,8 +249,6 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo= github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= -github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc= -github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE= github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0= @@ -284,11 +277,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= -github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= @@ -402,8 +391,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= -github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s= +github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -445,8 +434,6 @@ github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u1 github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -791,8 +778,6 @@ 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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm/Q= -github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4= github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -820,8 +805,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opencontainers/runc v1.2.8 h1:RnEICeDReapbZ5lZEgHvj7E9Q3Eex9toYmaGBsbvU5Q= -github.com/opencontainers/runc v1.2.8/go.mod h1:cC0YkmZcuvr+rtBZ6T7NBoVbMGNAdLa/21vIElJDOzI= github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84= @@ -925,8 +908,6 @@ github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEW github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d h1:RQqyEogx5J6wPdoxqL132b100j8KjcVHO1c0KLRoIhc= github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d/go.mod h1:PegD7EVqlN88z7TpCqH92hHP+GBpfomGCCnw1PFtNOA= -github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY= -github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= @@ -960,7 +941,6 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -997,8 +977,6 @@ github.com/sylabs/sif/v2 v2.21.1 h1:GZ0b5//AFAqJEChd8wHV/uSKx/l1iuGYwjR8nx+4wPI= github.com/sylabs/sif/v2 v2.21.1/go.mod h1:YoqEGQnb5x/ItV653bawXHZJOXQaEWpGwHsSD3YePJI= github.com/sylabs/squashfs v1.0.6 h1:PvJcDzxr+vIm2kH56mEMbaOzvGu79gK7P7IX+R7BDZI= github.com/sylabs/squashfs v1.0.6/go.mod h1:DlDeUawVXLWAsSRa085Eo0ZenGzAB32JdAUFaB0LZfE= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= @@ -1009,19 +987,12 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= -github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/vbatts/go-mtree v0.5.4 h1:OMAb8jaCyiFA7zXj0Zc/oARcxBDBoeu2LizjB8BVJl0= github.com/vbatts/go-mtree v0.5.4/go.mod h1:5GqJbVhm9BBiCc4K5uc/c42FPgXulHaQs4sFUEfIWMo= github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0= github.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o= -github.com/vishvananda/netlink v1.3.1-0.20250303224720-0e7078ed04c8 h1:Y4egeTrP7sccowz2GWTJVtHlwkZippgBTpUmMteFUWQ= -github.com/vishvananda/netlink v1.3.1-0.20250303224720-0e7078ed04c8/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= -github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= -github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA= github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20= github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 h1:0KGbf+0SMg+UFy4e1A/CPVvXn21f1qtWdeJwxZFoQG8= @@ -1343,11 +1314,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.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.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -1589,7 +1557,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/internal/commands/asca/asca-engine.go b/internal/commands/asca/asca-engine.go index 5cde76171..cad19fd74 100644 --- a/internal/commands/asca/asca-engine.go +++ b/internal/commands/asca/asca-engine.go @@ -1,21 +1,42 @@ package asca import ( + "strings" + "github.com/checkmarx/ast-cli/internal/commands/util/printer" commonParams "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/services" "github.com/checkmarx/ast-cli/internal/wrappers" "github.com/checkmarx/ast-cli/internal/wrappers/grpcs" + "github.com/checkmarx/ast-cli/internal/wrappers/utils" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" ) +const ( + ascaLocationParam = "asca-location" +) + func RunScanASCACommand(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + var vorpalLocation string ASCALatestVersion, _ := cmd.Flags().GetBool(commonParams.ASCALatestVersion) fileSourceFlag, _ := cmd.Flags().GetString(commonParams.SourcesFlag) ignoredFilePathFlag, _ := cmd.Flags().GetString(commonParams.IgnoredFilePathFlag) agent, _ := cmd.Flags().GetString(commonParams.AgentFlag) + err := validateASCALocationFlags(cmd) + if err != nil { + return err + } + + vorpal := strings.TrimSpace(viper.GetString(commonParams.ASCALocationKey)) + if vorpal != "" { + vorpalLocation = vorpal + } else if location := utils.GetOptionalParam(ascaLocationParam); location != "" { + vorpalLocation = location + } + var port = viper.GetInt(commonParams.ASCAPortKey) ASCAWrapper := grpcs.NewASCAGrpcWrapper(port) ASCAParams := services.AscaScanParams{ @@ -23,7 +44,9 @@ func RunScanASCACommand(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, ASCAUpdateVersion: ASCALatestVersion, IsDefaultAgent: agent == commonParams.DefaultAgent, IgnoredFilePath: ignoredFilePathFlag, + VorpalLocation: vorpalLocation, } + wrapperParams := services.AscaWrappersParam{ JwtWrapper: jwtWrapper, ASCAWrapper: ASCAWrapper, @@ -32,7 +55,6 @@ func RunScanASCACommand(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, if err != nil { return err } - err = printer.Print(cmd.OutOrStdout(), scanResult, printer.FormatJSON) if err != nil { return err @@ -41,3 +63,16 @@ func RunScanASCACommand(jwtWrapper wrappers.JWTWrapper) func(cmd *cobra.Command, return nil } } + +func validateASCALocationFlags(cmd *cobra.Command) error { + if cmd.Flags().Changed(commonParams.ASCALocationFlag) { + flagVal, err := cmd.Flags().GetString(commonParams.ASCALocationFlag) + if err != nil { + return err + } + if strings.TrimSpace(flagVal) == "" { + return errors.Errorf("%s flag is provided but empty", commonParams.ASCALocationFlag) + } + } + return nil +} diff --git a/internal/commands/asca/asca-engine_test.go b/internal/commands/asca/asca-engine_test.go index 379612d9c..bac822da7 100644 --- a/internal/commands/asca/asca-engine_test.go +++ b/internal/commands/asca/asca-engine_test.go @@ -75,6 +75,7 @@ func Test_ExecuteAscaScan(t *testing.T) { JwtWrapper: &mock.JWTMockWrapper{}, ASCAWrapper: &mock.ASCAMockWrapper{}, } + // No CustomVorpal Location got, err := services.CreateASCAScanRequest(ASCAParams, wrapperParams) if (err != nil) != ttt.wantErr { t.Errorf("executeASCAScan() error = %v, wantErr %v", err, ttt.wantErr) @@ -140,3 +141,59 @@ func Test_runScanASCACommand(t *testing.T) { }) } } + +func Test_runScanASCAWithAscaLocationFlagCommand(t *testing.T) { + tests := []struct { + name string + sourceFlag string + engineFlag bool + ascaLocation string + wantErr bool + want *grpcs.ScanResult + wantErrMsg string + }{ + { + name: "Test with empty fileSourceFlag", + sourceFlag: "", + engineFlag: true, + ascaLocation: "C:/Users/test/Downloads/vorpal.exe", + wantErr: false, + want: nil, + }, + { + name: "Test with valid fileSource Flag and ASCAUpdateVersion flag set false ", + sourceFlag: "data/python-vul-file.py", + engineFlag: false, + ascaLocation: "C:/Users/test/Downloads/vorpal.exe", + want: nil, + wantErr: false, + }, + { + name: "Test with valid fileSource Flag and ASCAUpdateVersion flag set true ", + sourceFlag: "data/python-vul-file.py", + engineFlag: true, + ascaLocation: "C:/Users/test/Downloads/vorpal.exe", + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + ttt := tt + t.Run(ttt.name, func(t *testing.T) { + cmd := &cobra.Command{} + cmd.Flags().String(commonParams.SourcesFlag, ttt.sourceFlag, "") + cmd.Flags().Bool(commonParams.ASCALatestVersion, ttt.engineFlag, "") + cmd.Flags().String(commonParams.FormatFlag, printer.FormatJSON, "") + cmd.Flags().String(commonParams.ASCALocationFlag, ttt.ascaLocation, "") + runFunc := RunScanASCACommand(&mock.JWTMockWrapper{}) + err := runFunc(cmd, []string{}) + if (err != nil) != ttt.wantErr { + t.Errorf("RunScanASCACommand() error = %v, wantErr %v", err, ttt.wantErr) + return + } + if ttt.wantErr && err.Error() != ttt.wantErrMsg { + t.Errorf("RunScanASCACommand() error message = %v, wantErrMsg %v", err.Error(), ttt.wantErrMsg) + } + }) + } +} diff --git a/internal/commands/root.go b/internal/commands/root.go index fba9d3462..b0d8d8fde 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "io" "log" "os" @@ -15,6 +16,7 @@ import ( "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/wrappers/bitbucketserver" "github.com/checkmarx/ast-cli/internal/wrappers/configuration" + "github.com/checkmarx/ast-cli/internal/wrappers/utils" "github.com/pkg/errors" "github.com/checkmarx/ast-cli/internal/wrappers" @@ -106,6 +108,7 @@ func NewAstCLI( rootCmd.PersistentFlags().String(params.ConfigFilePathFlag, "", "Path to the configuration file") rootCmd.PersistentFlags().Bool(params.ApikeyOverrideFlag, false, "") + rootCmd.PersistentFlags().String(params.OptionalFlags, "", params.OptionalFlagUsage) _ = rootCmd.PersistentFlags().MarkHidden(params.ApikeyOverrideFlag) rootCmd.PersistentFlags().String(params.LogFileFlag, "", params.LogFileUsage) @@ -115,7 +118,11 @@ func NewAstCLI( // are passed to Cobra. rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { CheckPreferredCredentials(cmd) - err := customLogConfiguration(rootCmd) + err := extractOptionalFlags(cmd) + if err != nil { + return err + } + err = customLogConfiguration(rootCmd) if err != nil { return err } @@ -149,6 +156,8 @@ func NewAstCLI( _ = viper.BindPFlag(params.OriginKey, rootCmd.PersistentFlags().Lookup(params.OriginFlag)) _ = viper.BindPFlag(params.IgnoreProxyKey, rootCmd.PersistentFlags().Lookup(params.IgnoreProxyFlag)) _ = viper.BindPFlag(params.ConfigFilePathKey, rootCmd.PersistentFlags().Lookup(params.ConfigFilePathFlag)) + _ = viper.BindPFlag(params.OptionalFlagsKey, rootCmd.PersistentFlags().Lookup(params.OptionalFlags)) + // Key here is the actual flag since it doesn't use an environment variable _ = viper.BindPFlag(params.DebugFlag, rootCmd.PersistentFlags().Lookup(params.DebugFlag)) _ = viper.BindPFlag(params.InsecureFlag, rootCmd.PersistentFlags().Lookup(params.InsecureFlag)) @@ -427,3 +436,38 @@ func CheckPreferredCredentials(cmd *cobra.Command) { viper.Set(params.PreferredCredentialTypeKey, "") } } + +func extractOptionalFlags(cmd *cobra.Command) error { + if cmd.Flags().Changed(params.OptionalFlags) { + flagVal, err := cmd.Flags().GetString(params.OptionalFlags) + if err != nil { + return err + } + if strings.TrimSpace(flagVal) == "" { + return errors.Errorf("%s flag is provided but empty", params.OptionalFlags) + } + } + optionalFlags := strings.TrimSpace(viper.GetString(params.OptionalFlagsKey)) + if optionalFlags == "" { + return nil + } + pairs := strings.Split(optionalFlags, ";") + for _, pair := range pairs { + pair = strings.TrimSpace(pair) + if pair == "" { + continue + } + keyVal := strings.Split(pair, "=") + if len(keyVal) != params.KeyValuePairSize { + return errors.New("Invalid optional flags. Optional flags should be in a KEY1=VALUE1;KEY2=VALUE2 format") + } + if strings.TrimSpace(keyVal[1]) == "" { + return errors.New("Invalid optional flags. Value for key " + keyVal[0] + " is empty") + } + err := utils.SetOptionalParam(keyVal[0], keyVal[1]) + if err != nil { + return err + } + } + return nil +} diff --git a/internal/commands/root_test.go b/internal/commands/root_test.go index 149cc4ba8..b71efa74d 100644 --- a/internal/commands/root_test.go +++ b/internal/commands/root_test.go @@ -309,3 +309,10 @@ func TestSetLogOutputFromFlag_DirPath_Console_Success(t *testing.T) { err := setLogOutputFromFlag(params.LogFileConsoleFlag, tempDir) assert.NilError(t, err) } + +func TestOptionalFlag(t *testing.T) { + baseArgs := []string{"scan", "create", "--project-name", "MOCK", "-s", githubDummyRepo, "-b", "dummy_branch", "--optional-flags", "asca-location=/optional/path"} + cmd := createASTTestCommand() + err := executeTestCommand(cmd, baseArgs...) + assert.NilError(t, err) +} diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 85944edcf..fb3a7583b 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -482,6 +482,9 @@ func scanASCASubCommand(jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrap ) scanASCACmd.PersistentFlags().String(commonParams.IgnoredFilePathFlag, "", "Path to ignored secrets file") + scanASCACmd.PersistentFlags().String(commonParams.ASCALocationFlag, "", "Path to custom location where ASCA engine is installed") + _ = viper.BindPFlag(commonParams.ASCALocationKey, scanASCACmd.PersistentFlags().Lookup(commonParams.ASCALocationFlag)) + return scanASCACmd } diff --git a/internal/params/binds.go b/internal/params/binds.go index d65f595e7..e1fa34d03 100644 --- a/internal/params/binds.go +++ b/internal/params/binds.go @@ -87,4 +87,6 @@ var EnvVarsBinds = []struct { {CompleteMultiPartUploadPathKey, CompleteMultipartUploadPathEnv, "api/uploads/complete-multipart-upload"}, {MultipartFileSizeKey, MultipartFileSizeEnv, "2"}, {DisableASCALatestVersionKey, DisableASCALatestVersionEnv, ""}, + {ASCALocationKey, ASCALocationEnv, ""}, + {OptionalFlagsKey, OptionalFlagsEnv, ""}, } diff --git a/internal/params/envs.go b/internal/params/envs.go index 614792cbf..041442d95 100644 --- a/internal/params/envs.go +++ b/internal/params/envs.go @@ -90,4 +90,6 @@ const ( CompleteMultipartUploadPathEnv = "CX_COMPLETE_MULTIPART_UPLOAD_PATH" MultipartFileSizeEnv = "MULTIPART_FILE_SIZE" DisableASCALatestVersionEnv = "DISABLE_ASCA_UPDATE" + ASCALocationEnv = "CX_ASCA_LOCATION" + OptionalFlagsEnv = "CX_OPTIONAL_FLAGS" ) diff --git a/internal/params/flags.go b/internal/params/flags.go index ae202fedf..a55e027b2 100644 --- a/internal/params/flags.go +++ b/internal/params/flags.go @@ -64,9 +64,11 @@ const ( FormatFlagUsageFormat = "Format for the output. One of %s" FilterFlag = "filter" ASCALatestVersion = "asca-latest-version" + ASCALocationFlag = "asca-location" BaseURIFlag = "base-uri" ProxyFlag = "proxy" ProxyFlagUsage = "Proxy server to send communication through" + OptionalFlagUsage = "Flag for providing command specific flag from IDE or CI/CD plugins." IgnoreProxyFlag = "ignore-proxy" IgnoreProxyFlagUsage = "Ignore proxy configuration" ProxyTypeFlag = "proxy-auth-type" @@ -77,6 +79,7 @@ const ( KerberosProxySPNFlag = "proxy-kerberos-spn" KerberosKrb5ConfFlag = "proxy-kerberos-krb5-conf" KerberosCcacheFlag = "proxy-kerberos-ccache" + OptionalFlags = "optional-flags" SastFastScanFlag = "sast-fast-scan" SastLightQueriesFlag = "sast-light-queries" BranchPrimaryFlag = "branch-primary" diff --git a/internal/params/keys.go b/internal/params/keys.go index 09aeea2c8..8685ba217 100644 --- a/internal/params/keys.go +++ b/internal/params/keys.go @@ -89,4 +89,6 @@ var ( CompleteMultiPartUploadPathKey = strings.ToLower(CompleteMultipartUploadPathEnv) MultipartFileSizeKey = strings.ToLower(MultipartFileSizeEnv) DisableASCALatestVersionKey = strings.ToLower(DisableASCALatestVersionEnv) + ASCALocationKey = strings.ToLower(ASCALocationEnv) + OptionalFlagsKey = strings.ToLower(OptionalFlagsEnv) ) diff --git a/internal/services/asca.go b/internal/services/asca.go index 5a0af82de..9f051acb0 100644 --- a/internal/services/asca.go +++ b/internal/services/asca.go @@ -19,6 +19,7 @@ import ( "github.com/checkmarx/ast-cli/internal/wrappers/configuration" "github.com/checkmarx/ast-cli/internal/wrappers/grpcs" getport "github.com/jsumners/go-getport" + "github.com/pkg/errors" "github.com/spf13/viper" ) @@ -32,6 +33,7 @@ type AscaScanParams struct { ASCAUpdateVersion bool IsDefaultAgent bool IgnoredFilePath string + VorpalLocation string } type AscaWrappersParam struct { @@ -39,22 +41,53 @@ type AscaWrappersParam struct { ASCAWrapper grpcs.AscaWrapper } -func CreateASCAScanRequest(ascaParams AscaScanParams, wrapperParams AscaWrappersParam) (*grpcs.ScanResult, error) { - err := manageASCAInstallation(ascaParams, wrapperParams) +func validateVorpalDirExist(dirPath string) error { + info, err := os.Stat(dirPath) if err != nil { - return nil, err + if os.IsNotExist(err) { + return errors.Errorf("%s path does not exist", dirPath) + } + if errors.Is(err, os.ErrPermission) { + return errors.Errorf("permission denied while accessing path %s", dirPath) + } + return errors.Errorf("cannot access path %s: %v", dirPath, err) + } + if !info.IsDir() { + return errors.Errorf("provided path is not a directory %s", dirPath) } + return nil +} +func ValidateCustomASCAInstallation(vorpalLocation string) error { + if err := validateVorpalDirExist(vorpalLocation); err != nil { + return errors.Wrap(err, "Failed to validate ASCA custom location") + } + ASCAInstalled, _ := osinstaller.FileExists(filepath.Join(vorpalLocation, ascaconfig.Params.ExecutableFile)) + if !ASCAInstalled { + return errors.Errorf("No ASCA executable found in provided location: %s", vorpalLocation) + } + logger.PrintIfVerbose("Using custom ASCA engine installed at: " + vorpalLocation) + return nil +} + +func CreateASCAScanRequest(ascaParams AscaScanParams, wrapperParams AscaWrappersParam) (*grpcs.ScanResult, error) { + var err error + if ascaParams.VorpalLocation == "" { + err = manageASCAInstallation(ascaParams, wrapperParams) + if err != nil { + return nil, err + } + } else if err := ValidateCustomASCAInstallation(ascaParams.VorpalLocation); err != nil { + return nil, err + } err = ensureASCAServiceRunning(wrapperParams, ascaParams) if err != nil { return nil, err } - emptyResults := validateFilePath(ascaParams.FilePath) if emptyResults != nil { return emptyResults, nil } - ignoredResults := validateIgnoredFilePath(ascaParams.IgnoredFilePath) if ignoredResults != nil { return ignoredResults, nil @@ -222,7 +255,7 @@ func ensureASCAServiceRunning(wrappersParam AscaWrappersParam, ascaParams AscaSc if err != nil { return err } - if err := RunASCAEngine(wrappersParam.ASCAWrapper.GetPort()); err != nil { + if err := RunASCAEngine(wrappersParam.ASCAWrapper.GetPort(), ascaParams.VorpalLocation); err != nil { return err } @@ -249,7 +282,7 @@ func readSourceCode(filePath string) (string, error) { return string(data), nil } -func RunASCAEngine(port int) error { +func RunASCAEngine(port int, vorpalLocation string) error { dialTimeout := 5 * time.Second args := []string{ "-listen", @@ -257,8 +290,13 @@ func RunASCAEngine(port int) error { } logger.PrintIfVerbose(fmt.Sprintf("Running ASCA engine with args: %v \n", args)) + var cmd *exec.Cmd - cmd := exec.Command(ascaconfig.Params.ExecutableFilePath(), args...) + if vorpalLocation != "" { + cmd = exec.Command(filepath.Join(vorpalLocation, ascaconfig.Params.ExecutableFile), args...) + } else { + cmd = exec.Command(ascaconfig.Params.ExecutableFilePath(), args...) + } osinstaller.ConfigureIndependentProcess(cmd) @@ -266,7 +304,6 @@ func RunASCAEngine(port int) error { if err != nil { return err } - ready := waitForServer(fmt.Sprintf("localhost:%d", port), dialTimeout) if !ready { return fmt.Errorf("server did not become ready in time") diff --git a/internal/services/asca_test.go b/internal/services/asca_test.go index 9e6b805c8..295c5f22d 100644 --- a/internal/services/asca_test.go +++ b/internal/services/asca_test.go @@ -2,8 +2,12 @@ package services import ( "fmt" + + "os" + "path/filepath" "testing" + "github.com/checkmarx/ast-cli/internal/commands/asca/ascaconfig" errorconstants "github.com/checkmarx/ast-cli/internal/constants/errors" "github.com/checkmarx/ast-cli/internal/params" "github.com/checkmarx/ast-cli/internal/wrappers" @@ -45,6 +49,7 @@ func TestCreateASCAScanRequest_DefaultAgent_Success(t *testing.T) { FilePath: "data/python-vul-file.py", ASCAUpdateVersion: false, IsDefaultAgent: true, + VorpalLocation: "", } wrapperParams := AscaWrappersParam{ JwtWrapper: &mock.JWTMockWrapper{}, @@ -233,3 +238,60 @@ func TestCreateASCAScanRequest_WithSingleIgnoredFinding_FiltersResult(t *testing ) } } + +func TestCreateASCAScanRequest_InvalidCustomVorpalLocation(t *testing.T) { + ascaParams := AscaScanParams{ + FilePath: "valid/path", + VorpalLocation: "definitely/invalid/path", + } + wrapperParams := AscaWrappersParam{} + result, err := CreateASCAScanRequest(ascaParams, wrapperParams) + if err == nil { + t.Fatalf("Expected error for invalid vorpalLocation") + } + if result != nil { + t.Fatalf("Expected nil result when validation fails") + } + assert.NotNil(t, err) +} + +func TestCreateASCAScanRequest_ValidCustomVorpalLocation_NoVorpalExe_Installed_Failed(t *testing.T) { + tempDir := t.TempDir() + ascaParams := AscaScanParams{ + FilePath: "valid/path", + VorpalLocation: tempDir, + } + wrapperParams := AscaWrappersParam{} + result, err := CreateASCAScanRequest(ascaParams, wrapperParams) + assert.NotNil(t, err) + + _ = result +} + +func TestCreateASCAScanRequest_ValidCustomVorpalLocation_VorPal_exe_Success(t *testing.T) { + tempDir := t.TempDir() + + executableName := ascaconfig.Params.ExecutableFile + executablePath := filepath.Join(tempDir, executableName) + err := os.WriteFile(executablePath, []byte("dummy"), 0755) + if err != nil { + t.Fatalf("Failed to create dummy executable: %v", err) + } + ASCAParams := AscaScanParams{ + FilePath: "data/python-vul-file.py", + ASCAUpdateVersion: false, + IsDefaultAgent: true, + IgnoredFilePath: "data/ignoredAsca.json", + VorpalLocation: tempDir, + } + wrapperParams := AscaWrappersParam{ + JwtWrapper: &mock.JWTMockWrapper{}, + ASCAWrapper: mock.NewASCAMockWrapper(1234), + } + result, err := CreateASCAScanRequest(ASCAParams, wrapperParams) + + if err != nil { + t.Fatalf("Expected no error, got: %v", err) + } + _ = result +} diff --git a/internal/wrappers/utils/utils.go b/internal/wrappers/utils/utils.go index 89b6933d2..793d9ef96 100644 --- a/internal/wrappers/utils/utils.go +++ b/internal/wrappers/utils/utils.go @@ -1,11 +1,24 @@ package utils import ( + "errors" "net/url" "path" "strings" + "sync" + + "github.com/checkmarx/ast-cli/internal/logger" +) + +var ( + mutex sync.RWMutex + optionalParams = make(map[string]string) ) +var allowedOptionalKeys = map[string]bool{ + "asca-location": true, +} + // CleanURL returns a cleaned url removing double slashes func CleanURL(uri string) (string, error) { parsedURL, err := url.Parse(uri) @@ -31,3 +44,34 @@ func LimitSlice[T any](slice []T, limit int) []T { } return slice[:limit] } + +func SetOptionalParam(key, value string) error { + logger.PrintfIfVerbose("Setting optional parameter: %s", key) + mutex.Lock() + defer mutex.Unlock() + value = strings.TrimSpace(value) + key = strings.TrimSpace(key) + if _, ok := allowedOptionalKeys[key]; ok { + optionalParams[key] = value + } else { + return errors.New("Invalid optional flags parameter key: " + key) + } + return nil +} + +func hasOptionalParam(key string) bool { + mutex.RLock() + defer mutex.RUnlock() + _, ok := optionalParams[key] + return ok +} + +func GetOptionalParam(key string) string { + mutex.RLock() + defer mutex.RUnlock() + trimmedKey := strings.TrimSpace(key) + if hasOptionalParam(trimmedKey) { + return optionalParams[trimmedKey] + } + return "" +} diff --git a/internal/wrappers/utils/utils_test.go b/internal/wrappers/utils/utils_test.go index b9845cb3f..286f41c65 100644 --- a/internal/wrappers/utils/utils_test.go +++ b/internal/wrappers/utils/utils_test.go @@ -2,7 +2,14 @@ package utils import ( "log" + "sync" "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + ascaLocationKey = "asca-location" ) func TestCleanURL_CleansCorrectly(t *testing.T) { @@ -160,3 +167,89 @@ func equal(a, b []int) bool { } return true } + +func clearOptionalParams() { + mutex.Lock() + optionalParams = make(map[string]string) + mutex.Unlock() +} + +func TestSetAndGetAllowedKey(t *testing.T) { + clearOptionalParams() + key := ascaLocationKey + value := "location-1" + + err := SetOptionalParam(key, value) + assert.Nil(t, err) + + if !hasOptionalParam(key) { + t.Fatalf("expected hasOptionalParam(%q) to be true", key) + } + got := GetOptionalParam(key) + if got != value { + t.Fatalf("expected GetOptionalParam(%q) == %q, got %q", key, value, got) + } +} + +func TestSetNotAllowedKeyDoesNotSet(t *testing.T) { + clearOptionalParams() + + key := "not-allowed-key" + value := "value" + + err := SetOptionalParam(key, value) + assert.NotNil(t, err) + + if hasOptionalParam(key) { + t.Fatalf("expected hasOptionalParam(%q) to be false for disallowed key", key) + } + + got := GetOptionalParam(key) + if got != "" { + t.Fatalf("expected GetOptionalParam(%q) == empty, got %q", key, got) + } +} + +func TestSetWithTrimmedKeyBehavior(t *testing.T) { + clearOptionalParams() + + originalKey := " asca-location " + trimmedKey := ascaLocationKey + value := "trimmed-value" + + err := SetOptionalParam(originalKey, value) + assert.Nil(t, err) + + if got := GetOptionalParam(originalKey); got != value { + t.Fatalf("expected GetOptionalParam(%q) == %q, got %q", originalKey, value, got) + } + + if got := GetOptionalParam(trimmedKey); got != value { + t.Fatalf("expected GetOptionalParam(%q) == %q, got %q", originalKey, value, got) + } +} + +func TestConcurrentSetOptionalParam(t *testing.T) { + clearOptionalParams() + var wg sync.WaitGroup + + // spawn several goroutines setting allowed and disallowed keys + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + err := SetOptionalParam(ascaLocationKey, "v") + assert.Nil(t, err) + err = SetOptionalParam("not-allowed", "x") + assert.NotNil(t, err) + }() + } + wg.Wait() + + if !hasOptionalParam(ascaLocationKey) { + t.Fatalf("expected hasOptionalParam(%q) to be true after concurrent sets", "asca-location") + } + if GetOptionalParam("asca-location") != "v" { + t.Fatalf("expected GetOptionalParam(%q) == %q", ascaLocationKey, "v") + } +} diff --git a/test/integration/asca-engine_test.go b/test/integration/asca-engine_test.go index 43a8948ff..a7caeb203 100644 --- a/test/integration/asca-engine_test.go +++ b/test/integration/asca-engine_test.go @@ -3,10 +3,16 @@ package integration import ( + "archive/tar" + "compress/gzip" "encoding/json" "fmt" + "io" + "net/http" "os" + "path/filepath" "testing" + "time" "github.com/checkmarx/ast-cli/internal/commands/asca/ascaconfig" commonParams "github.com/checkmarx/ast-cli/internal/params" @@ -222,3 +228,113 @@ func TestExecuteASCAScan_EngineNotRunningWithLicense_Success(t *testing.T) { err, _ := executeCommand(t, args...) assert.NilError(t, err, "User has license, should not fail") } + +func TestExecuteASCAScan_Asca_location_Flag_Success(t *testing.T) { + configuration.LoadConfiguration() + ASCAWrapper := grpcs.NewASCAGrpcWrapper(viper.GetInt(commonParams.ASCAPortKey)) + _ = ASCAWrapper.ShutDown() + _ = os.RemoveAll(ascaconfig.Params.WorkingDir()) + tempDir := t.TempDir() + + resp, err := http.Get(ascaconfig.Params.DownloadURL) + asserts.Nil(t, err) + defer resp.Body.Close() + + asserts.Equal(t, http.StatusOK, resp.StatusCode) + + zipPath := filepath.Join(tempDir, ascaconfig.Params.FileName) + zipBytes, err := io.ReadAll(resp.Body) + asserts.Nil(t, err) + asserts.NotZero(t, len(zipBytes)) + err = os.WriteFile(zipPath, zipBytes, 0644) + asserts.Nil(t, err) + file, err := os.Open(zipPath) + asserts.Nil(t, err) + defer file.Close() + + gzReader, err := gzip.NewReader(file) + asserts.Nil(t, err) + defer gzReader.Close() + + tarReader := tar.NewReader(gzReader) + + var extractedExePath string + + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + asserts.Nil(t, err) + + if header.Typeflag == tar.TypeReg && + filepath.Base(header.Name) == ascaconfig.Params.ExecutableFile { + + extractedExePath = filepath.Join(tempDir, filepath.Base(header.Name)) + + outFile, err := os.Create(extractedExePath) + asserts.Nil(t, err) + + _, err = io.Copy(outFile, tarReader) + asserts.Nil(t, err) + + outFile.Close() + } + } + asserts.NotEmpty(t, extractedExePath, "Executable not found inside zip") + // Ensure executable permissions + err = os.Chmod(extractedExePath, 0755) + asserts.Nil(t, err) + + args := []string{ + "scan", "asca", + flag(commonParams.SourcesFlag), "data/python-vul-file.py", + flag(commonParams.DebugFlag), + flag(commonParams.AgentFlag), "JetBrains", + flag(commonParams.ASCALocationFlag), tempDir, + } + + err, _ = executeCommand(t, args...) + assert.NilError(t, err, "should not fail") + ASCAWrapper = grpcs.NewASCAGrpcWrapper(viper.GetInt(commonParams.ASCAPortKey)) + _ = ASCAWrapper.ShutDown() + + time.Sleep(500 * time.Millisecond) +} + +func TestExecuteASCAScan_Asca_location_Flag_ThrowError_No_Executable(t *testing.T) { + configuration.LoadConfiguration() + ASCAWrapper := grpcs.NewASCAGrpcWrapper(viper.GetInt(commonParams.ASCAPortKey)) + _ = ASCAWrapper.ShutDown() + _ = os.RemoveAll(ascaconfig.Params.WorkingDir()) + + tempDir := t.TempDir() + args := []string{ + "scan", "asca", + flag(commonParams.SourcesFlag), "data/python-vul-file.py", + flag(commonParams.DebugFlag), + flag(commonParams.AgentFlag), "JetBrains", + flag(commonParams.ASCALocationFlag), tempDir, + } + + err, _ := executeCommand(t, args...) + asserts.NotNil(t, err, " Expected error due to missing executable in custom location") + asserts.ErrorContains(t, err, "No ASCA executable found in provided location") +} + +func TestExecuteASCAScan_Asca_location_Flag_ThrowError_InvalidPath(t *testing.T) { + configuration.LoadConfiguration() + ASCAWrapper := grpcs.NewASCAGrpcWrapper(viper.GetInt(commonParams.ASCAPortKey)) + _ = ASCAWrapper.ShutDown() + _ = os.RemoveAll(ascaconfig.Params.WorkingDir()) + + args := []string{ + "scan", "asca", + flag(commonParams.SourcesFlag), "data/python-vul-file.py", + flag(commonParams.DebugFlag), + flag(commonParams.AgentFlag), "JetBrains", + flag(commonParams.ASCALocationFlag), "/definitely/invalid/path", + } + err, _ := executeCommand(t, args...) + asserts.ErrorContains(t, err, "Failed to validate ASCA custom location") +}