diff --git a/go.sum b/go.sum index b79ac990e..a29f97259 100644 --- a/go.sum +++ b/go.sum @@ -107,7 +107,6 @@ github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -118,7 +117,6 @@ github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1 github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= @@ -126,7 +124,6 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= @@ -141,7 +138,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -270,7 +266,6 @@ github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= @@ -282,7 +277,6 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -359,7 +353,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= @@ -462,9 +455,7 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -526,7 +517,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-getter v1.5.1 h1:lM9sM02nvEApQGFgkXxWbhfqtyN+AyhQmi+MaMdBDOI= github.com/hashicorp/go-getter v1.5.1/go.mod h1:a7z7NPPfNQpJWcn4rSWFtdrSldqLdLPEF3d8nFMsSLM= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -639,15 +629,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= @@ -938,7 +925,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -1040,7 +1026,6 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1426,7 +1411,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1444,7 +1428,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= @@ -1476,7 +1459,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3 h1:qTakTkI6ni6LFD5sBwwsdSO+AQqbSIxOauHTTQKZ/7o= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= diff --git a/pkg/cli/color-console_windows.go b/pkg/cli/color-console_windows.go index fd2b15898..68973d6ec 100644 --- a/pkg/cli/color-console_windows.go +++ b/pkg/cli/color-console_windows.go @@ -1,3 +1,5 @@ +// +build windows + /* Copyright (C) 2020 Accurics, Inc. @@ -14,8 +16,6 @@ limitations under the License. */ -// +build windows - package cli import ( diff --git a/pkg/cli/register.go b/pkg/cli/register.go index 07736862c..8eb088d5c 100644 --- a/pkg/cli/register.go +++ b/pkg/cli/register.go @@ -25,8 +25,11 @@ import ( "github.com/accurics/terrascan/pkg/config" "github.com/accurics/terrascan/pkg/logging" "github.com/spf13/cobra" + "go.uber.org/zap" ) +const configEnvvarName = "TERRASCAN_CONFIG" + // RegisterCommand Registers a new command under the base command func RegisterCommand(baseCommand *cobra.Command, command *cobra.Command) { baseCommand.AddCommand(command) @@ -43,8 +46,24 @@ func Execute() { cobra.OnInitialize(func() { // Set up the logger logging.Init(LogType, LogLevel) + + var configfile string + if len(ConfigFile) > 0 { + configfile = ConfigFile + } + + if len(configfile) == 0 { + configfile = os.Getenv(configEnvvarName) + } + + zap.S().Debugf("%s=%s", configEnvvarName, os.Getenv(configEnvvarName)) + // Make sure we load the global config from the specified config file - config.LoadGlobalConfig(ConfigFile) + if err := config.LoadGlobalConfig(configfile); err != nil { + zap.S().Error("error while loading global config", zap.Error(err)) + os.Exit(1) + } + }) // parse the flags but hack around to avoid exiting with error code 2 on help diff --git a/pkg/cli/run_test.go b/pkg/cli/run_test.go index 3c6792533..c67b6bb43 100644 --- a/pkg/cli/run_test.go +++ b/pkg/cli/run_test.go @@ -23,6 +23,7 @@ import ( "path/filepath" "testing" + "github.com/accurics/terrascan/pkg/config" "github.com/accurics/terrascan/pkg/iac-providers/output" "github.com/accurics/terrascan/pkg/policy" "github.com/accurics/terrascan/pkg/results" @@ -38,6 +39,9 @@ func TestMain(m *testing.M) { } func setup() { + // set default config values before policy download + config.LoadGlobalConfig("") + // to download the policies for Run test // downloads the policies at $HOME/.terrascan initial(nil, nil, false) @@ -45,7 +49,8 @@ func setup() { func shutdown() { // remove the downloaded policies - os.RemoveAll(filepath.Join(utils.GetHomeDir(), ".terrascan")) + os.RemoveAll(config.GetPolicyBasePath()) + // cleanup the loaded config values } func TestRun(t *testing.T) { @@ -222,6 +227,7 @@ func TestRun(t *testing.T) { for _, tt := range table { t.Run(tt.name, func(t *testing.T) { + config.LoadGlobalConfig(tt.scanOptions.configFile) err := tt.scanOptions.Run() if (err != nil) != tt.wantErr { t.Errorf("ScanOptions.Run() error = %v, wantErr %v", err, tt.wantErr) diff --git a/pkg/config/config-reader.go b/pkg/config/config-reader.go index 095a947ee..dae0a2f23 100644 --- a/pkg/config/config-reader.go +++ b/pkg/config/config-reader.go @@ -27,7 +27,7 @@ import ( var ( // ErrTomlLoadConfig indicates error: Failed to load toml config - errTomlLoadConfig = fmt.Errorf("failed to load toml config") + ErrTomlLoadConfig = fmt.Errorf("failed to load toml config") // ErrNotPresent indicates error: Config file not present ErrNotPresent = fmt.Errorf("config file not present") ) @@ -59,7 +59,7 @@ func NewTerrascanConfigReader(fileName string) (*TerrascanConfigReader, error) { data, err := ioutil.ReadFile(fileName) if err != nil { zap.S().Error("error loading config file", zap.Error(err)) - return configReader, errTomlLoadConfig + return configReader, ErrTomlLoadConfig } if err = toml.Unmarshal(data, &configReader.config); err != nil { @@ -69,26 +69,26 @@ func NewTerrascanConfigReader(fileName string) (*TerrascanConfigReader, error) { } // GetPolicyConfig will return the policy config from the terrascan config file -func (r TerrascanConfigReader) GetPolicyConfig() Policy { +func (r TerrascanConfigReader) getPolicyConfig() Policy { return r.config.Policy } // GetNotifications will return the notifiers specified in the terrascan config file -func (r TerrascanConfigReader) GetNotifications() map[string]Notifier { +func (r TerrascanConfigReader) getNotifications() map[string]Notifier { return r.config.Notifications } // GetRules will return the rules specified in the terrascan config file -func (r TerrascanConfigReader) GetRules() Rules { +func (r TerrascanConfigReader) getRules() Rules { return r.config.Rules } // GetCategory will return the category specified in the terrascan config file -func (r TerrascanConfigReader) GetCategory() Category { +func (r TerrascanConfigReader) getCategory() Category { return r.config.Category } // GetSeverity will return the level of severity specified in the terrascan config file -func (r TerrascanConfigReader) GetSeverity() Severity { +func (r TerrascanConfigReader) getSeverity() Severity { return r.config.Severity } diff --git a/pkg/config/config-reader_test.go b/pkg/config/config-reader_test.go index 51123acf8..931c83366 100644 --- a/pkg/config/config-reader_test.go +++ b/pkg/config/config-reader_test.go @@ -29,8 +29,8 @@ func TestNewTerrascanConfigReader(t *testing.T) { }, } testPolicy := Policy{ - BasePath: "custom-path", RepoPath: "rego-subdir", + BasePath: "custom-path", RepoURL: "https://repository/url", Branch: "branch-name", } @@ -167,8 +167,8 @@ func TestNewTerrascanConfigReader(t *testing.T) { t.Errorf("NewTerrascanConfigReader() = got %v, want %v", got, tt.want) } if tt.assertGetters { - if !reflect.DeepEqual(got.GetPolicyConfig(), tt.Policy) || !reflect.DeepEqual(got.GetNotifications(), tt.notifications) || !reflect.DeepEqual(got.GetRules(), tt.Rules) { - t.Errorf("NewTerrascanConfigReader() = got config: %v, notifications: %v, rules: %v want config: %v, notifications: %v, rules: %v", got.GetPolicyConfig(), got.GetNotifications(), got.GetRules(), tt.Policy, tt.notifications, tt.Rules) + if !reflect.DeepEqual(got.getPolicyConfig(), tt.Policy) || !reflect.DeepEqual(got.getNotifications(), tt.notifications) || !reflect.DeepEqual(got.getRules(), tt.Rules) { + t.Errorf("NewTerrascanConfigReader() = got config: %v, notifications: %v, rules: %v want config: %v, notifications: %v, rules: %v", got.getPolicyConfig(), got.getNotifications(), got.getRules(), tt.Policy, tt.notifications, tt.Rules) } } }) diff --git a/pkg/config/global.go b/pkg/config/global.go index 20db033b8..5a0a117f2 100644 --- a/pkg/config/global.go +++ b/pkg/config/global.go @@ -17,7 +17,6 @@ package config import ( - "os" "path/filepath" "github.com/accurics/terrascan/pkg/utils" @@ -25,79 +24,136 @@ import ( ) const ( - policyRepoURL = "https://github.com/accurics/terrascan.git" - policyBranch = "master" - configEnvvarName = "TERRASCAN_CONFIG" - policyConfigKey = "policy" + defaultPolicyRepoURL = "https://github.com/accurics/terrascan.git" + defaultPolicyBranch = "master" ) var ( - policyBasePath = filepath.Join(utils.GetHomeDir(), ".terrascan") - policyRepoPath = filepath.Join(policyBasePath, "pkg", "policies", "opa", "rego") + defaultPolicyRepoPath = filepath.Join("pkg", "policies", "opa", "rego") + defaultBasePolicyPath = filepath.Join(utils.GetHomeDir(), ".terrascan") ) -func init() { - // If the user specifies a config file in TERRASCAN_CONFIG, - // overwrite the defaults with the values from that file. - // Retain the defaults for members not specified in the file. - if err := LoadGlobalConfig(os.Getenv(configEnvvarName)); err != nil { - zap.S().Error("error while loading global config", zap.Error(err)) - } -} - // LoadGlobalConfig loads policy configuration from specified configFile // into var Global.Policy. Members of Global.Policy that are not specified // in configFile will get default values func LoadGlobalConfig(configFile string) error { // Start with the defaults - Global.Policy = Policy{ - BasePath: policyBasePath, - RepoPath: policyRepoPath, - RepoURL: policyRepoURL, - Branch: policyBranch, + global.Policy = Policy{ + BasePath: defaultBasePolicyPath, + RepoPath: defaultPolicyRepoPath, + RepoURL: defaultPolicyRepoURL, + Branch: defaultPolicyBranch, + } + + var configReader *TerrascanConfigReader + var err error + + if configReader, err = NewTerrascanConfigReader(configFile); err != nil { + return err + } + + if configFile != "" { + zap.S().Debugf("loading global config from: %s", configFile) } - if configFile == "" { - zap.S().Debug("global config env variable is not specified") - return nil + if len(configReader.getPolicyConfig().BasePath) > 0 && len(configReader.getPolicyConfig().RepoPath) == 0 { + zap.S().Warnf("policy base path specified in configfile %s, but rego_subdir path not specified.", configFile) } - configReader, err := NewTerrascanConfigReader(configFile) + if len(configReader.getPolicyConfig().RepoPath) > 0 && len(configReader.getPolicyConfig().BasePath) == 0 { + zap.S().Warnf("policy rego_subdir specified in configfile %s, but base path not specified.", configFile) + } + + if len(configReader.getPolicyConfig().BasePath) > 0 { + global.BasePath = configReader.getPolicyConfig().BasePath + } + + if len(configReader.getPolicyConfig().RepoPath) > 0 { + global.RepoPath = configReader.getPolicyConfig().RepoPath + } + + absolutePolicyBasePath, absolutePolicyRepoPath, err := utils.GetAbsPolicyConfigPaths(GetPolicyBasePath(), GetPolicyRepoPath()) if err != nil { + zap.S().Error("error processing provided policy paths", zap.Error(err)) return err } - if len(configReader.GetPolicyConfig().BasePath) > 0 { - Global.Policy.BasePath = configReader.GetPolicyConfig().BasePath + global.Policy.BasePath = absolutePolicyBasePath + global.Policy.RepoPath = absolutePolicyRepoPath + + if len(configReader.getPolicyConfig().RepoURL) > 0 { + global.Policy.RepoURL = configReader.getPolicyConfig().RepoURL + } + if len(configReader.getPolicyConfig().Branch) > 0 { + global.Policy.Branch = configReader.getPolicyConfig().Branch + } + + if len(configReader.getRules().ScanRules) > 0 { + global.Rules.ScanRules = configReader.getRules().ScanRules } - if len(configReader.GetPolicyConfig().RepoPath) > 0 { - Global.Policy.RepoPath = configReader.GetPolicyConfig().RepoPath + + if len(configReader.getRules().SkipRules) > 0 { + global.Rules.SkipRules = configReader.getRules().SkipRules } - if len(configReader.GetPolicyConfig().RepoURL) > 0 { - Global.Policy.RepoURL = configReader.GetPolicyConfig().RepoURL + + if len(configReader.getSeverity().Level) > 0 { + global.Severity.Level = configReader.getSeverity().Level } - if len(configReader.GetPolicyConfig().Branch) > 0 { - Global.Policy.Branch = configReader.GetPolicyConfig().Branch + + if len(configReader.getNotifications()) > 0 { + global.Notifications = configReader.getNotifications() } + + if len(configReader.getCategory().List) > 0 { + global.Category.List = configReader.getCategory().List + } + + zap.S().Debugf("global config loaded") + return nil } -// GetPolicyBasePath returns policy base path as set in global config +// GetPolicyBasePath returns the configured policy base path func GetPolicyBasePath() string { - return Global.Policy.BasePath + return global.Policy.BasePath } -// GetPolicyRepoPath return path to the policies repo locally downloaded +// GetPolicyRepoPath return the configured path to the policies repo locally downloaded func GetPolicyRepoPath() string { - return Global.Policy.RepoPath + return global.Policy.RepoPath } -// GetPolicyRepoURL returns policy repo url +// GetPolicyRepoURL returns the configured policy repo url func GetPolicyRepoURL() string { - return Global.Policy.RepoURL + return global.Policy.RepoURL } -// GetPolicyBranch returns policy repo url +// GetPolicyBranch returns the configured policy repo url func GetPolicyBranch() string { - return Global.Policy.Branch + return global.Policy.Branch +} + +// GetScanRules returns the configured scan rules +func GetScanRules() []string { + return global.Rules.ScanRules +} + +// GetSkipRules returns the configured skips rules +func GetSkipRules() []string { + return global.Rules.SkipRules +} + +// GetSeverityLevel returns the configured severity level +func GetSeverityLevel() string { + return global.Severity.Level +} + +// GetCategoryList returns the configured list of category of violations +func GetCategoryList() []string { + return global.Category.List +} + +// GetNotifications returns the configured notifier map +func GetNotifications() map[string]Notifier { + return global.Notifications } diff --git a/pkg/config/global_test.go b/pkg/config/global_test.go index 23de3f711..011dde6c1 100644 --- a/pkg/config/global_test.go +++ b/pkg/config/global_test.go @@ -18,10 +18,14 @@ package config import ( "testing" + + "github.com/accurics/terrascan/pkg/utils" ) func TestLoadGlobalConfig(t *testing.T) { testConfigFile := "./testdata/terrascan-config.toml" + absDefaultBasePolicyPath, absDefaultPolicyRepoPath, _ := utils.GetAbsPolicyConfigPaths(defaultBasePolicyPath, defaultPolicyRepoPath) + absCustomPath, absRegoSubdirPath, _ := utils.GetAbsPolicyConfigPaths("custom-path", "rego-subdir") type args struct { configFile string @@ -41,10 +45,10 @@ func TestLoadGlobalConfig(t *testing.T) { args: args{ configFile: "", }, - policyBasePath: policyBasePath, - policyRepoPath: policyRepoPath, - repoURL: policyRepoURL, - branchName: policyBranch, + policyBasePath: absDefaultBasePolicyPath, + policyRepoPath: absDefaultPolicyRepoPath, + repoURL: defaultPolicyRepoURL, + branchName: defaultPolicyBranch, }, { name: "global config file specified but doesn't exist", @@ -52,18 +56,18 @@ func TestLoadGlobalConfig(t *testing.T) { configFile: "test.toml", }, wantErr: true, - policyBasePath: policyBasePath, - policyRepoPath: policyRepoPath, - repoURL: policyRepoURL, - branchName: policyBranch, + policyBasePath: defaultBasePolicyPath, + policyRepoPath: defaultPolicyRepoPath, + repoURL: defaultPolicyRepoURL, + branchName: defaultPolicyBranch, }, { name: "valid global config file specified", args: args{ configFile: testConfigFile, }, - policyBasePath: "custom-path", - policyRepoPath: "rego-subdir", + policyBasePath: absCustomPath, + policyRepoPath: absRegoSubdirPath, repoURL: "https://repository/url", branchName: "branch-name", }, diff --git a/pkg/config/types.go b/pkg/config/types.go index cad643672..8067c1949 100644 --- a/pkg/config/types.go +++ b/pkg/config/types.go @@ -17,7 +17,7 @@ package config // Global initalizes GlobalConfig struct -var Global *TerrascanConfig = &TerrascanConfig{} +var global *TerrascanConfig = &TerrascanConfig{} // TerrascanConfig struct defines global variables/configurations across terrascan type TerrascanConfig struct { @@ -40,8 +40,9 @@ type Severity struct { // Policy struct defines policy specific configurations type Policy struct { - // policy local path + // policy local path, inside RepoPath where policies are at BasePath string `toml:"path,omitempty"` + // local filepath where repository containing policies is cached at RepoPath string `toml:"rego_subdir,omitempty"` // policy git url and branch diff --git a/pkg/http-server/file-scan.go b/pkg/http-server/file-scan.go index bdf1ccaab..f4e3afeb9 100644 --- a/pkg/http-server/file-scan.go +++ b/pkg/http-server/file-scan.go @@ -154,7 +154,7 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { tempFile.Name(), "", "", []string{"./testdata/testpolicies"}, scanRules, skipRules, categories, severity) } else { executor, err = runtime.NewExecutor(iacType, iacVersion, cloudType, - tempFile.Name(), "", "", getPolicyPathFromEnv(), scanRules, skipRules, categories, severity) + tempFile.Name(), "", "", getPolicyPathFromConfig(), scanRules, skipRules, categories, severity) } if err != nil { zap.S().Error(err) @@ -194,19 +194,7 @@ func (g *APIHandler) scanFile(w http.ResponseWriter, r *http.Request) { apiResponse(w, string(j), http.StatusOK) } -// getPolicyPathFromEnv reads the TERRASCAN_CONFIG env variable (if present) and returns the policy path -func getPolicyPathFromEnv() []string { - policyPath := []string{} - - // read policy path from TERRASCAN_CONFIG env variable - terrascanConfigFile := os.Getenv("TERRASCAN_CONFIG") - if terrascanConfigFile != "" { - terrascanConfigReader, err := config.NewTerrascanConfigReader(terrascanConfigFile) - if err != nil { - zap.S().Errorf("error while reading config file, %s; err %v", terrascanConfigFile, err) - } else { - policyPath = append(policyPath, terrascanConfigReader.GetPolicyConfig().RepoPath) - } - } - return policyPath +// getPolicyPathFromConfig returns the policy path from config +func getPolicyPathFromConfig() []string { + return []string{config.GetPolicyRepoPath()} } diff --git a/pkg/http-server/remote-repo.go b/pkg/http-server/remote-repo.go index 276cd09a7..b5ab7ff69 100644 --- a/pkg/http-server/remote-repo.go +++ b/pkg/http-server/remote-repo.go @@ -73,7 +73,7 @@ func (g *APIHandler) scanRemoteRepo(w http.ResponseWriter, r *http.Request) { results, err = s.ScanRemoteRepo(iacType, iacVersion, cloudType, []string{"./testdata/testpolicies"}) } else { - results, err = s.ScanRemoteRepo(iacType, iacVersion, cloudType, getPolicyPathFromEnv()) + results, err = s.ScanRemoteRepo(iacType, iacVersion, cloudType, getPolicyPathFromConfig()) } if err != nil { apiErrorResponse(w, err.Error(), http.StatusBadRequest) diff --git a/pkg/initialize/run.go b/pkg/initialize/run.go index bcfdcbe3f..b60d25332 100644 --- a/pkg/initialize/run.go +++ b/pkg/initialize/run.go @@ -29,22 +29,23 @@ import ( ) var ( - policyRepoPath = config.GetPolicyRepoPath() - policyBasePath = config.GetPolicyBasePath() - repoURL = config.GetPolicyRepoURL() - branch = config.GetPolicyBranch() errNoConnection = fmt.Errorf("could not connect to github.com") ) const terrascanReadmeURL string = "https://raw.githubusercontent.com/accurics/terrascan/master/README.md" // Run initializes terrascan if not done already -func Run(isScanCmd bool) error { +func Run(isNonInitCmd bool) error { zap.S().Debug("initializing terrascan") + zap.S().Debugf("rego subdir path : %s", config.GetPolicyRepoPath()) // check if policy paths exist - if path, err := os.Stat(policyRepoPath); err == nil && path.IsDir() { - if isScanCmd { + if path, err := os.Stat(config.GetPolicyRepoPath()); err == nil && path.IsDir() { + + zap.S().Debug("EXISTS AND IS A DIR") + if isNonInitCmd { + zap.S().Debug("IS NON INIT") + return nil } } @@ -64,6 +65,12 @@ func Run(isScanCmd bool) error { // DownloadPolicies clones the policies to a local folder func DownloadPolicies() error { + + policyBasePath := config.GetPolicyBasePath() + policyRepoPath := config.GetPolicyRepoPath() + repoURL := config.GetPolicyRepoURL() + branch := config.GetPolicyBranch() + zap.S().Debug("downloading policies") zap.S().Debugf("base directory path : %s", policyBasePath) @@ -79,6 +86,7 @@ func DownloadPolicies() error { r, err := git.PlainClone(policyBasePath, false, &git.CloneOptions{ URL: repoURL, }) + if err != nil { return fmt.Errorf("failed to download policies. error: '%v'", err) } diff --git a/pkg/notifications/notifiers.go b/pkg/notifications/notifiers.go index 0e6cefcb5..d25938e52 100644 --- a/pkg/notifications/notifiers.go +++ b/pkg/notifications/notifiers.go @@ -25,15 +25,11 @@ import ( "go.uber.org/zap" ) -const ( - notificationsConfigKey = "notifications" -) - var ( errNotifierNotSupported = fmt.Errorf("notifier not supported") errNotifierTypeNotPresent = fmt.Errorf("notifier type not present in toml config") - // ErrTomlKeyNotPresent will be returned when config file does not have notificationsConfigKey - ErrTomlKeyNotPresent = fmt.Errorf("key not present in toml config") + // ErrNotificationNotPresent error is caused when there isn't any notification present in the config + ErrNotificationNotPresent = fmt.Errorf("no notification present") ) // NewNotifier returns a new notifier @@ -51,25 +47,15 @@ func NewNotifier(notifierType string) (notifier Notifier, err error) { } // NewNotifiers returns a list of notifiers configured in the config file -func NewNotifiers(configFile string) ([]Notifier, error) { +func NewNotifiers() ([]Notifier, error) { var notifiers []Notifier - if configFile == "" { - zap.S().Debug("no config file specified") - return notifiers, nil - } - - configReader, err := config.NewTerrascanConfigReader(configFile) - if err != nil || configReader == nil { - return notifiers, err - } - // get config for 'notifications' - notifications := configReader.GetNotifications() - if notifications == nil { - zap.S().Debug("key '%s' not present in toml config", notificationsConfigKey) - return notifiers, ErrTomlKeyNotPresent + notifications := config.GetNotifications() + if len(notifications) == 0 { + zap.S().Debug("no notification detected from config") + return notifiers, ErrNotificationNotPresent } // create notifiers diff --git a/pkg/notifications/notifiers_test.go b/pkg/notifications/notifiers_test.go index b1084416d..66befcfbb 100644 --- a/pkg/notifications/notifiers_test.go +++ b/pkg/notifications/notifiers_test.go @@ -1,7 +1,6 @@ package notifications import ( - "fmt" "reflect" "testing" @@ -52,17 +51,17 @@ func TestNewNotifiers(t *testing.T) { { name: "config not present", configFile: "notthere", - wantErr: config.ErrNotPresent, + wantErr: ErrNotificationNotPresent, }, { name: "invalid toml", configFile: "testdata/invalid.toml", - wantErr: fmt.Errorf("(1, 3): was expecting token =, but got \"am\" instead"), + wantErr: ErrNotificationNotPresent, }, { name: "key not present", configFile: "testdata/nokey.toml", - wantErr: ErrTomlKeyNotPresent, + wantErr: ErrNotificationNotPresent, }, { name: "invalid notifier", @@ -92,7 +91,8 @@ func TestNewNotifiers(t *testing.T) { for _, tt := range table { t.Run(tt.name, func(t *testing.T) { - _, gotErr := NewNotifiers(tt.configFile) + config.LoadGlobalConfig(tt.configFile) + _, gotErr := NewNotifiers() if !reflect.DeepEqual(gotErr, tt.wantErr) { t.Errorf("incorrect error; got: '%v', want: '%v'", gotErr, tt.wantErr) } diff --git a/pkg/policy/all.go b/pkg/policy/all.go index eaf00a4d4..0616ef4d2 100644 --- a/pkg/policy/all.go +++ b/pkg/policy/all.go @@ -23,5 +23,7 @@ const ( func init() { // Register all as a cloud provider with terrascan - RegisterIndirectCloudProvider("all", defaultAllIacType, defaultAllIacVersion, func() []string { return SupportedPolicyTypes(false) }) + RegisterIndirectCloudProvider("all", defaultAllIacType, defaultAllIacVersion, func() []string { + return SupportedPolicyTypes(false) + }) } diff --git a/pkg/policy/cloud-providers.go b/pkg/policy/cloud-providers.go index 447fae88e..b9c0ad2a0 100644 --- a/pkg/policy/cloud-providers.go +++ b/pkg/policy/cloud-providers.go @@ -17,6 +17,7 @@ package policy import ( + "path/filepath" "sort" "github.com/accurics/terrascan/pkg/config" @@ -49,10 +50,6 @@ var defaultIacType = make(map[supportedCloudType]supportedIacType) // defaultIacVersion map of default IaC version for a given policy/cloud provider var defaultIacVersion = make(map[supportedCloudType]supportedIacVersion) -var ( - basePolicyPath = config.GetPolicyRepoPath() -) - func registerActualCloudProvider(cloudType supportedCloudType, iacTypeDefault supportedIacType, iacVersionDefault supportedIacVersion, isIndirect bool, getPolicyPaths func() []string) { if isIndirect { supportedCloudProvider[cloudType] = cloudProviderType{ @@ -77,7 +74,9 @@ func RegisterIndirectCloudProvider(cloudType supportedCloudType, iacTypeDefault // RegisterCloudProvider registers a cloud provider with terrascan func RegisterCloudProvider(cloudType supportedCloudType, iacTypeDefault supportedIacType, iacVersionDefault supportedIacVersion) { - registerActualCloudProvider(cloudType, iacTypeDefault, iacVersionDefault, false, func() []string { return []string{basePolicyPath + "/" + string(cloudType)} }) + registerActualCloudProvider(cloudType, iacTypeDefault, iacVersionDefault, false, func() []string { + return []string{filepath.Join(config.GetPolicyRepoPath(), string(cloudType))} + }) } // IsCloudProviderSupported returns whether a cloud provider is supported in terrascan @@ -102,9 +101,11 @@ func GetDefaultPolicyPaths(cloudTypes []string) []string { } for _, x := range names { - paths := (supportedCloudProvider[supportedCloudType(x)]).policyPaths() + def := supportedCloudProvider[supportedCloudType(x)] + paths := def.policyPaths() providers = append(providers, paths...) } + return providers } diff --git a/pkg/policy/opa/engine.go b/pkg/policy/opa/engine.go index 7f7d9eadd..0e03047df 100644 --- a/pkg/policy/opa/engine.go +++ b/pkg/policy/opa/engine.go @@ -40,7 +40,8 @@ import ( ) var ( - errInitFailed = fmt.Errorf("failed to initialize OPA policy engine") + // ErrInitFailed error + ErrInitFailed = fmt.Errorf("failed to initialize OPA policy engine") ) // NewEngine returns a new OPA policy engine @@ -246,7 +247,7 @@ func (e *Engine) Init(policyPath string, scanRules, skipRules, categories []stri if err := e.LoadRegoFiles(policyPath); err != nil { zap.S().Error("error loading rego files", zap.String("policy path", policyPath), zap.Error(err)) - return errInitFailed + return ErrInitFailed } // before compiling the rego files, filter the rules based on scan and skip rules, and severity level supplied @@ -258,7 +259,7 @@ func (e *Engine) Init(policyPath string, scanRules, skipRules, categories []stri err := e.CompileRegoFiles() if err != nil { zap.S().Error("error compiling rego files", zap.String("policy path", policyPath), zap.Error(err)) - return errInitFailed + return ErrInitFailed } // initialize ViolationStore diff --git a/pkg/runtime/executor.go b/pkg/runtime/executor.go index 08b9360c7..73c5aabc9 100644 --- a/pkg/runtime/executor.go +++ b/pkg/runtime/executor.go @@ -56,7 +56,7 @@ func NewExecutor(iacType, iacVersion string, cloudType []string, filePath, dirPa } // read config file and update scan and skip rules - if err := e.initRuleSetFromConfigFile(); err != nil { + if err := e.loadRuleSetFromConfig(); err != nil { zap.S().Error("error initialising scan and skip rules", zap.Error(err)) return nil, err } @@ -102,11 +102,11 @@ func (e *Executor) Init() error { } // create new notifiers - e.notifiers, err = notifications.NewNotifiers(e.configFile) + e.notifiers, err = notifications.NewNotifiers() if err != nil { zap.S().Debug("failed to create notifier(s).", zap.Error(err)) // do not return an error if a key is not present in the config file - if err != notifications.ErrTomlKeyNotPresent { + if err != notifications.ErrNotificationNotPresent { zap.S().Error("failed to create notifier(s).", zap.Error(err)) return err } diff --git a/pkg/runtime/executor_test.go b/pkg/runtime/executor_test.go index 3caf43076..ca63be4d6 100644 --- a/pkg/runtime/executor_test.go +++ b/pkg/runtime/executor_test.go @@ -18,16 +18,16 @@ package runtime import ( "fmt" + iacProvider "github.com/accurics/terrascan/pkg/iac-providers" + tfv12 "github.com/accurics/terrascan/pkg/iac-providers/terraform/v12" + tfv14 "github.com/accurics/terrascan/pkg/iac-providers/terraform/v14" + "github.com/accurics/terrascan/pkg/notifications/webhook" "reflect" "testing" "github.com/accurics/terrascan/pkg/config" - iacProvider "github.com/accurics/terrascan/pkg/iac-providers" "github.com/accurics/terrascan/pkg/iac-providers/output" - tfv12 "github.com/accurics/terrascan/pkg/iac-providers/terraform/v12" - tfv14 "github.com/accurics/terrascan/pkg/iac-providers/terraform/v14" "github.com/accurics/terrascan/pkg/notifications" - "github.com/accurics/terrascan/pkg/notifications/webhook" "github.com/accurics/terrascan/pkg/policy" "github.com/accurics/terrascan/pkg/utils" ) @@ -174,7 +174,6 @@ func TestExecute(t *testing.T) { } func TestInit(t *testing.T) { - table := []struct { name string executor Executor @@ -267,32 +266,6 @@ func TestInit(t *testing.T) { wantErr: fmt.Errorf("(3, 5): no value can start with c"), wantIacProvider: &tfv14.TfV14{}, }, - } - - for _, tt := range table { - t.Run(tt.name, func(t *testing.T) { - gotErr := tt.executor.Init() - if !reflect.DeepEqual(gotErr, tt.wantErr) { - t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr) - } - if !reflect.DeepEqual(tt.executor.iacProvider, tt.wantIacProvider) { - t.Errorf("got: '%v', want: '%v'", tt.executor.iacProvider, tt.wantIacProvider) - } - for i, notifier := range tt.executor.notifiers { - if !reflect.DeepEqual(reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) { - t.Errorf("got: '%v', want: '%v'", reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) - } - } - }) - } - - table = []struct { - name string - executor Executor - wantErr error - wantIacProvider iacProvider.IacProvider - wantNotifiers []notifications.Notifier - }{ { name: "valid filePath", executor: Executor{ @@ -367,17 +340,27 @@ func TestInit(t *testing.T) { } for _, tt := range table { + t.Run(tt.name, func(t *testing.T) { - gotErr := tt.executor.Init() - if !reflect.DeepEqual(gotErr, tt.wantErr) { - t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr) - } - if !reflect.DeepEqual(tt.executor.iacProvider, tt.wantIacProvider) { - t.Errorf("got: '%v', want: '%v'", tt.executor.iacProvider, tt.wantIacProvider) - } - for i, notifier := range tt.executor.notifiers { - if !reflect.DeepEqual(reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) { - t.Errorf("got: '%v', want: '%v'", reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) + configErr := config.LoadGlobalConfig(tt.executor.configFile) + if configErr != nil { + if !reflect.DeepEqual(configErr, tt.wantErr) { + t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", configErr, tt.wantErr) + } + } else { + gotErr := tt.executor.Init() + if !reflect.DeepEqual(gotErr, tt.wantErr) { + t.Errorf("unexpected error; gotErr: '%v', wantErr: '%v'", gotErr, tt.wantErr) + } + if !reflect.DeepEqual(tt.executor.iacProvider, tt.wantIacProvider) { + t.Errorf("got: '%v', want: '%v'", tt.executor.iacProvider, tt.wantIacProvider) + } + if len(tt.wantNotifiers) > 0 { + for i, notifier := range tt.executor.notifiers { + if !reflect.DeepEqual(reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) { + t.Errorf("got: '%v', want: '%v'", reflect.TypeOf(notifier), reflect.TypeOf(tt.wantNotifiers[i])) + } + } } } }) @@ -521,6 +504,8 @@ func TestNewExecutor(t *testing.T) { for _, tt := range table { t.Run(tt.name, func(t *testing.T) { + config.LoadGlobalConfig(tt.configfile) + gotExecutor, gotErr := NewExecutor(tt.flags.iacType, tt.flags.iacVersion, tt.flags.cloudType, tt.flags.filePath, tt.flags.dirPath, tt.configfile, tt.flags.policyPath, tt.flags.scanRules, tt.flags.skipRules, tt.flags.categories, tt.flags.severity) if !reflect.DeepEqual(tt.wantErr, gotErr) { diff --git a/pkg/runtime/rules.go b/pkg/runtime/rules.go index 7f2a34c56..a5ed5d18a 100644 --- a/pkg/runtime/rules.go +++ b/pkg/runtime/rules.go @@ -2,39 +2,26 @@ package runtime import ( "github.com/accurics/terrascan/pkg/config" - "go.uber.org/zap" ) // read the config file and update scan and skip rules -func (e *Executor) initRuleSetFromConfigFile() error { - if e.configFile == "" { - return nil - } - - configReader, err := config.NewTerrascanConfigReader(e.configFile) - if err != nil { - zap.S().Error("error loading config file", zap.Error(err)) - return err - } +func (e *Executor) loadRuleSetFromConfig() error { // append scan rules - if len(configReader.GetRules().ScanRules) > 0 { - e.scanRules = append(e.scanRules, configReader.GetRules().ScanRules...) + if len(config.GetScanRules()) > 0 { + e.scanRules = append(e.scanRules, config.GetScanRules()...) } // append skip rules - if len(configReader.GetRules().SkipRules) > 0 { - e.skipRules = append(e.skipRules, configReader.GetRules().SkipRules...) + if len(config.GetSkipRules()) > 0 { + e.skipRules = append(e.skipRules, config.GetSkipRules()...) } - // specify category of violations to be reported - if len(configReader.GetCategory().List) > 0 { - e.categories = configReader.GetCategory().List - } + e.categories = config.GetCategoryList() // specify severity of violations to be reported - if len(configReader.GetSeverity().Level) > 0 { - e.severity = configReader.GetSeverity().Level + if len(config.GetSeverityLevel()) > 0 { + e.severity = config.GetSeverityLevel() } return nil diff --git a/pkg/runtime/rules_test.go b/pkg/runtime/rules_test.go deleted file mode 100644 index 12feafd0c..000000000 --- a/pkg/runtime/rules_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package runtime - -import ( - "testing" - - "github.com/accurics/terrascan/pkg/utils" -) - -func TestExecutorInitRulesSeverityAndCategories(t *testing.T) { - type fields struct { - configFile string - scanRules []string - skipRules []string - categories []string - severity string - } - tests := []struct { - name string - fields fields - wantErr bool - assert bool - lenScanRules int - lenSkipRules int - lenCategories int - severity string - }{ - { - name: "no config file", - fields: fields{}, - }, - { - name: "config file doesn't exist", - fields: fields{ - configFile: "testdata/test.toml", - }, - wantErr: true, - }, - { - name: "empty config file", - fields: fields{ - configFile: "testdata/empty.toml", - }, - }, - { - name: "config file with empty rules", - fields: fields{ - configFile: "testdata/webhook.toml", - }, - }, - { - name: "valid config file with scan and skip rules", - fields: fields{ - configFile: "testdata/scan-skip-rules.toml", - scanRules: []string{"testRuleA", "testRuleB"}, - skipRules: []string{"testRuleC"}, - }, - assert: true, - lenScanRules: 4, - lenSkipRules: 5, - }, - { - name: "valid config file with scan and skip rules with low severity and compliance validation category", - fields: fields{ - configFile: "testdata/scan-skip-rules-low-severity.toml", - scanRules: []string{"testRuleA", "testRuleB"}, - skipRules: []string{"testRuleC"}, - categories: []string{"RESILIENCE", "IDENTITY AND ACCESS MANAGEMENT"}, - severity: "low", - }, - assert: true, - lenScanRules: 4, - lenSkipRules: 5, - }, - { - name: "valid config file with invalid scan rules", - fields: fields{ - configFile: "testdata/invalid-scan-skip-rules.toml", - }, - wantErr: true, - }, - { - name: "valid config file with invalid skip rules", - fields: fields{ - configFile: "testdata/invalid-skip-rules.toml", - }, - wantErr: true, - }, - { - - name: "valid config file with invalid severity", - fields: fields{ - configFile: "testdata/invalid-severity.toml", - }, - wantErr: true, - }, - { - name: "valid config file with invalid category", - fields: fields{ - configFile: "testdata/invalid-category.toml", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - e := &Executor{ - configFile: tt.fields.configFile, - scanRules: tt.fields.scanRules, - skipRules: tt.fields.skipRules, - } - if err := e.initRuleSetFromConfigFile(); (err != nil) != tt.wantErr { - t.Errorf("Executor.initRulesAndSeverity() error = %v, wantErr %v", err, tt.wantErr) - } - if tt.assert { - if len(e.scanRules) != tt.lenScanRules && len(e.skipRules) != tt.lenSkipRules && e.severity != tt.severity { - t.Errorf("Executor.TestExecutorInitRulesSeverityAndCategories() expected scanRules: %d , skipRules: %d & severity : %s, got scanRules: %d , skipRules: %d and severity: %s", tt.lenScanRules, tt.lenSkipRules, tt.severity, len(e.scanRules), len(e.skipRules), e.severity) - } - if !utils.IsSliceEqual(e.categories, tt.fields.categories) { - t.Errorf("Executor.TestExecutorInitRulesSeverityAndCategories() expected categories: %v, got categories: %v", e.categories, tt.fields.categories) - } - } - }) - } -} diff --git a/pkg/runtime/validate.go b/pkg/runtime/validate.go index 89e6e8798..5e975f76b 100644 --- a/pkg/runtime/validate.go +++ b/pkg/runtime/validate.go @@ -103,13 +103,6 @@ func (e *Executor) ValidateInputs() error { e.iacVersion = IacProvider.GetDefaultIacVersion(e.iacType) } - // check if IaC type is supported - if !IacProvider.IsIacSupported(e.iacType, e.iacVersion) { - zap.S().Errorf("iac type '%s', version '%s' not supported", e.iacType, e.iacVersion) - return errIacNotSupported - } - zap.S().Debugf("iac type '%s', version '%s' is supported", e.iacType, e.iacVersion) - // check if cloud type is supported for _, ct := range e.cloudType { if !policy.IsCloudProviderSupported(ct) { @@ -118,11 +111,20 @@ func (e *Executor) ValidateInputs() error { } } zap.S().Debugf("cloud type '%s' is supported", strings.Join(e.cloudType, ",")) + if len(e.policyPath) == 0 { e.policyPath = policy.GetDefaultPolicyPaths(e.cloudType) } + zap.S().Debugf("using policy path %v", e.policyPath) + // check if IaC type is supported + if !IacProvider.IsIacSupported(e.iacType, e.iacVersion) { + zap.S().Errorf("iac type '%s', version '%s' not supported", e.iacType, e.iacVersion) + return errIacNotSupported + } + zap.S().Debugf("iac type '%s', version '%s' is supported", e.iacType, e.iacVersion) + if len(e.categories) > 0 { if isValid, invalidInputs := utils.ValidateCategoryInput(e.categories); !isValid { diff --git a/pkg/utils/policy.go b/pkg/utils/policy.go new file mode 100644 index 000000000..b59071ed0 --- /dev/null +++ b/pkg/utils/policy.go @@ -0,0 +1,32 @@ +package utils + +import ( + "path/filepath" + "strings" + + "github.com/pkg/errors" + "go.uber.org/zap" +) + +// GetAbsPolicyConfigPaths tranforms the provided policy base path and repo path into absolute paths +func GetAbsPolicyConfigPaths(policyBasePath, policyRepoPath string) (string, string, error) { + absolutePolicyBasePath, err := GetAbsPath(policyBasePath) + if err != nil { + return policyBasePath, policyRepoPath, errors.Errorf("invalid policy path `%s`, error : `%v`", policyBasePath, err) + } + + absolutePolicyRepoPath, err := GetAbsPath(policyRepoPath) + if err != nil { + return policyRepoPath, policyBasePath, errors.Errorf("invalid repository path `%s`, error : `%v`", policyRepoPath, err) + } + + if strings.HasPrefix(absolutePolicyRepoPath, absolutePolicyBasePath) { + return absolutePolicyBasePath, absolutePolicyRepoPath, nil + } + + zap.S().Debugf("absolute rego_subdir path, `%s`, does not fall under base repo path's `%s` directory structure", absolutePolicyRepoPath, absolutePolicyBasePath) + zap.S().Debugf("appending rego_subdir path: `%s` to the policy base path: `%s`. checking ...", policyRepoPath, policyBasePath) + + absolutePolicyRepoPath = filepath.Join(absolutePolicyBasePath, policyRepoPath) + return absolutePolicyBasePath, absolutePolicyRepoPath, nil +} diff --git a/test/e2e/init/config/home_prefix_path_config.toml b/test/e2e/init/config/home_prefix_path_config.toml new file mode 100644 index 000000000..ecd0e79cd --- /dev/null +++ b/test/e2e/init/config/home_prefix_path_config.toml @@ -0,0 +1,5 @@ +[policy] +repo_url = "https://github.com/accurics/terrascan.git" +branch = "master" +path = "~/.terrascan-test" +rego_subdir = "pkg/policies/opa/rego" diff --git a/test/e2e/init/config/home_prefixed_path.toml b/test/e2e/init/config/home_prefixed_path.toml new file mode 100644 index 000000000..53da6593c --- /dev/null +++ b/test/e2e/init/config/home_prefixed_path.toml @@ -0,0 +1,2 @@ +[policy] +path = "~/.terrascan-test" diff --git a/test/e2e/init/config/invalid_path.toml b/test/e2e/init/config/invalid_path.toml deleted file mode 100644 index bcdcceaf4..000000000 --- a/test/e2e/init/config/invalid_path.toml +++ /dev/null @@ -1,2 +0,0 @@ -[policy] -path = "invalid/path" \ No newline at end of file diff --git a/test/e2e/init/config/invalid_rego_subdir.toml b/test/e2e/init/config/invalid_rego_subdir.toml deleted file mode 100644 index 2b1cb5524..000000000 --- a/test/e2e/init/config/invalid_rego_subdir.toml +++ /dev/null @@ -1,2 +0,0 @@ -[policy] -rego_subdir = "invalid/path" \ No newline at end of file diff --git a/test/e2e/init/config/kai_monkey_relative_path.toml b/test/e2e/init/config/kai_monkey_relative_path.toml new file mode 100644 index 000000000..975ac250b --- /dev/null +++ b/test/e2e/init/config/kai_monkey_relative_path.toml @@ -0,0 +1,4 @@ +[policy] +repo_url = "https://github.com/accurics/KaiMonkey.git" +branch = "master" +path = "policy/base_path" diff --git a/test/e2e/init/config/relative_path.toml b/test/e2e/init/config/relative_path.toml new file mode 100644 index 000000000..8d5709e39 --- /dev/null +++ b/test/e2e/init/config/relative_path.toml @@ -0,0 +1,2 @@ +[policy] +path = "policy/base_path" diff --git a/test/e2e/init/config/relative_rego_subdir.toml b/test/e2e/init/config/relative_rego_subdir.toml new file mode 100644 index 000000000..301241f76 --- /dev/null +++ b/test/e2e/init/config/relative_rego_subdir.toml @@ -0,0 +1,2 @@ +[policy] +rego_subdir = "policy/sub_path" diff --git a/test/e2e/init/config/valid_config.toml b/test/e2e/init/config/valid_config.toml index 1251133bd..ecd0e79cd 100644 --- a/test/e2e/init/config/valid_config.toml +++ b/test/e2e/init/config/valid_config.toml @@ -1,4 +1,5 @@ [policy] -repo_url = "https://github.com/accurics/KaiMonkey.git" +repo_url = "https://github.com/accurics/terrascan.git" branch = "master" -path = "valid/path" \ No newline at end of file +path = "~/.terrascan-test" +rego_subdir = "pkg/policies/opa/rego" diff --git a/test/e2e/init/config/valid_paths.toml b/test/e2e/init/config/valid_paths.toml new file mode 100644 index 000000000..98c711baf --- /dev/null +++ b/test/e2e/init/config/valid_paths.toml @@ -0,0 +1,3 @@ +[policy] +path = "~/.terrascan-test" +rego_subdir = "pkg/policies/opa/rego" diff --git a/test/e2e/init/config/valid_repo.toml b/test/e2e/init/config/valid_repo.toml new file mode 100644 index 000000000..eee8e0be4 --- /dev/null +++ b/test/e2e/init/config/valid_repo.toml @@ -0,0 +1,3 @@ +[policy] +repo_url = "https://github.com/accurics/KaiMonkey.git" +branch = "master" diff --git a/test/e2e/init/init_test.go b/test/e2e/init/init_test.go index a19db4a6c..3aea8c250 100644 --- a/test/e2e/init/init_test.go +++ b/test/e2e/init/init_test.go @@ -17,11 +17,6 @@ package init_test import ( - "io" - "os" - "path/filepath" - "time" - "github.com/accurics/terrascan/pkg/utils" initUtil "github.com/accurics/terrascan/test/e2e/init" "github.com/accurics/terrascan/test/helper" @@ -30,15 +25,24 @@ import ( "github.com/onsi/gomega/gbytes" "github.com/onsi/gomega/gexec" "gopkg.in/src-d/go-git.v4" + "io" + "os" + "path/filepath" + "time" ) var ( - initCommand string = "init" - defaultPolicyRepoPath string = filepath.Join(utils.GetHomeDir(), ".terrascan") - terrascanGitURL string = "https://github.com/accurics/terrascan.git" - terrascanDefaultBranch string = "master" - terrascanConfigEnvName string = "TERRASCAN_CONFIG" - kaiMoneyGitURL string = "https://github.com/accurics/KaiMonkey.git" + initCommand = "init" + defaultPolicyRepoPath = filepath.Join(utils.GetHomeDir(), ".terrascan") + terrascanGitURL = "https://github.com/accurics/terrascan.git" + terrascanDefaultBranch = "master" + terrascanConfigEnvName = "TERRASCAN_CONFIG" + kaiMoneyGitURL = "https://github.com/accurics/KaiMonkey.git" + + testPolicyRepoPath = filepath.Join(utils.GetHomeDir(), ".terrascan-test") + testRegoSubDirPath = filepath.Join(testPolicyRepoPath, "pkg", "policies", "opa", "rego") + warnNoBasePath = "policy rego_subdir specified in configfile config/relative_rego_subdir.toml, but base path not specified." + warnNoSubDirPath = "policy base path specified in configfile config/home_prefixed_path.toml, but rego_subdir path not specified." ) var _ = Describe("Init", func() { @@ -64,6 +68,7 @@ var _ = Describe("Init", func() { Describe("terrascan init is run", func() { When("without any flags", func() { + It("should download policies and exit with status code 0", func() { session = initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) Expect(outWriter).Should(gbytes.Say("")) @@ -116,14 +121,81 @@ var _ = Describe("Init", func() { Eventually(session, 5).Should(gexec.Exit(helper.ExitCodeOne)) }) }) + }) + + Describe("terrascan init is run with -c flag", func() { + + Context("config file has valid policy repo and branch data", func() { + + It("should download policies as per the policy config in the config file", func() { + configFile := filepath.Join("config", "valid_repo.toml") + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, "init", "-c", configFile) + helper.ValidateExitCode(session, initUtil.InitCommandTimeout, helper.ExitCodeZero) + }) + + Context("KaiMonkey git repo is downloaded", func() { + It("should validate KaiMonkey repo in the policy path", func() { + repo := initUtil.OpenGitRepo(defaultPolicyRepoPath) + initUtil.ValidateGitRepo(repo, kaiMoneyGitURL) + }) + }) + + }) + + Context("config file has valid policy path and rego_subdir data", func() { + It("should download policies as per the policy config in the config file", func() { + configFile := filepath.Join("config", "valid_paths.toml") + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, "init", "-c", configFile) + helper.ValidateExitCode(session, initUtil.InitCommandTimeout, helper.ExitCodeZero) + }) + + It("should validate terrascan repo in the policy path", func() { + repo := initUtil.OpenGitRepo(testPolicyRepoPath) + initUtil.ValidateGitRepo(repo, terrascanGitURL) + }) + + os.RemoveAll(testPolicyRepoPath) + }) + + Context("config file has all valid policy config data", func() { + + It("should download policies as per the policy config in the config file", func() { + configFile := filepath.Join("config", "valid_config.toml") + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, "init", "-c", configFile) + helper.ValidateExitCode(session, initUtil.InitCommandTimeout, helper.ExitCodeZero) + }) + + Context("terrascan git repo is downloaded", func() { + It("should validate terrascan repo in the policy path", func() { + repo := initUtil.OpenGitRepo(testPolicyRepoPath) + initUtil.ValidateGitRepo(repo, terrascanGitURL) + helper.ValidateDirectoryExists(testRegoSubDirPath) + }) + }) + + os.RemoveAll(testPolicyRepoPath) + }) + + Context("config file has all valid policy paths with ~ prefix base path", func() { + + It("should download policies as per the policy config in the config file", func() { + configFile := filepath.Join("config", "home_prefix_path_config.toml") + session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, "init", "-c", configFile) + helper.ValidateExitCode(session, initUtil.InitCommandTimeout, helper.ExitCodeZero) + }) - When("terrascan init is run with -c flag", func() { - Context("config file has valid policy config data", func() { - It("should download policies as per the policy config in the config file", func() { - Skip("skipping this test due to https://github.com/accurics/terrascan/issues/550, should be implemented when fixed") + Context("terrascan git repo is downloaded", func() { + It("should validate terrascan repo in the policy path", func() { + repo := initUtil.OpenGitRepo(testPolicyRepoPath) + initUtil.ValidateGitRepo(repo, terrascanGitURL) + subpath := testRegoSubDirPath //filepath.Join(path, "pkg/policies/opa/rego") + helper.ValidateDirectoryExists(subpath) }) }) + + os.RemoveAll(testPolicyRepoPath) }) + }) Describe("terrascan init is run when TERRASCAN_CONFIG is set", func() { @@ -151,55 +223,113 @@ var _ = Describe("Init", func() { helper.ContainsErrorSubString(session, `failed to initialize terrascan. error : failed to checkout git branch 'invalid-branch'. error: 'reference not found'`) }) }) - When("the config file has invalid rego subdir", func() { + When("the config file has relative rego subdir", func() { JustBeforeEach(func() { - os.Setenv(terrascanConfigEnvName, filepath.Join("config", "invalid_rego_subdir.toml")) + os.Setenv(terrascanConfigEnvName, filepath.Join("config", "relative_rego_subdir.toml")) }) JustAfterEach(func() { os.Setenv(terrascanConfigEnvName, "") }) + // The current behavior of terrascan is that, in case of init command, even if the value of // rego_subdir is an invalid/non-existant directory, the init is successful and repoURL will be // cloned at the base path (either default or based on config file) - It("should not error out and exit with status code 0", func() { - initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + It("should log a warning & download the policies at default base path", func() { + session = initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + repo := initUtil.OpenGitRepo(defaultPolicyRepoPath) + initUtil.ValidateGitRepo(repo, terrascanGitURL) + }) + + It("should log a warning stating no base path speicified", func() { + helper.ContainsErrorSubString(session, warnNoBasePath) }) }) - When("the config file has invalid path", func() { + + When("the config file has relative path", func() { + path, err := utils.GetAbsPath("policy/base_path") + JustBeforeEach(func() { - os.Setenv(terrascanConfigEnvName, filepath.Join("config", "invalid_path.toml")) + os.Setenv(terrascanConfigEnvName, filepath.Join("config", "relative_path.toml")) }) JustAfterEach(func() { os.Setenv(terrascanConfigEnvName, "") //remove the cloned repo at "invalid/path", (refer to 'path' in "config/invalid_path.toml") os.RemoveAll("invalid") }) + // The current behavior of terrascan is that, when init command is being run with an invalid/ // non-existant base path, the specified path gets created and repoURL is cloned at that location - It("should download policies and exit with status code 0", func() { - initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + It("should work fine and give out exit code zero", func() { + session = initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + }) + It("should download the policy repo at the specified path (relative to the cwd)", func() { + Expect(err).ToNot(HaveOccurred()) + repo := initUtil.OpenGitRepo(path) + initUtil.ValidateGitRepo(repo, terrascanGitURL) + os.RemoveAll(path) + }) + }) + + When("the config file has relative path with kai monkey repository specified", func() { + path, err := utils.GetAbsPath("policy/base_path") + + JustBeforeEach(func() { + os.Setenv(terrascanConfigEnvName, filepath.Join("config", "kai_monkey_relative_path.toml")) + }) + JustAfterEach(func() { + os.Setenv(terrascanConfigEnvName, "") + }) + It("should work fine and give out exit code zero", func() { + session = initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + }) + It("should download the policy repo at the specified path (relative to the cwd)", func() { + Expect(err).ToNot(HaveOccurred()) + repo := initUtil.OpenGitRepo(path) + initUtil.ValidateGitRepo(repo, kaiMoneyGitURL) + os.RemoveAll(path) + }) + + }) + + When("the config file has a ~ prefixed path and no rego_subdir", func() { + JustBeforeEach(func() { + os.Setenv(terrascanConfigEnvName, filepath.Join("config", "home_prefixed_path.toml")) + }) + JustAfterEach(func() { + os.Setenv(terrascanConfigEnvName, "") + }) + + It("should download the policies at $HOME/", func() { + session = initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) + repo := initUtil.OpenGitRepo(testPolicyRepoPath) + initUtil.ValidateGitRepo(repo, terrascanGitURL) }) + + It("should log a warning stating no rego_subdir specified", func() { + helper.ContainsErrorSubString(session, warnNoSubDirPath) + }) + + os.RemoveAll(testPolicyRepoPath) }) + Context("the config file has valid data", func() { When("config file has different git repo and branch", func() { JustBeforeEach(func() { - os.Setenv(terrascanConfigEnvName, filepath.Join("config", "valid_config.toml")) + os.Setenv(terrascanConfigEnvName, filepath.Join("config", "valid_repo.toml")) }) JustAfterEach(func() { os.Setenv(terrascanConfigEnvName, "") - //remove the cloned repo at "valid/path", (refer to 'path' in "config/valid_config.toml") - os.RemoveAll("valid") }) It("init should download the repo provided in the config file", func() { initUtil.RunInitCommand(terrascanBinaryPath, outWriter, errWriter, helper.ExitCodeZero) - basePathInValidConfig := "valid/path" // Kai Monkey git repo is downloaded // validate Kai Monkey repo in the repo path - repo := initUtil.OpenGitRepo(basePathInValidConfig) + repo := initUtil.OpenGitRepo(defaultPolicyRepoPath) initUtil.ValidateGitRepo(repo, kaiMoneyGitURL) }) }) }) + }) Describe("terrascan init is run multiple times", func() { diff --git a/test/e2e/init/init_utils.go b/test/e2e/init/init_utils.go index dbf0f005e..f401f6086 100644 --- a/test/e2e/init/init_utils.go +++ b/test/e2e/init/init_utils.go @@ -17,22 +17,20 @@ package init import ( - "io" - "github.com/accurics/terrascan/test/helper" "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" "gopkg.in/src-d/go-git.v4" + "io" ) -const ( - initCommandTimeout = 60 -) +// InitCommandTimeout timeout +const InitCommandTimeout = 60 // RunInitCommand will execute the init command and verify exit code func RunInitCommand(terrascanBinaryPath string, outWriter, errWriter io.Writer, exitCode int) *gexec.Session { session := helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, "init") - gomega.Eventually(session, initCommandTimeout).Should(gexec.Exit(exitCode)) + gomega.Eventually(session, InitCommandTimeout).Should(gexec.Exit(exitCode)) return session } diff --git a/test/e2e/scan/scan_remote_test.go b/test/e2e/scan/scan_remote_test.go index 1b2c3bd10..88b5a3ec8 100644 --- a/test/e2e/scan/scan_remote_test.go +++ b/test/e2e/scan/scan_remote_test.go @@ -42,35 +42,35 @@ var _ = Describe("Scan Command using remote types", func() { When("remote type is git", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "git"} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) When("remote type is s3", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "s3"} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) When("remote type is gcs", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "gcs"} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) When("remote type is http", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "http"} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) When("remote type is terraform-registry", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "terraform-registry"} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) }) @@ -81,7 +81,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "git", "--remote-url", invalidRemoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) @@ -96,7 +96,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "s3", "--remote-url", invalidRemoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) @@ -104,7 +104,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "gcs", "--remote-url", invalidRemoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) @@ -112,7 +112,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "http", "--remote-url", invalidRemoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) @@ -120,7 +120,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "terraform-registry", "--remote-url", invalidRemoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) @@ -128,7 +128,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { errString := "supplied remote type is not supported" scanArgs := []string{scanUtils.ScanCommand, "-r", "unsupportedType", "--remote-url", invalidRemoteURL} - scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.ScanTimeout, errString, outWriter, errWriter, scanArgs...) + scanUtils.RunScanAndAssertErrorMessage(terrascanBinaryPath, helper.ExitCodeOne, scanUtils.RemoteScanTimeout, errString, outWriter, errWriter, scanArgs...) }) }) }) @@ -139,14 +139,14 @@ var _ = Describe("Scan Command using remote types", func() { It("should download the resource and generate scan results", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "git", "--remote-url", remoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, 10).Should(gexec.Exit(helper.ExitCodeThree)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeThree)) }) It("should download the resource and generate scan results", func() { remoteURL := "https://github.com/accurics/KaiMonkey.git//terraform/aws" scanArgs := []string{scanUtils.ScanCommand, "-r", "git", "--remote-url", remoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, 10).Should(gexec.Exit(helper.ExitCodeThree)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeThree)) }) }) @@ -175,7 +175,7 @@ var _ = Describe("Scan Command using remote types", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "terraform-registry", "--remote-url", remoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) // has a OR condition because we don't know if there would be violations or not - Eventually(session, 10).Should(Or(gexec.Exit(helper.ExitCodeThree), gexec.Exit(helper.ExitCodeZero))) + Eventually(session, scanUtils.RemoteScanTimeout).Should(Or(gexec.Exit(helper.ExitCodeThree), gexec.Exit(helper.ExitCodeZero))) }) }) @@ -191,7 +191,7 @@ var _ = Describe("Scan Command using remote types", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "terraform-registry", "--remote-url", remoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) // has a OR condition because we don't know if there would be violations or not - Eventually(session, 10).Should(Or(gexec.Exit(helper.ExitCodeThree), gexec.Exit(helper.ExitCodeZero))) + Eventually(session, scanUtils.RemoteScanTimeout).Should(Or(gexec.Exit(helper.ExitCodeThree), gexec.Exit(helper.ExitCodeZero))) }) }) @@ -206,7 +206,7 @@ var _ = Describe("Scan Command using remote types", func() { It("should error out and exit with status code 1", func() { scanArgs := []string{scanUtils.ScanCommand, "-r", "terraform-registry", "--remote-url", remoteURL} session = helper.RunCommand(terrascanBinaryPath, outWriter, errWriter, scanArgs...) - Eventually(session, scanUtils.ScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) + Eventually(session, scanUtils.RemoteScanTimeout).Should(gexec.Exit(helper.ExitCodeOne)) }) }) }) diff --git a/test/e2e/scan/scan_utils.go b/test/e2e/scan/scan_utils.go index e08346a36..44262b078 100644 --- a/test/e2e/scan/scan_utils.go +++ b/test/e2e/scan/scan_utils.go @@ -28,8 +28,12 @@ import ( const ( // ScanCommand is terrascan's scan command ScanCommand string = "scan" + // ScanTimeout is default scan command execution timeout ScanTimeout int = 3 + + // RemoteScanTimeout is default scan command remote execution timeout + RemoteScanTimeout int = 20 ) // RunScanAndAssertGoldenOutputRegex runs the scan command with supplied paramters and compares actual and golden output diff --git a/test/helper/helper.go b/test/helper/helper.go index f557ac77c..c9f4e822b 100644 --- a/test/helper/helper.go +++ b/test/helper/helper.go @@ -69,6 +69,18 @@ var ( sourceRegexPattern = regexp.MustCompile(`["]*source["]*[ \t]*[:][ \t]*["]*(.+)\/(.+)["]*`) ) +// ValidateExitCode validates the exit code of a gexec.Session +func ValidateExitCode(session *gexec.Session, timeout, exitCode int) { + gomega.Eventually(session, timeout).Should(gexec.Exit(exitCode)) +} + +// ValidateDirectoryExists validates that a directory exists at the provided path +func ValidateDirectoryExists(path string) { + _, err := os.Stat(path) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + gomega.Expect(path).To(gomega.BeADirectory()) +} + // CompareActualWithGolden compares actual string with contents of golden file path passed as parameter func CompareActualWithGolden(session *gexec.Session, goldenFileAbsPath string, isStdOut bool) { sessionBytes, fileBytes := GetByteData(session, goldenFileAbsPath, isStdOut)