diff --git a/integration/client_server_test.go b/integration/client_server_test.go index 3a06aadc10..c1b5b4d601 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -18,18 +18,21 @@ import ( "github.com/stretchr/testify/require" ) +type args struct { + Format string + TemplatePath string + Version string + IgnoreUnfixed bool + Severity []string + IgnoreIDs []string + Input string + ClientToken string + ClientTokenHeader string + ServerToken string + ServerTokenHeader string +} + func TestClientServer(t *testing.T) { - type args struct { - Version string - IgnoreUnfixed bool - Severity []string - IgnoreIDs []string - Input string - ClientToken string - ClientTokenHeader string - ServerToken string - ServerTokenHeader string - } cases := []struct { name string testArgs args @@ -85,6 +88,16 @@ func TestClientServer(t *testing.T) { }, golden: "testdata/alpine-310-ignore-cveids.json.golden", }, + { + name: "alpine 3.10 integration with gitlab template", + testArgs: args{ + Format: "template", + TemplatePath: "@../contrib/gitlab.tpl", + Version: "dev", + Input: "testdata/fixtures/alpine-310.tar.gz", + }, + golden: "testdata/alpine-310.gitlab.golden", + }, { name: "alpine 3.9 integration", testArgs: args{ @@ -345,8 +358,7 @@ func TestClientServer(t *testing.T) { app := internal.NewApp(c.testArgs.Version) app.Writer = ioutil.Discard - osArgs, outputFile, cleanup := setupClient(t, c.testArgs.IgnoreUnfixed, c.testArgs.Severity, - c.testArgs.IgnoreIDs, addr, c.testArgs.ClientToken, c.testArgs.ClientTokenHeader, c.testArgs.Input, cacheDir, c.golden) + osArgs, outputFile, cleanup := setupClient(t, c.testArgs, addr, cacheDir, c.golden) defer cleanup() // Run Trivy client @@ -379,35 +391,43 @@ func setupServer(addr, token, tokenHeader, cacheDir string) []string { return osArgs } -func setupClient(t *testing.T, ignoreUnfixed bool, severity, ignoreIDs []string, - addr, token, tokenHeader, input, cacheDir, golden string) ([]string, string, func()) { +func setupClient(t *testing.T, c args, addr string, cacheDir string, golden string) ([]string, string, func()) { t.Helper() - osArgs := []string{"trivy", "client", "--cache-dir", cacheDir, - "--format", "json", "--remote", "http://" + addr} - if ignoreUnfixed { + osArgs := []string{"trivy", "client", "--cache-dir", cacheDir, "--remote", "http://" + addr} + + if c.Format != "" { + osArgs = append(osArgs, "--format", c.Format) + if c.TemplatePath != "" { + osArgs = append(osArgs, "--template", c.TemplatePath) + } + } else { + osArgs = append(osArgs, "--format", "json") + } + + if c.IgnoreUnfixed { osArgs = append(osArgs, "--ignore-unfixed") } - if len(severity) != 0 { + if len(c.Severity) != 0 { osArgs = append(osArgs, - []string{"--severity", strings.Join(severity, ",")}..., + []string{"--severity", strings.Join(c.Severity, ",")}..., ) } var err error var ignoreTmpDir string - if len(ignoreIDs) != 0 { + if len(c.IgnoreIDs) != 0 { ignoreTmpDir, err = ioutil.TempDir("", "ignore") require.NoError(t, err, "failed to create a temp dir") trivyIgnore := filepath.Join(ignoreTmpDir, ".trivyignore") - err = ioutil.WriteFile(trivyIgnore, []byte(strings.Join(ignoreIDs, "\n")), 0444) + err = ioutil.WriteFile(trivyIgnore, []byte(strings.Join(c.IgnoreIDs, "\n")), 0444) require.NoError(t, err, "failed to write .trivyignore") osArgs = append(osArgs, []string{"--ignorefile", trivyIgnore}...) } - if token != "" { - osArgs = append(osArgs, []string{"--token", token, "--token-header", tokenHeader}...) + if c.ClientToken != "" { + osArgs = append(osArgs, []string{"--token", c.ClientToken, "--token-header", c.ClientTokenHeader}...) } - if input != "" { - osArgs = append(osArgs, []string{"--input", input}...) + if c.Input != "" { + osArgs = append(osArgs, []string{"--input", c.Input}...) } // Setup the output file diff --git a/integration/testdata/alpine-310.gitlab.golden b/integration/testdata/alpine-310.gitlab.golden new file mode 100644 index 0000000000..43b6d16c07 --- /dev/null +++ b/integration/testdata/alpine-310.gitlab.golden @@ -0,0 +1,208 @@ +{ + "version": "2.3", + "vulnerabilities": [ + { + "category": "container_scanning", + "message": "openssl: information disclosure in fork()", + "description": "OpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).", + "cve": "CVE-2019-1549", + "severity": "Medium", + "confidence": "Unknown", + "solution": "Upgrade openssl to 1.1.1d-r0", + "scanner": { + "id": "trivy", + "name": "trivy" + }, + "location": { + "dependency": { + "package": { + "name": "openssl" + }, + "version": "1.1.1c-r0" + }, + "operating_system": "Unknown", + "image": "testdata/fixtures/alpine-310.tar.gz (alpine 3.10.2)" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-1549", + "value": "CVE-2019-1549", + "url": "" + } + ], + "links": [{ + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1549" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=1b0fe00e2704b5e20334a16d3c9099d1ba2ef1be" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GY6SNRJP2S7Y42GIIDO3HXPNMDYN2U3A/" + },{ + "url": "https://security.netapp.com/advisory/ntap-20190919-0002/" + },{ + "url": "https://support.f5.com/csp/article/K44070243" + },{ + "url": "https://www.openssl.org/news/secadv/20190910.txt" + } + ] + }, + { + "category": "container_scanning", + "message": "openssl: Integer overflow in RSAZ modular exponentiation on x86_64", + "description": "There is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).", + "cve": "CVE-2019-1551", + "severity": "Medium", + "confidence": "Unknown", + "solution": "Upgrade openssl to 1.1.1d-r2", + "scanner": { + "id": "trivy", + "name": "trivy" + }, + "location": { + "dependency": { + "package": { + "name": "openssl" + }, + "version": "1.1.1c-r0" + }, + "operating_system": "Unknown", + "image": "testdata/fixtures/alpine-310.tar.gz (alpine 3.10.2)" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-1551", + "value": "CVE-2019-1551", + "url": "" + } + ], + "links": [{ + "url": "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00030.html" + },{ + "url": "http://packetstormsecurity.com/files/155754/Slackware-Security-Advisory-openssl-Updates.html" + },{ + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1551" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=419102400a2811582a7a3d4a4e317d72e5ce0a8f" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=f1c5eea8a817075d31e43f5876993c6710238c98" + },{ + "url": "https://github.com/openssl/openssl/pull/10575" + },{ + "url": "https://seclists.org/bugtraq/2019/Dec/39" + },{ + "url": "https://seclists.org/bugtraq/2019/Dec/46" + },{ + "url": "https://security.netapp.com/advisory/ntap-20191210-0001/" + },{ + "url": "https://www.debian.org/security/2019/dsa-4594" + },{ + "url": "https://www.openssl.org/news/secadv/20191206.txt" + },{ + "url": "https://www.tenable.com/security/tns-2019-09" + } + ] + }, + { + "category": "container_scanning", + "message": "openssl: information disclosure in PKCS7_dataDecode and CMS_decrypt_set1_pkey", + "description": "In situations where an attacker receives automated notification of the success or failure of a decryption attempt an attacker, after sending a very large number of messages to be decrypted, can recover a CMS/PKCS7 transported encryption key or decrypt any RSA encrypted message that was encrypted with the public RSA key, using a Bleichenbacher padding oracle attack. Applications are not affected if they use a certificate together with the private RSA key to the CMS_decrypt or PKCS7_decrypt functions to select the correct recipient info to decrypt. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).", + "cve": "CVE-2019-1563", + "severity": "Medium", + "confidence": "Unknown", + "solution": "Upgrade openssl to 1.1.1d-r0", + "scanner": { + "id": "trivy", + "name": "trivy" + }, + "location": { + "dependency": { + "package": { + "name": "openssl" + }, + "version": "1.1.1c-r0" + }, + "operating_system": "Unknown", + "image": "testdata/fixtures/alpine-310.tar.gz (alpine 3.10.2)" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-1563", + "value": "CVE-2019-1563", + "url": "" + } + ], + "links": [{ + "url": "http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html" + },{ + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1563" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=08229ad838c50f644d7e928e2eef147b4308ad64" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=631f94db0065c78181ca9ba5546ebc8bb3884b97" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e21f8cf78a125cd3c8c0d1a1a6c8bb0b901f893f" + },{ + "url": "https://seclists.org/bugtraq/2019/Sep/25" + },{ + "url": "https://security.netapp.com/advisory/ntap-20190919-0002/" + },{ + "url": "https://www.openssl.org/news/secadv/20190910.txt" + } + ] + }, + { + "category": "container_scanning", + "message": "openssl: side-channel weak encryption vulnerability", + "description": "Normally in OpenSSL EC groups always have a co-factor present and this is used in side channel resistant code paths. However, in some cases, it is possible to construct a group using explicit parameters (instead of using a named curve). In those cases it is possible that such a group does not have the cofactor present. This can occur even where all the parameters match a known named curve. If such a curve is used then OpenSSL falls back to non-side channel resistant code paths which may result in full key recovery during an ECDSA signature operation. In order to be vulnerable an attacker would have to have the ability to time the creation of a large number of signatures where explicit parameters with no co-factor present are in use by an application using libcrypto. For the avoidance of doubt libssl is not vulnerable because explicit parameters are never used. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c). Fixed in OpenSSL 1.1.0l (Affected 1.1.0-1.1.0k). Fixed in OpenSSL 1.0.2t (Affected 1.0.2-1.0.2s).", + "cve": "CVE-2019-1547", + "severity": "Low", + "confidence": "Unknown", + "solution": "Upgrade openssl to 1.1.1d-r0", + "scanner": { + "id": "trivy", + "name": "trivy" + }, + "location": { + "dependency": { + "package": { + "name": "openssl" + }, + "version": "1.1.1c-r0" + }, + "operating_system": "Unknown", + "image": "testdata/fixtures/alpine-310.tar.gz (alpine 3.10.2)" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-1547", + "value": "CVE-2019-1547", + "url": "" + } + ], + "links": [{ + "url": "http://packetstormsecurity.com/files/154467/Slackware-Security-Advisory-openssl-Updates.html" + },{ + "url": "https://arxiv.org/abs/1909.01785" + },{ + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1547" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=21c856b75d81eff61aa63b4f036bb64a85bf6d46" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=30c22fa8b1d840036b8e203585738df62a03cec8" + },{ + "url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=7c1709c2da5414f5b6133d00a03fc8c5bf996c7a" + },{ + "url": "https://seclists.org/bugtraq/2019/Sep/25" + },{ + "url": "https://security.netapp.com/advisory/ntap-20190919-0002/" + },{ + "url": "https://www.openssl.org/news/secadv/20190910.txt" + } + ] + } + ], + "remediations": [] +} diff --git a/internal/standalone/run.go b/internal/standalone/run.go index 507b32e155..dc9f28e383 100644 --- a/internal/standalone/run.go +++ b/internal/standalone/run.go @@ -2,10 +2,8 @@ package standalone import ( "context" - "io/ioutil" l "log" "os" - "strings" "github.com/aquasecurity/trivy-db/pkg/db" @@ -107,17 +105,7 @@ func run(c config.Config) (err error) { c.Severities, c.IgnoreUnfixed, c.IgnoreFile) } - template := c.Template - - if strings.HasPrefix(c.Template, "@") { - buf, err := ioutil.ReadFile(strings.TrimPrefix(c.Template, "@")) - if err != nil { - return xerrors.Errorf("Error retrieving template from path: %w", err) - } - template = string(buf) - } - - if err = report.WriteResults(c.Format, c.Output, results, template, c.Light); err != nil { + if err = report.WriteResults(c.Format, c.Output, results, c.Template, c.Light); err != nil { return xerrors.Errorf("unable to write results: %w", err) } diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 2aa84194f9..f7ebd2d10c 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "io/ioutil" "os" "strings" "text/template" @@ -25,6 +26,14 @@ type Result struct { } func WriteResults(format string, output io.Writer, results Results, outputTemplate string, light bool) error { + if strings.HasPrefix(outputTemplate, "@") { + buf, err := ioutil.ReadFile(strings.TrimPrefix(outputTemplate, "@")) + if err != nil { + return xerrors.Errorf("Error retrieving template from path: %w", err) + } + outputTemplate = string(buf) + } + var writer Writer switch format { case "table":