branch: elpa/flymake-collection commit 1b62fd9b5844b231cb48b4919064420d64a123ff Author: Abdelhak Bougouffa <abougou...@cryptolab.net> Commit: GitHub <nore...@github.com>
Additional checkers (#38) * checkers: add `codespell` checker * checkers: add the `bandit` checker for Python * checkers: add `nasm` checker for Assembly code * checkers: add `pyre` checker for Python * checkers: add `clang-tidy` static checker for C/C++ * test: fix tests for NASM * checkers: fix `clang-tidy` --- src/checkers/flymake-collection-bandit.el | 51 +++++++++++++++ src/checkers/flymake-collection-clang-tidy.el | 92 +++++++++++++++++++++++++++ src/checkers/flymake-collection-codespell.el | 50 +++++++++++++++ src/checkers/flymake-collection-nasm.el | 58 +++++++++++++++++ src/checkers/flymake-collection-pyre.el | 50 +++++++++++++++ src/flymake-collection-hook.el | 22 +++++-- tests/checkers/installers/bandit.bash | 1 + tests/checkers/installers/clang-tidy.bash | 1 + tests/checkers/installers/codespell.bash | 1 + tests/checkers/installers/nasm.bash | 1 + tests/checkers/installers/pyre.bash | 1 + tests/checkers/test-cases/bandit.yml | 33 ++++++++++ tests/checkers/test-cases/codespell.yml | 18 ++++++ tests/checkers/test-cases/nasm.yml | 28 ++++++++ 14 files changed, 403 insertions(+), 4 deletions(-) diff --git a/src/checkers/flymake-collection-bandit.el b/src/checkers/flymake-collection-bandit.el new file mode 100644 index 0000000000..61f73a55e4 --- /dev/null +++ b/src/checkers/flymake-collection-bandit.el @@ -0,0 +1,51 @@ +;;; flymake-collection-bandit.el --- bandit diagnostic function -*- lexical-binding: t -*- + +;; Copyright (c) 2024 Abdelhak Bougouffa + +;; Permission is hereby granted, free of charge, to any person obtaining a copy +;; of this software and associated documentation files (the "Software"), to deal +;; in the Software without restriction, including without limitation the rights +;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +;; copies of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in all +;; copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +;;; Commentary: + +;; `flymake' checker for common security issues in Python code using "bandit". + +;;; Code: + +(require 'flymake) +(require 'flymake-collection) + +(eval-when-compile + (require 'flymake-collection-define)) + +;;;###autoload (autoload 'flymake-collection-bandit "flymake-collection-bandit") +(flymake-collection-define-rx flymake-collection-bandit + "Find common security issues in Python code." + :title "bandit" + :pre-let ((bandit-exec (executable-find "bandit"))) + :pre-check (unless bandit-exec (error "Cannot find bandit executable")) + :write-type 'file + :command (list bandit-exec "--format" "custom" "--msg-template" "diag:{line}:{severity}:{test_id}: {msg}" flymake-collection-temp-file) + :regexps + ((error bol "diag:" line ":" "HIGH" ":" (id (* alnum)) ":" (message) eol) + (warning bol "diag:" line ":" "MEDIUM" ":" (id (* alnum)) ":" (message) eol) + (note bol "diag:" line ":" (or "LOW" "UNDEFINED") ":" (id (* alnum)) ":" (message) eol))) + + +(provide 'flymake-collection-bandit) + +;;; flymake-collection-bandit.el ends here diff --git a/src/checkers/flymake-collection-clang-tidy.el b/src/checkers/flymake-collection-clang-tidy.el new file mode 100644 index 0000000000..a072309769 --- /dev/null +++ b/src/checkers/flymake-collection-clang-tidy.el @@ -0,0 +1,92 @@ +;;; flymake-collection-clang-tidy.el --- Clang-tidy diagnostic function -*- lexical-binding: t -*- + +;; Copyright (c) 2024 Abdelhak Bougouffa + +;; Permission is hereby granted, free of charge, to any person obtaining a copy +;; of this software and associated documentation files (the "Software"), to deal +;; in the Software without restriction, including without limitation the rights +;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +;; copies of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in all +;; copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +;;; Commentary: + +;; `flymake' static checker for C/C++ using "clang-tidy". +;; Inspired by `flycheck-clang-tidy' - https://github.com/ch1bo/flycheck-clang-tidy + +;;; Code: + +(require 'flymake) +(require 'flymake-collection) + +(eval-when-compile + (require 'flymake-collection-define)) + +;;; Custom variables + +(defcustom flymake-collection-clang-tidy-build-path "build" + "Clang build directory." + :type '(choice (const nil) directory) + :group 'flymake-collection) + +(defcustom flymake-collection-clang-tidy-extra-options nil + "Extra options to pass to Clang-tidy." + :type '(choice (const nil) (repeat string)) + :group 'flymake-collection) + +;;; Helpers + +(defun flymake-collection-clang-tidy-find-project-root (_checker) + "Find the project root for CHECKER. +This uses `project', `projectile', `vc' or the \".clang-tidy\" file" + (or + (when (and (bound-and-true-p projectile-mode) (fboundp 'projectile-project-root)) + (projectile-project-root)) + (and (project-current) (project-root (project-current))) + (vc-root-dir) + (locate-dominating-file (or buffer-file-name default-directory) ".clang-tidy") + (progn + (message "Could not determine project root, trying current directory.") + (file-name-directory buffer-file-name)))) + +(defun flymake-collection-clang-tidy-get-config () + "Find and read .clang-tidy." + (when-let ((config-dir (locate-dominating-file (or buffer-file-name default-directory) ".clang-tidy")) + (config-file (expand-file-name ".clang-tidy" config-dir))) + (with-temp-buffer + (insert-file-contents config-file) + (buffer-string)))) + +;;;###autoload (autoload 'flymake-collection-clang-tidy "flymake-collection-clang-tidy") +(flymake-collection-define-rx flymake-collection-clang-tidy + "Clang-based C++ linter tool." + :pre-let ((clang-tidy-exec (executable-find "clang-tidy"))) + :pre-check (unless clang-tidy-exec (error "Cannot find clang-tidy executable")) + :write-type 'file + :command (append + (list clang-tidy-exec) + (when flymake-collection-clang-tidy-build-path (list "-p" flymake-collection-clang-tidy-build-path)) + (when buffer-file-name (list (concat "-extra-arg=-I" (file-name-directory buffer-file-name)))) + (when (flymake-collection-clang-tidy-get-config) (list (concat "-config=" (flymake-collection-clang-tidy-get-config)))) + (ensure-list flymake-collection-clang-tidy-extra-options) + (list flymake-collection-temp-file)) + :regexps + ((error bol (file-name) ":" line ":" column ": error:" (message) eol) + (warning bol (file-name) ":" line ":" column ": warning:" (message) eol) + (note bol (file-name) ":" line ":" column ": note:" (message) eol))) + + +(provide 'flymake-collection-clang-tidy) + +;;; flymake-collection-clang-tidy.el ends here diff --git a/src/checkers/flymake-collection-codespell.el b/src/checkers/flymake-collection-codespell.el new file mode 100644 index 0000000000..1df1439cb4 --- /dev/null +++ b/src/checkers/flymake-collection-codespell.el @@ -0,0 +1,50 @@ +;;; flymake-collection-codespell.el --- codespell diagnostic function -*- lexical-binding: t -*- + +;; Copyright (c) 2024 Abdelhak Bougouffa + +;; Permission is hereby granted, free of charge, to any person obtaining a copy +;; of this software and associated documentation files (the "Software"), to deal +;; in the Software without restriction, including without limitation the rights +;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +;; copies of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in all +;; copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +;;; Commentary: + +;; `flymake' checker for common misspellings in code using "codespell". + +;;; Code: + +(require 'flymake) +(require 'flymake-collection) + +(eval-when-compile + (require 'flymake-collection-define)) + + +;;;###autoload (autoload 'flymake-collection-codespell "flymake-collection-codespell") +(flymake-collection-define-rx flymake-collection-codespell + "Check code for common misspellings." + :title "codespell" + :pre-let ((codespell-exec (executable-find "codespell"))) + :pre-check (unless codespell-exec (error "Cannot find codespell executable")) + :write-type 'file + :command (list codespell-exec "-d" "-i0" flymake-collection-temp-file) + :regexps + ((warning bol (file-name) ":" line ": " (message) eol))) + + +(provide 'flymake-collection-codespell) + +;;; flymake-collection-codespell.el ends here diff --git a/src/checkers/flymake-collection-nasm.el b/src/checkers/flymake-collection-nasm.el new file mode 100644 index 0000000000..d080bc6025 --- /dev/null +++ b/src/checkers/flymake-collection-nasm.el @@ -0,0 +1,58 @@ +;;; flymake-collection-nasm.el --- NASM diagnostic function -*- lexical-binding: t -*- + +;; Copyright (c) 2024 Abdelhak Bougouffa + +;; Permission is hereby granted, free of charge, to any person obtaining a copy +;; of this software and associated documentation files (the "Software"), to deal +;; in the Software without restriction, including without limitation the rights +;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +;; copies of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in all +;; copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +;;; Commentary: + +;; `flymake' checker for Assembly using "nasm". +;; Inspired by `flymake-nasm' - https://github.com/juergenhoetzel/flymake-nasm + +;;; Code: + +(require 'flymake) +(require 'flymake-collection) + +(eval-when-compile + (require 'flymake-collection-define)) + +(defcustom flymake-collection-nasm-format 'elf64 + "The NASM output format. +You can list the supported formats by running \"nasm -hf\"q." + :type 'symbol + :group 'flymake-collection) + +;;;###autoload (autoload 'flymake-collection-nasm "flymake-collection-nasm") +(flymake-collection-define-rx flymake-collection-nasm + "Assembly checker using the Netwide Assembler (NASM)." + :title "nasm" + :pre-let ((nasm-exec (executable-find "nasm"))) + :pre-check (unless nasm-exec (error "Not found nasm on PATH")) + :write-type 'file + :command `(,nasm-exec ,(format "-f%s" flymake-collection-nasm-format) ,flymake-collection-temp-file) + :regexps + ((error bol (file-name) ":" line ": error: " (message) eol) + (warning bol (file-name) ":" line ": warning: " (message) eol) + (note bol (file-name) ":" line ": note: " (message) eol))) + + +(provide 'flymake-collection-nasm) + +;;; flymake-collection-nasm.el ends here diff --git a/src/checkers/flymake-collection-pyre.el b/src/checkers/flymake-collection-pyre.el new file mode 100644 index 0000000000..7dc102da33 --- /dev/null +++ b/src/checkers/flymake-collection-pyre.el @@ -0,0 +1,50 @@ +;;; flymake-collection-pyre.el --- pyre diagnostic function -*- lexical-binding: t -*- + +;; Copyright (c) 2024 Abdelhak Bougouffa + +;; Permission is hereby granted, free of charge, to any person obtaining a copy +;; of this software and associated documentation files (the "Software"), to deal +;; in the Software without restriction, including without limitation the rights +;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +;; copies of the Software, and to permit persons to whom the Software is +;; furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in all +;; copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. + +;;; Commentary: + +;; `flymake' type-checker for Python 3 using "pyre". + +;;; Code: + +(require 'flymake) +(require 'flymake-collection) + +(eval-when-compile + (require 'flymake-collection-define)) + + +;;;###autoload (autoload 'flymake-collection-pyre "flymake-collection-pyre") +(flymake-collection-define-rx flymake-collection-pyre + "Performant type-checking for python." + :title "pyre" + :pre-let ((pyre-exec (executable-find "pyre"))) + :pre-check (unless pyre-exec (error "Cannot find pyre in PATH")) + :write-type 'file + :command `(,pyre-exec) + :regexps + ((warning bol (file-name) ":" line ":" column " " (message) eol))) + + +(provide 'flymake-collection-pyre) + +;;; flymake-collection-pyre.el ends here diff --git a/src/flymake-collection-hook.el b/src/flymake-collection-hook.el index 475876bdb7..4390c6a227 100644 --- a/src/flymake-collection-hook.el +++ b/src/flymake-collection-hook.el @@ -39,29 +39,40 @@ ;;;###autoload (defcustom flymake-collection-hook-config - '((elisp-mode . + '((emacs-lisp-mode . (elisp-flymake-byte-compile - elisp-flymake-checkdoc)) + elisp-flymake-checkdoc + (flymake-collection-codespell :disabled t))) ((python-mode python-ts-mode) . (flymake-collection-pycodestyle (python-flymake :disabled t) (flymake-mypy :disabled t) + (flymake-collection-bandit :disabled t) + (flymake-collection-codespell :disabled t) + (flymake-collection-pyre :disabled t) (flymake-collection-pylint :disabled t) (flymake-collection-flake8 :disabled t) (flymake-collection-ruff :disabled t))) (awk-mode . (flymake-collection-awk-gawk)) + ((asm-mode nasm-mode) . (flymake-collection-nasm)) ((c-mode c-ts-mode) . (flymake-collection-clang + (flymake-collection-codespell :disabled t) + (flymake-collection-clang-tidy :disabled t) (flymake-collection-gcc :disabled t))) ((c++-mode c++-ts-mode) . (flymake-collection-clang + (flymake-collection-codespell :disabled t) + (flymake-collection-clang-tidy :disabled t) (flymake-collection-gcc :disabled t))) (haskell-mode . (flymake-collection-hlint)) ((janet-mode janet-ts-mode) . (flymake-collection-janet)) ((js-mode js2-mode typescript-mode typescript-ts-mode) . - (flymake-collection-eslint)) + (flymake-collection-eslint + (flymake-collection-codespell :disabled t))) ((json-mode json-ts-mode) . (flymake-collection-jq + (flymake-collection-codespell :disabled t) (flymake-collection-jsonlint :disabled t))) (less-mode flymake-collection-less) (markdown-mode @@ -77,13 +88,16 @@ flymake-collection-sql-lint (flymake-collection-sqlint :disabled t)) ((ruby-mode ruby-ts-mode) . - (flymake-collection-rubocop)) + (flymake-collection-rubocop + (flymake-collection-codespell :disabled t))) ;; (hledger-mode flymake-collection-hledger) ((sh-mode bash-ts-mode) . (flymake-collection-shellcheck + (flymake-collection-codespell :disabled t) (sh-shellcheck-flymake :disabled t))) ((yaml-mode yaml-ts-mode) . (flymake-collection-yamllint + (flymake-collection-codespell :disabled t) (flymake-collection-kube-linter :disabled t))) ((web-mode html-ts-mode) . (flymake-collection-html-tidy)) diff --git a/tests/checkers/installers/bandit.bash b/tests/checkers/installers/bandit.bash new file mode 100755 index 0000000000..80b303c3ec --- /dev/null +++ b/tests/checkers/installers/bandit.bash @@ -0,0 +1 @@ +python3 -m pip install bandit diff --git a/tests/checkers/installers/clang-tidy.bash b/tests/checkers/installers/clang-tidy.bash new file mode 100755 index 0000000000..a567fcf3bc --- /dev/null +++ b/tests/checkers/installers/clang-tidy.bash @@ -0,0 +1 @@ +apt-get install -y clang-tidy diff --git a/tests/checkers/installers/codespell.bash b/tests/checkers/installers/codespell.bash new file mode 100755 index 0000000000..cd9c11f422 --- /dev/null +++ b/tests/checkers/installers/codespell.bash @@ -0,0 +1 @@ +python3 -m pip install codespell diff --git a/tests/checkers/installers/nasm.bash b/tests/checkers/installers/nasm.bash new file mode 100755 index 0000000000..de458422c9 --- /dev/null +++ b/tests/checkers/installers/nasm.bash @@ -0,0 +1 @@ +apt-get install -y nasm diff --git a/tests/checkers/installers/pyre.bash b/tests/checkers/installers/pyre.bash new file mode 100755 index 0000000000..9f97de0c9f --- /dev/null +++ b/tests/checkers/installers/pyre.bash @@ -0,0 +1 @@ +python3 -m pip install pyre-check diff --git a/tests/checkers/test-cases/bandit.yml b/tests/checkers/test-cases/bandit.yml new file mode 100644 index 0000000000..9e703d79fe --- /dev/null +++ b/tests/checkers/test-cases/bandit.yml @@ -0,0 +1,33 @@ +--- +checker: flymake-collection-bandit +tests: + - name: no-lints + file: | + """A test case with no output from bandit.""" + + print("hello world") + lints: [] + - name: hardcoded-password + file: | + """A test case with an output from bandit""" + + class SomeClass: + password = "class_password" + + lints: + - point: [4, 4] + level: note + message: "B105 Possible hardcoded password: 'class_password' (bandit)" + - name: ciphers + file: | + """A test case with an output from codespell""" + + from cryptography.hazmat.primitives.ciphers.modes import ECB + + # Insecure mode + mode = ECB(iv) + + lints: + - point: [6, 0] + level: warning + message: "B305 Use of insecure cipher mode cryptography.hazmat.primitives.ciphers.modes.ECB. (bandit)" diff --git a/tests/checkers/test-cases/codespell.yml b/tests/checkers/test-cases/codespell.yml new file mode 100644 index 0000000000..2004caf3ab --- /dev/null +++ b/tests/checkers/test-cases/codespell.yml @@ -0,0 +1,18 @@ +--- +checker: flymake-collection-codespell +tests: + - name: no-lints + file: | + """A test case with no output from codespell.""" + + print("hello world") + lints: [] + - name: misspelling + file: | + """A test case with an output from codespell""" + + vairable = "Hello" + lints: + - point: [3, 0] + level: warning + message: vairable ==> variable (codespell) diff --git a/tests/checkers/test-cases/nasm.yml b/tests/checkers/test-cases/nasm.yml new file mode 100644 index 0000000000..8d017e429d --- /dev/null +++ b/tests/checkers/test-cases/nasm.yml @@ -0,0 +1,28 @@ +--- +checker: flymake-collection-nasm +tests: + - name: no-lints + file: | + _start: + mov rax, 1 + mov rdi, 1 + lints: [] + - name: errors + file: | + _start: + mov rax, 1 + mov rdi, 1 + mov rsi, message + mov rdx, 14 + + syscall + mov raxx, 60 + xor rdi, rdi + syscall + lints: + - point: [4, 4] + level: error + message: "symbol `message' undefined (nasm)" # TODO: "undefined" becomes "not defined" in newer NASM version + - point: [8, 4] + level: error + message: "symbol `raxx' undefined (nasm)" # TODO: "undefined" becomes "not defined" in newer NASM version