From 04b382b0d598dffd6bb4a3dcdd37dd0b44d25366 Mon Sep 17 00:00:00 2001 From: Peter Benjamin Date: Wed, 11 Oct 2023 19:06:54 -0700 Subject: [PATCH 1/3] feat(trivy): add trivy linter --- lua/lint/linters/trivy.lua | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 lua/lint/linters/trivy.lua diff --git a/lua/lint/linters/trivy.lua b/lua/lint/linters/trivy.lua new file mode 100644 index 00000000..4ddb5d9b --- /dev/null +++ b/lua/lint/linters/trivy.lua @@ -0,0 +1,39 @@ +local severity_map = { + ["LOW"] = vim.diagnostic.severity.INFO, + ["MEDIUM"] = vim.diagnostic.severity.WARN, + ["HIGH"] = vim.diagnostic.severity.ERROR, +} + +return { + cmd = "trivy", + stdin = false, + append_fname = true, + args = { "--scanners", "config", "--format", "json" }, + stream = "stdout", + parser = function(output, bufnr) + local diagnostics = {} + local ok, decoded = pcall(vim.json.decode, output) + if not ok then + return diagnostics + end + local fpath = vim.api.nvim_buf_get_name(bufnr) + for _, result in ipairs(decoded and decoded.Results or {}) do + if result.Target == fpath then + for _, misconfig in ipairs(result.Misconfigurations) do + local err = { + source = "trivy", + message = string.format("%s - %s - %s", misconfig.Message, misconfig.Title, misconfig.Description), + col = misconfig.CauseMetadata.StartLine, + end_col = misconfig.CauseMetadata.EndLine, + lnum = misconfig.CauseMetadata.StartLine - 1, + end_lnum = misconfig.CauseMetadata.EndLine - 1, + code = misconfig.ID, + severity = severity_map[misconfig.Severity], + } + table.insert(diagnostics, err) + end + end + end + return diagnostics + end, +} From 790dcaf9fb00a5a1f7c36f3b3ed0a895b711a4f6 Mon Sep 17 00:00:00 2001 From: Peter Benjamin Date: Wed, 11 Oct 2023 19:23:50 -0700 Subject: [PATCH 2/3] fix(trivy): fix trivy linter --- lua/lint/linters/trivy.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/lint/linters/trivy.lua b/lua/lint/linters/trivy.lua index 4ddb5d9b..d0276d74 100644 --- a/lua/lint/linters/trivy.lua +++ b/lua/lint/linters/trivy.lua @@ -8,21 +8,22 @@ return { cmd = "trivy", stdin = false, append_fname = true, - args = { "--scanners", "config", "--format", "json" }, + args = { "--scanners", "config", "--format", "json", "fs" }, stream = "stdout", + ignore_exitcode = false, parser = function(output, bufnr) local diagnostics = {} local ok, decoded = pcall(vim.json.decode, output) if not ok then return diagnostics end - local fpath = vim.api.nvim_buf_get_name(bufnr) + local fpath = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":t") for _, result in ipairs(decoded and decoded.Results or {}) do if result.Target == fpath then for _, misconfig in ipairs(result.Misconfigurations) do local err = { source = "trivy", - message = string.format("%s - %s - %s", misconfig.Message, misconfig.Title, misconfig.Description), + message = string.format("%s - %s", misconfig.Message, misconfig.Title), col = misconfig.CauseMetadata.StartLine, end_col = misconfig.CauseMetadata.EndLine, lnum = misconfig.CauseMetadata.StartLine - 1, From 9bb3fe6ce867a0b9a59b7d9ac801bdced777e873 Mon Sep 17 00:00:00 2001 From: Peter Benjamin Date: Fri, 13 Oct 2023 15:21:50 -0700 Subject: [PATCH 3/3] fix(trivy): add test and update docs --- README.md | 2 + lua/lint/linters/trivy.lua | 2 +- tests/trivy_spec.lua | 101 +++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 tests/trivy_spec.lua diff --git a/README.md b/README.md index 9bdc72dd..3decb5ec 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Other dedicated linters that are built-in are: | [vulture][vulture] | `vulture` | | [yamllint][yamllint] | `yamllint` | | [tfsec][tfsec] | `tfsec` | +| [trivy][trivy] | `trivy` | ## Custom Linters @@ -387,6 +388,7 @@ busted tests/ [buf_lint]: https://github.com/bufbuild/buf [erb-lint]: https://github.com/shopify/erb-lint [tfsec]: https://github.com/aquasecurity/tfsec +[trivy]: https://github.com/aquasecurity/trivy [djlint]: https://djlint.com/ [buildifier]: https://github.com/bazelbuild/buildtools/tree/master/buildifier [solhint]: https://protofire.github.io/solhint/ diff --git a/lua/lint/linters/trivy.lua b/lua/lint/linters/trivy.lua index d0276d74..57be886c 100644 --- a/lua/lint/linters/trivy.lua +++ b/lua/lint/linters/trivy.lua @@ -23,7 +23,7 @@ return { for _, misconfig in ipairs(result.Misconfigurations) do local err = { source = "trivy", - message = string.format("%s - %s", misconfig.Message, misconfig.Title), + message = string.format("%s %s", misconfig.Title, misconfig.Description), col = misconfig.CauseMetadata.StartLine, end_col = misconfig.CauseMetadata.EndLine, lnum = misconfig.CauseMetadata.StartLine - 1, diff --git a/tests/trivy_spec.lua b/tests/trivy_spec.lua new file mode 100644 index 00000000..8b440bd6 --- /dev/null +++ b/tests/trivy_spec.lua @@ -0,0 +1,101 @@ +describe("linter.trivy", function() + it("Parses output sample", function() + local parser = require("lint.linters.trivy").parser + local bufnr = vim.uri_to_bufnr("file:///main.tf") + local output = [[ +{ + "SchemaVersion": 2, + "ArtifactName": "main.tf", + "ArtifactType": "filesystem", + "Metadata": { + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": ".", + "Class": "config", + "Type": "terraform", + "MisconfSummary": { + "Successes": 1, + "Failures": 0, + "Exceptions": 0 + } + }, + { + "Target": "main.tf", + "Class": "config", + "Type": "terraform", + "MisconfSummary": { + "Successes": 0, + "Failures": 1, + "Exceptions": 0 + }, + "Misconfigurations": [ + { + "Type": "Terraform Security Check", + "ID": "AVD-AWS-0065", + "AVDID": "AVD-AWS-0065", + "Title": "A KMS key is not configured to auto-rotate.", + "Description": "You should configure your KMS keys to auto rotate to maintain security and defend against compromise.", + "Message": "Key does not have rotation enabled.", + "Query": "data..", + "Resolution": "Configure KMS key to auto rotate", + "Severity": "MEDIUM", + "PrimaryURL": "https://avd.aquasec.com/misconfig/avd-aws-0065", + "References": [ + "https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html", + "https://avd.aquasec.com/misconfig/avd-aws-0065" + ], + "Status": "FAIL", + "Layer": {}, + "CauseMetadata": { + "Resource": "aws_kms_key.foo", + "Provider": "AWS", + "Service": "kms", + "StartLine": 15, + "EndLine": 15, + "Code": { + "Lines": [ + { + "Number": 15, + "Content": "resource \"aws_kms_key\" \"foo\" {}", + "IsCause": true, + "Annotation": "", + "Truncated": false, + "FirstCause": true, + "LastCause": true + } + ] + } + } + } + ] + } + ] +} + ]] + local result = parser(output, bufnr) + local expected = { + { + source = "trivy", + message = "A KMS key is not configured to auto-rotate. You should configure your KMS keys to auto rotate to maintain security and defend against compromise.", + lnum = 14, + end_lnum = 14, + col = 15, + end_col = 15, + severity = vim.diagnostic.severity.WARN, + code = "AVD-AWS-0065", + }, + } + assert.are.same(expected, result) + end) +end)