You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by sz...@apache.org on 2022/06/01 15:34:56 UTC

[nifi-minifi-cpp] branch main updated: MINIFICPP-1832 Integrate first batch of clang-tidy checks in CI

This is an automated email from the ASF dual-hosted git repository.

szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/main by this push:
     new 232d08d59 MINIFICPP-1832 Integrate first batch of clang-tidy checks in CI
232d08d59 is described below

commit 232d08d5959bc2cf2abf579ba77f2301af008225
Author: Gabor Gyimesi <ga...@gmail.com>
AuthorDate: Wed Jun 1 17:14:33 2022 +0200

    MINIFICPP-1832 Integrate first batch of clang-tidy checks in CI
    
    - Fix clang-static-analyzer issues
    - Fix issues of boost*,bugprone*,cert*,portability*
    - Integrate clang-tidy to CI
    - workaround libc++ duration operator<=>
    
    Closes #1330
    Signed-off-by: Marton Szasz <sz...@apache.org>
    Co-authored-by: Marton Szasz <sz...@apache.org>
---
 .clang-tidy                                        |  2 ++
 .github/workflows/ci.yml                           | 25 ++++++++++++++---
 cmake/Asio.cmake                                   |  2 +-
 cmake/BundledOpenCV.cmake                          |  4 ++-
 cmake/GoogleCloudCpp.cmake                         |  5 ++++
 extensions/aws/utils/AWSSdkLogger.cpp              |  4 +--
 extensions/gcp/CMakeLists.txt                      |  2 +-
 .../http-curl/tests/TimeoutHTTPSiteToSiteTests.cpp | 29 +++++++++++---------
 extensions/libarchive/FocusArchiveEntry.cpp        |  6 ++--
 extensions/opc/src/fetchopc.cpp                    |  4 +++
 extensions/opc/src/opc.cpp                         |  1 -
 .../SourceInitiatedSubscriptionListener.cpp        |  2 +-
 extensions/pcap/CMakeLists.txt                     |  4 +--
 extensions/procfs/SystemClockDuration.h            |  1 +
 extensions/sftp/processors/PutSFTP.cpp             |  8 ++----
 extensions/sql/processors/ExecuteSQL.cpp           |  2 +-
 extensions/sql/processors/QueryDatabaseTable.cpp   |  2 +-
 .../standard-processors/processors/ExtractText.cpp |  2 +-
 extensions/systemd/tests/ConsumeJournaldTest.cpp   |  5 ++--
 extensions/usb-camera/GetUSBCamera.cpp             |  2 +-
 libminifi/include/utils/TimeUtil.h                 | 32 ++++++++++++++--------
 libminifi/src/FlowControlProtocol.cpp              |  6 ++--
 .../src/controllers/NetworkPrioritizerService.cpp  |  2 +-
 libminifi/src/controllers/SSLContextService.cpp    |  2 +-
 .../AbstractCoreComponentStateManagerProvider.cpp  |  2 +-
 libminifi/src/core/FlowFile.cpp                    |  3 ++
 libminifi/src/core/ProcessSession.cpp              |  6 ++--
 libminifi/src/core/logging/LoggerConfiguration.cpp |  2 +-
 libminifi/src/io/tls/TLSSocket.cpp                 | 12 ++++----
 libminifi/src/sitetosite/SiteToSiteClient.cpp      |  2 +-
 libminifi/src/utils/Id.cpp                         |  2 +-
 libminifi/src/utils/SystemCpuUsageTracker.cpp      |  2 +-
 libminifi/src/utils/file/FileSystem.cpp            |  2 +-
 libminifi/src/utils/file/FileUtils.cpp             |  8 ++----
 libminifi/test/unit/BackTraceTests.cpp             |  4 +--
 libminifi/test/unit/ExtensionVerificationTests.cpp |  2 +-
 libminifi/test/unit/FilePatternTests.cpp           |  5 ++--
 libminifi/test/unit/SocketTests.cpp                |  2 +-
 libminifi/test/unit/ThreadPoolTests.cpp            |  4 +--
 run_clang_tidy.sh                                  | 15 ++++++++++
 thirdparty/google-styleguide/cpplint.py            | 22 +++++++++++++++
 .../include/rapidjson/document.h                   |  2 +-
 42 files changed, 161 insertions(+), 90 deletions(-)

diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 000000000..16e1a2ee6
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'boost*,bugprone*,cert*,portability*,-clang-analyzer-optin.cplusplus.VirtualCall,-bugprone-narrowing-conversions,-bugprone-implicit-widening-of-multiplication-result,-bugprone-macro-parentheses,-bugprone-easily-swappable-parameters,-bugprone-exception-escape,-cert-err58-cpp,-cert-err33-c'
+FormatStyle: 'file'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6b72d95fe..5345b156f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -146,22 +146,39 @@ jobs:
             ubuntu-20.04-all-clang-ccache-refs/heads/main-
       - id: install_deps
         run: |
+          wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
+          echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" | sudo tee -a /etc/apt/sources.list
+          echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" | sudo tee -a /etc/apt/sources.list
+          echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main" | sudo tee -a /etc/apt/sources.list
+          echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main" | sudo tee -a /etc/apt/sources.list
           sudo apt update
-          sudo apt install -y ccache libfl-dev libpcap-dev libboost-all-dev openjdk-8-jdk maven libusb-1.0-0-dev libpng-dev libgps-dev clang-12 libc++-12-dev libc++abi-12-dev
+          sudo apt install -y ccache libfl-dev libpcap-dev libboost-all-dev openjdk-8-jdk maven libusb-1.0-0-dev libpng-dev libgps-dev clang-14 clang-tidy-14 libc++-14-dev libc++abi-14-dev libsqliteodbc lua5.3 liblua5.3-dev
           echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
           echo -e "127.0.0.1\t$HOSTNAME" | sudo tee -a /etc/hosts > /dev/null
       - name: build
         run: |
           ./bootstrap.sh -e -t
           cd build
-          export CC=clang-12
-          export CXX=clang++-12
+          export CC=clang-14
+          export CXX=clang++-14
           export CXXFLAGS="${CXXFLAGS} -stdlib=libc++"
           export LDFLAGS="${LDFLAGS} -stdlib=libc++"
-          cmake -DUSE_SHARED_LIBS= -DCMAKE_BUILD_TYPE=Release -DENABLE_MQTT=ON -DENABLE_LIBRDKAFKA=ON -DENABLE_AWS=ON -DENABLE_AZURE=ON -DFAIL_ON_WARNINGS=ON ..
+          cmake -DUSE_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DSTRICT_GSL_CHECKS=AUDIT -DFAIL_ON_WARNINGS=ON -DENABLE_AWS=ON -DENABLE_AZURE=ON -DENABLE_BUSTACHE=ON -DENABLE_COAP=ON \
+              -DENABLE_ENCRYPT_CONFIG=ON -DENABLE_GPS=ON -DENABLE_JNI=ON -DENABLE_LIBRDKAFKA=ON -DENABLE_LINTER=ON -DENABLE_MQTT=ON -DENABLE_NANOFI=ON -DENABLE_OPC=ON -DENABLE_OPENCV=ON \
+              -DENABLE_OPENWSMAN=ON -DENABLE_OPS=ON -DENABLE_PCAP=ON -DENABLE_PYTHON=ON -DENABLE_SENSORS=ON -DENABLE_SFTP=ON -DENABLE_SQL=ON -DENABLE_SYSTEMD=ON -DENABLE_TENSORFLOW=OFF \
+              -DENABLE_USB_CAMERA=ON -DENABLE_SCRIPTING=ON -DENABLE_LUA_SCRIPTING=ON -DENABLE_KUBERNETES=ON -DENABLE_GCP=ON -DENABLE_PROCFS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
           cmake --build . --parallel $(nproc)
       - name: test
         run: cd build && make test ARGS="--timeout 300 -j8 --output-on-failure"
+      - id: files
+        uses: Ana06/get-changed-files@v2.1.0
+      - name: clang-tidy
+        run: |
+          # https://stackoverflow.com/questions/58466701/clang-tidy-cant-locate-stdlib-headers
+          sed -i -e 's/\/usr\/lib\/ccache\/clang++-14/\/lib\/llvm-14\/bin\/clang++/g' build/compile_commands.json
+          sed -i -e 's/\/usr\/lib\/ccache\/clang-14/\/lib\/llvm-14\/bin\/clang/g' build/compile_commands.json
+
+          ./run_clang_tidy.sh "${{ steps.files.outputs.all }}"
   centos:
     name: "centos"
     runs-on: ubuntu-20.04
diff --git a/cmake/Asio.cmake b/cmake/Asio.cmake
index fd5862eff..1953c765c 100644
--- a/cmake/Asio.cmake
+++ b/cmake/Asio.cmake
@@ -25,7 +25,7 @@ FetchContent_GetProperties(asio)
 if(NOT asio_POPULATED)
     FetchContent_Populate(asio)
     add_library(asio INTERFACE)
-    target_include_directories(asio INTERFACE ${asio_SOURCE_DIR}/asio/include)
+    target_include_directories(asio SYSTEM INTERFACE ${asio_SOURCE_DIR}/asio/include)
     find_package(Threads)
     target_link_libraries(asio INTERFACE Threads::Threads)
 endif()
diff --git a/cmake/BundledOpenCV.cmake b/cmake/BundledOpenCV.cmake
index b79fb98fc..4efa9d67b 100644
--- a/cmake/BundledOpenCV.cmake
+++ b/cmake/BundledOpenCV.cmake
@@ -97,7 +97,9 @@ function(use_bundled_opencv SOURCE_DIR BINARY_DIR)
             "-DWITH_OPENEXR=OFF"
             "-DWITH_WEBP=OFF"
             "-DWITH_OPENJPEG=OFF"
-            "-DWITH_TIFF=OFF")
+            "-DWITH_TIFF=OFF"
+            "-DCMAKE_CXX_STANDARD=17"  # OpenCV fails to build in C++20 mode on Clang-14
+    )
 
     append_third_party_passthrough_args(OPENCV_CMAKE_ARGS "${OPENCV_CMAKE_ARGS}")
 
diff --git a/cmake/GoogleCloudCpp.cmake b/cmake/GoogleCloudCpp.cmake
index 931264780..4aa57040b 100644
--- a/cmake/GoogleCloudCpp.cmake
+++ b/cmake/GoogleCloudCpp.cmake
@@ -42,9 +42,14 @@ set(PC ${Bash_EXECUTABLE}  -c "set -x &&\
 set(GOOGLE_CLOUD_CPP_ENABLE storage CACHE INTERNAL storage-api)
 set(GOOGLE_CLOUD_CPP_ENABLE_MACOS_OPENSSL_CHECK OFF CACHE INTERNAL macos-openssl-check)
 set(BUILD_TESTING OFF CACHE INTERNAL testing-off)
+set(GOOGLE_CLOUD_CPP_ENABLE_WERROR OFF CACHE INTERNAL warnings-off)
 FetchContent_Declare(google-cloud-cpp
         URL      https://github.com/googleapis/google-cloud-cpp/archive/refs/tags/v1.37.0.tar.gz
         URL_HASH SHA256=a7269b21d5e95bebff7833ebb602bcd5bcc79e82a59449cc5d5b350ff2f50bbc
         PATCH_COMMAND "${PC}")
 add_compile_definitions(_SILENCE_CXX20_REL_OPS_DEPRECATION_WARNING _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING CURL_STATICLIB)
 FetchContent_MakeAvailable(google-cloud-cpp)
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0" )
+    target_compile_options(google_cloud_cpp_common PUBLIC -Wno-error=deprecated-pragma)
+endif()
diff --git a/extensions/aws/utils/AWSSdkLogger.cpp b/extensions/aws/utils/AWSSdkLogger.cpp
index a9dabfef5..efba7a599 100644
--- a/extensions/aws/utils/AWSSdkLogger.cpp
+++ b/extensions/aws/utils/AWSSdkLogger.cpp
@@ -44,7 +44,7 @@ Aws::Utils::Logging::LogLevel AWSSdkLogger::GetLogLevel() const {
   return Aws::Utils::Logging::LogLevel::Off;
 }
 
-void AWSSdkLogger::Log(Aws::Utils::Logging::LogLevel log_level, const char* tag, const char* format_str, ...) {
+void AWSSdkLogger::Log(Aws::Utils::Logging::LogLevel log_level, const char* tag, const char* format_str, ...) {  // NOLINT(cert-dcl50-cpp)
   switch (log_level) {
     case Aws::Utils::Logging::LogLevel::Trace:
       logger_->log_trace("[%s] %s", tag, format_str);
@@ -59,8 +59,6 @@ void AWSSdkLogger::Log(Aws::Utils::Logging::LogLevel log_level, const char* tag,
       logger_->log_warn("[%s] %s", tag, format_str);
       break;
     case Aws::Utils::Logging::LogLevel::Error:
-      logger_->log_error("[%s] %s", tag, format_str);
-      break;
     case Aws::Utils::Logging::LogLevel::Fatal:
       logger_->log_error("[%s] %s", tag, format_str);
       break;
diff --git a/extensions/gcp/CMakeLists.txt b/extensions/gcp/CMakeLists.txt
index 871b2b9c2..9edc4df0c 100644
--- a/extensions/gcp/CMakeLists.txt
+++ b/extensions/gcp/CMakeLists.txt
@@ -28,7 +28,7 @@ file(GLOB SOURCES "*.cpp" "controllerservices/*.cpp" "processors/*.cpp")
 add_library(minifi-gcp SHARED ${SOURCES})
 
 target_link_libraries(minifi-gcp ${LIBMINIFI} google-cloud-cpp::storage)
-target_include_directories(minifi-gcp PUBLIC ${google-cloud-cpp_INCLUDE_DIRS})
+target_include_directories(minifi-gcp SYSTEM PUBLIC ${google-cloud-cpp_INCLUDE_DIRS})
 
 register_extension(minifi-gcp "GCP EXTENSIONS" GCP-EXTENSIONS "This enables Google Cloud Platform support" "extensions/gcp/tests")
 
diff --git a/extensions/http-curl/tests/TimeoutHTTPSiteToSiteTests.cpp b/extensions/http-curl/tests/TimeoutHTTPSiteToSiteTests.cpp
index 3161e8b54..727a6b5cd 100644
--- a/extensions/http-curl/tests/TimeoutHTTPSiteToSiteTests.cpp
+++ b/extensions/http-curl/tests/TimeoutHTTPSiteToSiteTests.cpp
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 #include <iostream>
+#include <memory>
 #include "sitetosite/HTTPProtocol.h"
 #include "InvokeHTTP.h"
 #include "TestBase.h"
@@ -78,13 +79,15 @@ class SiteToSiteTestHarness : public HTTPIntegrationBase {
 };
 
 struct defaulted_handler{
-  ServerAwareHandler* handler = nullptr;
+  std::unique_ptr<ServerAwareHandler> handler;
   ServerAwareHandler* get(ServerAwareHandler *def) const {
-    if (handler)return handler;
+    if (handler) {
+      return handler.get();
+    }
     return def;
   }
   void set(std::vector<std::chrono::milliseconds>&& timeout) {
-    handler = new TimeoutingHTTPHandler(std::move(timeout));
+    handler = std::make_unique<TimeoutingHTTPHandler>(std::move(timeout));
   }
 };
 
@@ -104,38 +107,38 @@ void run_timeout_variance(std::string test_file_location, bool isSecure, std::st
 
   std::string in_port = "471deef6-2a6e-4a7d-912a-81cc17e3a204";
 
-  TransactionResponder *transaction_response = new TransactionResponder(url, in_port, true);
+  auto transaction_response = std::make_unique<TransactionResponder>(url, in_port, true);
 
   std::string transaction_id = transaction_response->getTransactionId();
 
   harness.setKeyDir("");
 
   std::string baseUrl = url + "/site-to-site";
-  SiteToSiteBaseResponder *base = new SiteToSiteBaseResponder(baseUrl);
+  auto base = std::make_unique<SiteToSiteBaseResponder>(baseUrl);
 
-  harness.setUrl(baseUrl, profile.base_.get(base));
+  harness.setUrl(baseUrl, profile.base_.get(base.get()));
 
   std::string transaction_url = url + "/data-transfer/input-ports/" + in_port + "/transactions";
   std::string action_url = url + "/site-to-site/input-ports/" + in_port + "/transactions";
 
-  harness.setUrl(transaction_url, profile.transaction_.get(transaction_response));
+  harness.setUrl(transaction_url, profile.transaction_.get(transaction_response.get()));
 
   std::string peer_url = url + "/site-to-site/peers";
 
-  PeerResponder *peer_response = new PeerResponder(url);
+  auto peer_response = std::make_unique<PeerResponder>(url);
 
-  harness.setUrl(peer_url, profile.peer_.get(peer_response));
+  harness.setUrl(peer_url, profile.peer_.get(peer_response.get()));
 
   std::string flow_url = action_url + "/" + transaction_id + "/flow-files";
 
-  FlowFileResponder *flowResponder = new FlowFileResponder(true);
+  auto flowResponder = std::make_unique<FlowFileResponder>(true);
   flowResponder->setFlowUrl(flow_url);
 
-  harness.setUrl(flow_url, profile.flow_.get(flowResponder));
+  harness.setUrl(flow_url, profile.flow_.get(flowResponder.get()));
 
   std::string delete_url = transaction_url + "/" + transaction_id;
-  DeleteTransactionResponder *deleteResponse = new DeleteTransactionResponder(delete_url, "201 OK", 12);
-  harness.setUrl(delete_url, profile.delete_.get(deleteResponse));
+  auto deleteResponse = std::make_unique<DeleteTransactionResponder>(delete_url, "201 OK", 12);
+  harness.setUrl(delete_url, profile.delete_.get(deleteResponse.get()));
 
   harness.run(test_file_location);
 
diff --git a/extensions/libarchive/FocusArchiveEntry.cpp b/extensions/libarchive/FocusArchiveEntry.cpp
index b38378b9c..ad5c1b282 100644
--- a/extensions/libarchive/FocusArchiveEntry.cpp
+++ b/extensions/libarchive/FocusArchiveEntry.cpp
@@ -176,15 +176,13 @@ int64_t FocusArchiveEntry::ReadCallback::operator()(const std::shared_ptr<io::Ba
   archive_read_support_filter_all(inputArchive);
 
   // Read each item in the archive
-  int res;
-
-  if ((res = archive_read_open(inputArchive, &data, ok_cb, read_cb, ok_cb))) {
+  if (archive_read_open(inputArchive, &data, ok_cb, read_cb, ok_cb)) {
     logger_->log_error("FocusArchiveEntry can't open due to archive error: %s", archive_error_string(inputArchive));
     return nlen;
   }
 
   while (proc_->isRunning()) {
-    res = archive_read_next_header(inputArchive, &entry);
+    auto res = archive_read_next_header(inputArchive, &entry);
 
     if (res == ARCHIVE_EOF) {
       break;
diff --git a/extensions/opc/src/fetchopc.cpp b/extensions/opc/src/fetchopc.cpp
index 60295436e..5d183ac72 100644
--- a/extensions/opc/src/fetchopc.cpp
+++ b/extensions/opc/src/fetchopc.cpp
@@ -153,6 +153,10 @@ namespace processors {
       } else if (idType_ == opc::OPCNodeIDType::String) {
         myID.identifierType = UA_NODEIDTYPE_STRING;
         myID.identifier.string = UA_STRING_ALLOC(nodeID_.c_str());
+      } else {
+        logger_->log_error("Unhandled id type: '%d'. No flowfiles are generated.", idType_);
+        yield();
+        return;
       }
       connection_->traverse(myID, f, "", maxDepth_);
     } else {
diff --git a/extensions/opc/src/opc.cpp b/extensions/opc/src/opc.cpp
index 050246f24..8bd6dab1e 100644
--- a/extensions/opc/src/opc.cpp
+++ b/extensions/opc/src/opc.cpp
@@ -102,7 +102,6 @@ core::logging::LOG_LEVEL MapOPCLogLevel(UA_LogLevel ualvl) {
     case UA_LOGLEVEL_ERROR:
       return core::logging::err;
     case UA_LOGLEVEL_FATAL:
-      return core::logging::critical;
     default:
       return core::logging::critical;
   }
diff --git a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
index 6625f42e1..d133164a8 100644
--- a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
+++ b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
@@ -887,7 +887,7 @@ void SourceInitiatedSubscriptionListener::onSchedule(const std::shared_ptr<core:
 }
 
 void SourceInitiatedSubscriptionListener::notifyStop() {
-  server_.release();
+  server_.reset();
 }
 
 REGISTER_RESOURCE(SourceInitiatedSubscriptionListener, "This processor implements a Windows Event Forwarding Source Initiated Subscription server with the help of OpenWSMAN. "
diff --git a/extensions/pcap/CMakeLists.txt b/extensions/pcap/CMakeLists.txt
index c7e85d1bc..d3497da7d 100644
--- a/extensions/pcap/CMakeLists.txt
+++ b/extensions/pcap/CMakeLists.txt
@@ -26,8 +26,8 @@ find_package(PCAP REQUIRED)
 include(FetchContent)
 
 FetchContent_Declare(pcapplusplus
-		URL      https://github.com/seladb/PcapPlusPlus/archive/refs/tags/v21.05.tar.gz
-		URL_HASH SHA256=f7bc2caea72544f42e3547c8acf65fca07ddd4cd45f7be2f5132dd1826ea27bb
+		URL      https://github.com/seladb/PcapPlusPlus/archive/refs/tags/v22.05.tar.gz
+		URL_HASH SHA256=5f299c4503bf5d3c29f82b8d876a19be7dea29c2aadcb52f2f3b394846c21da9
 		)
 FetchContent_MakeAvailable(pcapplusplus)
 
diff --git a/extensions/procfs/SystemClockDuration.h b/extensions/procfs/SystemClockDuration.h
index f07d02859..a0272a104 100644
--- a/extensions/procfs/SystemClockDuration.h
+++ b/extensions/procfs/SystemClockDuration.h
@@ -19,6 +19,7 @@
 #include <asm-generic/param.h>
 #include <istream>
 #include <chrono>
+#include "utils/TimeUtil.h"  // for libc++ duration operator<=> workaround
 
 namespace org::apache::nifi::minifi::extensions::procfs {
 
diff --git a/extensions/sftp/processors/PutSFTP.cpp b/extensions/sftp/processors/PutSFTP.cpp
index d90687465..7351a618f 100644
--- a/extensions/sftp/processors/PutSFTP.cpp
+++ b/extensions/sftp/processors/PutSFTP.cpp
@@ -251,9 +251,8 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c
   if (remote_path.empty()) {
     remote_path = ".";
   }
-  if (context->getDynamicProperty(DisableDirectoryListing.getName(), value)) {
-    disable_directory_listing = utils::StringUtils::toBool(value).value_or(false);
-  } else if (context->getProperty(DisableDirectoryListing.getName(), value)) {
+  if (context->getDynamicProperty(DisableDirectoryListing.getName(), value) ||
+      context->getProperty(DisableDirectoryListing.getName(), value)) {
     disable_directory_listing = utils::StringUtils::toBool(value).value_or(false);
   }
   context->getProperty(TempFilename, temp_file_name, flow_file);
@@ -387,9 +386,6 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c
         context->yield();
         return false;
       case SFTPProcessorBase::CreateDirectoryHierarchyError::CREATE_DIRECTORY_HIERARCHY_ERROR_NOT_A_DIRECTORY:
-        session->transfer(flow_file, Failure);
-        put_connection_back_to_cache();
-        return true;
       case SFTPProcessorBase::CreateDirectoryHierarchyError::CREATE_DIRECTORY_HIERARCHY_ERROR_NOT_FOUND:
       case SFTPProcessorBase::CreateDirectoryHierarchyError::CREATE_DIRECTORY_HIERARCHY_ERROR_PERMISSION_DENIED:
         session->transfer(flow_file, Failure);
diff --git a/extensions/sql/processors/ExecuteSQL.cpp b/extensions/sql/processors/ExecuteSQL.cpp
index 2ef36580c..19416482b 100644
--- a/extensions/sql/processors/ExecuteSQL.cpp
+++ b/extensions/sql/processors/ExecuteSQL.cpp
@@ -72,7 +72,7 @@ void ExecuteSQL::processOnSchedule(core::ProcessContext& context) {
   context.getProperty(OutputFormat.getName(), output_format_);
 
   max_rows_ = [&] {
-    uint64_t max_rows;
+    uint64_t max_rows = 0;
     context.getProperty(MaxRowsPerFlowFile.getName(), max_rows);
     return gsl::narrow<size_t>(max_rows);
   }();
diff --git a/extensions/sql/processors/QueryDatabaseTable.cpp b/extensions/sql/processors/QueryDatabaseTable.cpp
index cf2c8a7c0..aecad99f9 100644
--- a/extensions/sql/processors/QueryDatabaseTable.cpp
+++ b/extensions/sql/processors/QueryDatabaseTable.cpp
@@ -109,7 +109,7 @@ void QueryDatabaseTable::initialize() {
 void QueryDatabaseTable::processOnSchedule(core::ProcessContext& context) {
   context.getProperty(OutputFormat.getName(), output_format_);
   max_rows_ = [&] {
-    uint64_t max_rows;
+    uint64_t max_rows = 0;
     context.getProperty(MaxRowsPerFlowFile.getName(), max_rows);
     return gsl::narrow<size_t>(max_rows);
   }();
diff --git a/extensions/standard-processors/processors/ExtractText.cpp b/extensions/standard-processors/processors/ExtractText.cpp
index 6febe23e3..26fe35909 100644
--- a/extensions/standard-processors/processors/ExtractText.cpp
+++ b/extensions/standard-processors/processors/ExtractText.cpp
@@ -162,7 +162,7 @@ int64_t ExtractText::ReadCallback::operator()(const std::shared_ptr<io::BaseStre
     ctx_->getProperty(EnableRepeatingCaptureGroup.getName(), repeatingcapture);
 
     const size_t maxCaptureSize = [this] {
-      uint64_t val;
+      uint64_t val = 0;
       ctx_->getProperty(MaxCaptureGroupLen.getName(), val);
       return gsl::narrow<size_t>(val);
     }();
diff --git a/extensions/systemd/tests/ConsumeJournaldTest.cpp b/extensions/systemd/tests/ConsumeJournaldTest.cpp
index 997e9809d..7f33d1c4c 100644
--- a/extensions/systemd/tests/ConsumeJournaldTest.cpp
+++ b/extensions/systemd/tests/ConsumeJournaldTest.cpp
@@ -39,8 +39,9 @@ namespace {
 namespace gsl = minifi::gsl;
 struct JournalEntry final {
   JournalEntry(const char* const identifier, const char* const message, const int pid = 0, std::vector<std::string> extra_fields = {}, const char* const hostname = "test-pc")
-    :fields{std::move(extra_fields)}
+    : fields{std::move(extra_fields)}
   {
+    auto extra_fields_size = fields.size();
     fields.reserve(fields.size() + 4);
     fields.push_back(utils::StringUtils::join_pack("MESSAGE=", message));
     fields.push_back(utils::StringUtils::join_pack("SYSLOG_IDENTIFIER=", identifier));
@@ -48,7 +49,7 @@ struct JournalEntry final {
       // The intention of the long expression below is a simple pseudo-random to test both branches equally
       // without having to pull in complex random logic
       const char* const pid_key =
-          (int{message[0]} + int{identifier[0]} + static_cast<int>(extra_fields.size()) + pid + int{hostname[0]}) % 2 == 0 ? "_PID" : "SYSLOG_PID";
+          (int{message[0]} + int{identifier[0]} + static_cast<int>(extra_fields_size) + pid + int{hostname[0]}) % 2 == 0 ? "_PID" : "SYSLOG_PID";
       fields.push_back(utils::StringUtils::join_pack(pid_key, "=", std::to_string(pid)));
     }
     fields.push_back(utils::StringUtils::join_pack("_HOSTNAME=", hostname));
diff --git a/extensions/usb-camera/GetUSBCamera.cpp b/extensions/usb-camera/GetUSBCamera.cpp
index 279037848..e40de7195 100644
--- a/extensions/usb-camera/GetUSBCamera.cpp
+++ b/extensions/usb-camera/GetUSBCamera.cpp
@@ -417,7 +417,7 @@ int64_t GetUSBCamera::PNGWriteCallback::operator()(const std::shared_ptr<io::Bas
     return 0;
   }
 
-  if (setjmp(png_jmpbuf(png))) {
+  if (setjmp(png_jmpbuf(png))) {  // NOLINT(cert-err52-cpp)
     logger_->log_error("Failed to set PNG jmpbuf");
     return 0;
   }
diff --git a/libminifi/include/utils/TimeUtil.h b/libminifi/include/utils/TimeUtil.h
index b7d723f82..68c7c8b7d 100644
--- a/libminifi/include/utils/TimeUtil.h
+++ b/libminifi/include/utils/TimeUtil.h
@@ -31,16 +31,29 @@
 #include <functional>
 #include <algorithm>
 
+// libc++ doesn't define operator<=> on durations, and apparently the operator rewrite rules don't automagically make one
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 14000
+#include <compare>
+#endif
+
 #include "date/date.h"
 
 #define TIME_FORMAT "%Y-%m-%d %H:%M:%S"
 
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace utils {
-namespace timeutils {
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 14000
+template<typename Rep1, typename Period1, typename Rep2, typename Period2>
+std::strong_ordering operator<=>(std::chrono::duration<Rep1, Period1> lhs, std::chrono::duration<Rep2, Period2> rhs) {
+  if (lhs < rhs) {
+    return std::strong_ordering::less;
+  } else if (lhs == rhs) {
+    return std::strong_ordering::equal;
+  } else {
+    return std::strong_ordering::greater;
+  }
+}
+#endif
+
+namespace org::apache::nifi::minifi::utils::timeutils {
 
 /**
  * Gets the current time in nanoseconds
@@ -295,12 +308,7 @@ std::optional<TargetDuration> StringToDuration(const std::string& input) {
     std::chrono::days>(unit, value);
 }
 
-} /* namespace timeutils */
-} /* namespace utils */
-} /* namespace minifi */
-} /* namespace nifi */
-} /* namespace apache */
-} /* namespace org */
+}  // namespace org::apache::nifi::minifi::utils::timeutils
 
 // for backwards compatibility, to be removed after 0.8
 using org::apache::nifi::minifi::utils::timeutils::getTimeNano;
diff --git a/libminifi/src/FlowControlProtocol.cpp b/libminifi/src/FlowControlProtocol.cpp
index 79334c276..84eda0288 100644
--- a/libminifi/src/FlowControlProtocol.cpp
+++ b/libminifi/src/FlowControlProtocol.cpp
@@ -115,7 +115,7 @@ int FlowControlProtocol::readHdr(FlowControlProtocolHeader *hdr) {
   data = this->decode(data, value);
   hdr->status = value;
 
-  data = this->decode(data, value);
+  this->decode(data, value);
   hdr->payloadLen = value;
 
   return sizeof(FlowControlProtocolHeader);
@@ -190,7 +190,7 @@ int FlowControlProtocol::sendRegisterReq() {
 
   // encode the YAML name
   data = this->encode(data, FLOW_YML_NAME);
-  data = this->encode(data, this->_controller->getName());
+  this->encode(data, this->_controller->getName());
 
   // send it
   int status = sendData(buffer.data(), gsl::narrow<int>(size));
@@ -284,7 +284,7 @@ int FlowControlProtocol::sendReportReq() {
 
   // encode the YAML name
   data = this->encode(data, FLOW_YML_NAME);
-  data = this->encode(data, this->_controller->getName());
+  this->encode(data, this->_controller->getName());
 
   // send it
   int status = sendData(buffer.data(), gsl::narrow<int>(size));
diff --git a/libminifi/src/controllers/NetworkPrioritizerService.cpp b/libminifi/src/controllers/NetworkPrioritizerService.cpp
index 882effa69..217a9a5c5 100644
--- a/libminifi/src/controllers/NetworkPrioritizerService.cpp
+++ b/libminifi/src/controllers/NetworkPrioritizerService.cpp
@@ -215,7 +215,7 @@ void NetworkPrioritizerService::onEnable() {
     if (getProperty(DefaultPrioritizer.getName(), is_default)) {
       if (is_default) {
         if (io::NetworkPrioritizerFactory::getInstance()->setPrioritizer(shared_from_this()) < 0) {
-          std::runtime_error("Can only have one prioritizer");
+          throw std::runtime_error("Can only have one prioritizer");
         }
       }
     }
diff --git a/libminifi/src/controllers/SSLContextService.cpp b/libminifi/src/controllers/SSLContextService.cpp
index 5cb74e68b..3dd2f8127 100644
--- a/libminifi/src/controllers/SSLContextService.cpp
+++ b/libminifi/src/controllers/SSLContextService.cpp
@@ -187,7 +187,7 @@ bool SSLContextService::addP12CertificateToSSLContext(SSL_CTX* ctx) const {
       if (SSL_CTX_add_extra_chain_cert(ctx, cacert.get()) != 1) {
         return utils::tls::get_last_ssl_error_code();
       }
-      cacert.release();  // a successful SSL_CTX_add_extra_chain_cert() takes ownership of cacert
+      static_cast<void>(cacert.release());  // a successful SSL_CTX_add_extra_chain_cert() takes ownership of cacert
       return {};
     },
     .priv_key_cb = [&] (auto priv_key) -> std::error_code {
diff --git a/libminifi/src/controllers/keyvalue/AbstractCoreComponentStateManagerProvider.cpp b/libminifi/src/controllers/keyvalue/AbstractCoreComponentStateManagerProvider.cpp
index 4160db9d7..b9e4df383 100644
--- a/libminifi/src/controllers/keyvalue/AbstractCoreComponentStateManagerProvider.cpp
+++ b/libminifi/src/controllers/keyvalue/AbstractCoreComponentStateManagerProvider.cpp
@@ -165,7 +165,7 @@ bool AbstractCoreComponentStateManagerProvider::AbstractCoreComponentStateManage
       success = false;
     }
   } else if (change_type_ == ChangeType::CLEAR) {
-    if (!state_valid_) {
+    if (!state_valid_) {  // NOLINT(bugprone-branch-clone)
       success = false;
     } else if (provider_->removeImpl(id_)) {
       state_valid_ = false;
diff --git a/libminifi/src/core/FlowFile.cpp b/libminifi/src/core/FlowFile.cpp
index ec7032678..05b626c1d 100644
--- a/libminifi/src/core/FlowFile.cpp
+++ b/libminifi/src/core/FlowFile.cpp
@@ -53,6 +53,9 @@ FlowFile::FlowFile()
 }
 
 FlowFile& FlowFile::operator=(const FlowFile& other) {
+  if (this == &other) {
+    return *this;
+  }
   uuid_ = other.uuid_;
   stored = other.stored;
   marked_delete_ = other.marked_delete_;
diff --git a/libminifi/src/core/ProcessSession.cpp b/libminifi/src/core/ProcessSession.cpp
index eabebf5d5..086cc3a18 100644
--- a/libminifi/src/core/ProcessSession.cpp
+++ b/libminifi/src/core/ProcessSession.cpp
@@ -233,10 +233,9 @@ void ProcessSession::transfer(const std::shared_ptr<core::FlowFile> &flow, Relat
 }
 
 void ProcessSession::write(const std::shared_ptr<core::FlowFile> &flow, const io::OutputStreamCallback& callback) {
-  auto flow_file_equality_checker = [&flow](const auto& flow_file) { return flow == flow_file; };
   gsl_ExpectsAudit(_updatedFlowFiles.contains(flow->getUUID())
       || _addedFlowFiles.contains(flow->getUUID())
-      || std::any_of(_clonedFlowFiles.begin(), _clonedFlowFiles.end(), flow_file_equality_checker));
+      || std::any_of(_clonedFlowFiles.begin(), _clonedFlowFiles.end(), [&flow](const auto& flow_file) { return flow == flow_file; }));
 
   std::shared_ptr<ResourceClaim> claim = content_session_->create();
 
@@ -279,10 +278,9 @@ void ProcessSession::writeBuffer(const std::shared_ptr<core::FlowFile>& flow_fil
 }
 
 void ProcessSession::append(const std::shared_ptr<core::FlowFile> &flow, const io::OutputStreamCallback& callback) {
-  auto flow_file_equality_checker = [&flow](const auto& flow_file) { return flow == flow_file; };
   gsl_ExpectsAudit(_updatedFlowFiles.contains(flow->getUUID())
       || _addedFlowFiles.contains(flow->getUUID())
-      || std::any_of(_clonedFlowFiles.begin(), _clonedFlowFiles.end(), flow_file_equality_checker));
+      || std::any_of(_clonedFlowFiles.begin(), _clonedFlowFiles.end(), [&flow](const auto& flow_file) { return flow == flow_file; }));
 
   std::shared_ptr<ResourceClaim> claim = flow->getResourceClaim();
   if (!claim) {
diff --git a/libminifi/src/core/logging/LoggerConfiguration.cpp b/libminifi/src/core/logging/LoggerConfiguration.cpp
index ae8e4c84b..8c1455606 100644
--- a/libminifi/src/core/logging/LoggerConfiguration.cpp
+++ b/libminifi/src/core/logging/LoggerConfiguration.cpp
@@ -296,7 +296,7 @@ spdlog::sink_ptr LoggerConfiguration::create_syslog_sink() {
 #ifdef WIN32
   return std::make_shared<internal::windowseventlog_sink>("ApacheNiFiMiNiFi");
 #else
-  return std::dynamic_pointer_cast<spdlog::sinks::sink>(spdlog::syslog_logger_mt("ApacheNiFiMiNiFi", 0, LOG_USER, false));
+  return std::dynamic_pointer_cast<spdlog::sinks::sink>(spdlog::syslog_logger_mt("ApacheNiFiMiNiFi", "", 0, LOG_USER, false));
 #endif
 }
 
diff --git a/libminifi/src/io/tls/TLSSocket.cpp b/libminifi/src/io/tls/TLSSocket.cpp
index bca51139d..fa4585197 100644
--- a/libminifi/src/io/tls/TLSSocket.cpp
+++ b/libminifi/src/io/tls/TLSSocket.cpp
@@ -179,12 +179,12 @@ TLSSocket::TLSSocket(const std::shared_ptr<TLSContext> &context, const std::stri
 TLSSocket::TLSSocket(TLSSocket &&other)
     : Socket(std::move(other)),
       context_{ std::exchange(other.context_, nullptr) } {
-  std::lock_guard<std::mutex> lg{ other.ssl_mutex_ };
+  std::lock_guard<std::mutex> lg{ other.ssl_mutex_ };  // NOLINT(bugprone-use-after-move)
 
-  connected_.exchange(other.connected_.load());
-  other.connected_.exchange(false);
-  ssl_ = std::exchange(other.ssl_, nullptr);
-  ssl_map_ = std::exchange(other.ssl_map_, {});
+  connected_.exchange(other.connected_.load());  // NOLINT(bugprone-use-after-move)
+  other.connected_.exchange(false);  // NOLINT(bugprone-use-after-move)
+  ssl_ = std::exchange(other.ssl_, nullptr);  // NOLINT(bugprone-use-after-move)
+  ssl_map_ = std::exchange(other.ssl_map_, {});  // NOLINT(bugprone-use-after-move)
 }
 
 TLSSocket& TLSSocket::operator=(TLSSocket&& other) {
@@ -228,7 +228,7 @@ int16_t TLSSocket::initialize(bool blocking) {
       ERR_print_errors_fp(stderr);
       int ssl_error = SSL_get_error(ssl_, rez);
       if (ssl_error == SSL_ERROR_WANT_WRITE) {
-        logger_->log_trace("want read");
+        logger_->log_trace("want write");
         return 0;
       } else if (ssl_error == SSL_ERROR_WANT_READ) {
         logger_->log_trace("want read");
diff --git a/libminifi/src/sitetosite/SiteToSiteClient.cpp b/libminifi/src/sitetosite/SiteToSiteClient.cpp
index fbe118ce4..5b169247d 100644
--- a/libminifi/src/sitetosite/SiteToSiteClient.cpp
+++ b/libminifi/src/sitetosite/SiteToSiteClient.cpp
@@ -281,7 +281,7 @@ bool SiteToSiteClient::confirm(const utils::Identifier& transactionID) {
           return true;
         } else {
           logger_->log_debug("Site2Site transaction %s CRC not matched %s", transactionID.to_string(), crc);
-          ret = writeResponse(transaction, BAD_CHECKSUM, "BAD_CHECKSUM");
+          writeResponse(transaction, BAD_CHECKSUM, "BAD_CHECKSUM");
           return false;
         }
       }
diff --git a/libminifi/src/utils/Id.cpp b/libminifi/src/utils/Id.cpp
index 9c5c5591f..abd8dd608 100644
--- a/libminifi/src/utils/Id.cpp
+++ b/libminifi/src/utils/Id.cpp
@@ -23,7 +23,7 @@
 
 #include "utils/Id.h"
 
-#define __STDC_FORMAT_MACROS 1
+#define __STDC_FORMAT_MACROS 1  // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
 #include <inttypes.h>
 #include <algorithm>
 #include <chrono>
diff --git a/libminifi/src/utils/SystemCpuUsageTracker.cpp b/libminifi/src/utils/SystemCpuUsageTracker.cpp
index 9ca534442..dac25fbc9 100644
--- a/libminifi/src/utils/SystemCpuUsageTracker.cpp
+++ b/libminifi/src/utils/SystemCpuUsageTracker.cpp
@@ -47,7 +47,7 @@ void SystemCpuUsageTracker::queryCpuTimes() {
   previous_total_sys_ = total_sys_;
   previous_total_idle_ = total_idle_;
   FILE* file = fopen("/proc/stat", "r");
-  if (fscanf(file, "cpu %lu %lu %lu %lu", &total_user_, &total_user_low_, &total_sys_, &total_idle_) != 4) {
+  if (fscanf(file, "cpu %lu %lu %lu %lu", &total_user_, &total_user_low_, &total_sys_, &total_idle_) != 4) {  // NOLINT(cert-err34-c)
     total_user_ = previous_total_user_;
     total_user_low_ = previous_total_user_low_;
     total_idle_ = previous_total_idle_;
diff --git a/libminifi/src/utils/file/FileSystem.cpp b/libminifi/src/utils/file/FileSystem.cpp
index acb6265a4..415e14774 100644
--- a/libminifi/src/utils/file/FileSystem.cpp
+++ b/libminifi/src/utils/file/FileSystem.cpp
@@ -30,7 +30,7 @@ namespace file {
 FileSystem::FileSystem(bool should_encrypt_on_write, std::optional<utils::crypto::EncryptionProvider> encryptor)
     : should_encrypt_on_write_(should_encrypt_on_write),
       encryptor_(std::move(encryptor)) {
-  if (should_encrypt_on_write_ && !encryptor) {
+  if (should_encrypt_on_write_ && !encryptor_) {
     std::string err_message = "Requested file encryption but no encryption utility was provided";
     logger_->log_error(err_message.c_str());
     throw std::invalid_argument(err_message);
diff --git a/libminifi/src/utils/file/FileUtils.cpp b/libminifi/src/utils/file/FileUtils.cpp
index d141da61c..7313843a3 100644
--- a/libminifi/src/utils/file/FileUtils.cpp
+++ b/libminifi/src/utils/file/FileUtils.cpp
@@ -72,9 +72,7 @@ bool contains(const std::filesystem::path& file_path, std::string_view text_to_s
 }
 
 time_t to_time_t(std::filesystem::file_time_type file_time) {
-#if defined(WIN32)
-  return std::chrono::system_clock::to_time_t(to_sys(file_time));
-#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 14000
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 14000
   return std::chrono::file_clock::to_time_t(file_time);
 #else
   return std::chrono::system_clock::to_time_t(to_sys(file_time));
@@ -82,9 +80,9 @@ time_t to_time_t(std::filesystem::file_time_type file_time) {
 }
 
 std::chrono::time_point<std::chrono::system_clock> to_sys(std::filesystem::file_time_type file_time) {
-#if defined(WIN32)
+#if defined(WIN32) || defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 14000
   return std::chrono::time_point_cast<std::chrono::system_clock::duration>(file_time - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
-#elif defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 14000
+#elif defined(_LIBCPP_VERSION)
   return std::chrono::system_clock::from_time_t(std::chrono::file_clock::to_time_t(file_time));
 #else
   return std::chrono::file_clock::to_sys(file_time);
diff --git a/libminifi/test/unit/BackTraceTests.cpp b/libminifi/test/unit/BackTraceTests.cpp
index e470206ac..48aecf977 100644
--- a/libminifi/test/unit/BackTraceTests.cpp
+++ b/libminifi/test/unit/BackTraceTests.cpp
@@ -93,7 +93,7 @@ TEST_CASE("BT2", "[TPT2]") {
     utils::Worker<int> functor(f_ex, "id", std::move(after_execute));
 
     std::future<int> fut;
-    pool.execute(std::move(functor), fut);
+    pool.execute(std::move(functor), fut);  // NOLINT(bugprone-use-after-move)
   }
 
   std::function<int()> f_ex = counterFunction;
@@ -101,7 +101,7 @@ TEST_CASE("BT2", "[TPT2]") {
   utils::Worker<int> functor(f_ex, "id", std::move(after_execute));
 
   std::future<int> fut;
-  pool.execute(std::move(functor), fut);
+  pool.execute(std::move(functor), fut);  // NOLINT(bugprone-use-after-move)
 
   std::vector<BackTrace> traces = pool.getTraces();
   for (const auto &trace : traces) {
diff --git a/libminifi/test/unit/ExtensionVerificationTests.cpp b/libminifi/test/unit/ExtensionVerificationTests.cpp
index f23369888..f05b71c3a 100644
--- a/libminifi/test/unit/ExtensionVerificationTests.cpp
+++ b/libminifi/test/unit/ExtensionVerificationTests.cpp
@@ -92,7 +92,7 @@ TEST_CASE_METHOD(Fixture, "Can't load extension if the file does not exist") {
 }
 
 TEST_CASE_METHOD(Fixture, "Can't load extension if the file has zero length") {
-  std::ofstream{extension_};
+  std::ofstream{extension_};  // NOLINT(bugprone-unused-raii)
 
   auto lib = minifi::core::extension::internal::asDynamicLibrary(extension_);
   REQUIRE(lib);
diff --git a/libminifi/test/unit/FilePatternTests.cpp b/libminifi/test/unit/FilePatternTests.cpp
index 52cc644e1..7ce45cb19 100644
--- a/libminifi/test/unit/FilePatternTests.cpp
+++ b/libminifi/test/unit/FilePatternTests.cpp
@@ -52,7 +52,8 @@ TEST_CASE("Invalid paths") {
   REQUIRE_THROWS(FilePatternSegment("!."));
   REQUIRE_THROWS(FilePatternSegment("!.."));
   // parent accessor after wildcard
-  FilePatternSegment("./../file.txt");  // sanity check
+  // sanity check
+  FilePatternSegment("./../file.txt");  // NOLINT(bugprone-unused-raii)
   REQUIRE_THROWS(FilePatternSegment("./*/../file.txt"));
 }
 
@@ -66,7 +67,7 @@ TEST_CASE("FilePattern reports error in correct subpattern") {
   };
   auto pattern = invalid_subpattern | ranges::views::keys | ranges::views::join(',') | ranges::to<std::string>;
   size_t idx = 0;
-  FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error) {
+  FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error) {  // NOLINT(bugprone-unused-raii)
     REQUIRE(invalid_subpattern[idx].first == subpattern);
     REQUIRE(invalid_subpattern[idx++].second == error);
   });
diff --git a/libminifi/test/unit/SocketTests.cpp b/libminifi/test/unit/SocketTests.cpp
index 6653d1313..5c23e236c 100644
--- a/libminifi/test/unit/SocketTests.cpp
+++ b/libminifi/test/unit/SocketTests.cpp
@@ -190,7 +190,7 @@ TEST_CASE("TestTLSContextCreation", "[TestSocket8]") {
     std::function<bool()> f_ex = createSocket;
     utils::Worker<bool> functor(f_ex, "id");
     std::future<bool> fut;
-    pool.execute(std::move(functor), fut);
+    pool.execute(std::move(functor), fut);  // NOLINT(bugprone-use-after-move)
     futures.push_back(std::move(fut));
   }
   pool.start();
diff --git a/libminifi/test/unit/ThreadPoolTests.cpp b/libminifi/test/unit/ThreadPoolTests.cpp
index c4e613cad..e3502b5b5 100644
--- a/libminifi/test/unit/ThreadPoolTests.cpp
+++ b/libminifi/test/unit/ThreadPoolTests.cpp
@@ -72,7 +72,7 @@ TEST_CASE("ThreadPoolTest1", "[TPT1]") {
   utils::Worker<bool> functor(f_ex, "id");
   pool.start();
   std::future<bool> fut;
-  pool.execute(std::move(functor), fut);
+  pool.execute(std::move(functor), fut);  // NOLINT(bugprone-use-after-move)
   fut.wait();
   REQUIRE(true == fut.get());
 }
@@ -91,7 +91,7 @@ TEST_CASE("ThreadPoolTest2", "[TPT2]") {
   utils::Worker<int> functor(f_ex, "id", std::move(after_execute));
   pool.start();
   std::future<int> fut;
-  pool.execute(std::move(functor), fut);
+  pool.execute(std::move(functor), fut);  // NOLINT(bugprone-use-after-move)
   fut.wait();
   REQUIRE(20 == fut.get());
 }
diff --git a/run_clang_tidy.sh b/run_clang_tidy.sh
new file mode 100755
index 000000000..1689032bf
--- /dev/null
+++ b/run_clang_tidy.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -uo pipefail
+
+exit_code=0
+FILES=$1
+
+for changed_file in ${FILES}; do
+  if [[ "${changed_file}" == *.cpp ]]; then
+    clang-tidy-14 -warnings-as-errors=* -quiet -p build "${changed_file}"
+    exit_code=$(( $? | exit_code ))
+  fi;
+done
+
+exit $exit_code
diff --git a/thirdparty/google-styleguide/cpplint.py b/thirdparty/google-styleguide/cpplint.py
index ac6eb0df5..0cf3390ce 100644
--- a/thirdparty/google-styleguide/cpplint.py
+++ b/thirdparty/google-styleguide/cpplint.py
@@ -361,6 +361,25 @@ _LEGACY_ERROR_CATEGORIES = [
     'readability/function',
     ]
 
+# https://github.com/cpplint/cpplint/pull/196
+# These prefixes for categories should be ignored since they relate to other
+# tools which also use the NOLINT syntax, e.g. clang-tidy.
+_OTHER_NOLINT_CATEGORY_PREFIXES = [
+    'boost-',
+    'bugprone-',
+    'cert-',
+    'clang-analyzer-',
+    'concurrency-'
+    'cppcoreguidelines-',
+    'google-',
+    'hicpp-',
+    'misc-',
+    'modernize-',
+    'performance-',
+    'portability-',
+    'readability-',
+    ]
+
 # The default state of the category filter. This is overridden by the --filter=
 # flag. By default all errors are on, so only add here categories that should be
 # off by default (i.e., categories that must be enabled by the --filter= flags).
@@ -763,6 +782,9 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
         category = category[1:-1]
         if category in _ERROR_CATEGORIES:
           _error_suppressions.setdefault(category, set()).add(suppressed_line)
+        elif any(c for c in _OTHER_NOLINT_CATEGORY_PREFIXES if category.startswith(c)):
+          # Ignore any categories from other tools.
+          pass
         elif category not in _LEGACY_ERROR_CATEGORIES:
           error(filename, linenum, 'readability/nolint', 5,
                 'Unknown NOLINT error category: %s' % category)
diff --git a/thirdparty/rapidjson-48fbd8cd202ca54031fe799db2ad44ffa8e77c13/include/rapidjson/document.h b/thirdparty/rapidjson-48fbd8cd202ca54031fe799db2ad44ffa8e77c13/include/rapidjson/document.h
index 599011706..a91b5d153 100644
--- a/thirdparty/rapidjson-48fbd8cd202ca54031fe799db2ad44ffa8e77c13/include/rapidjson/document.h
+++ b/thirdparty/rapidjson-48fbd8cd202ca54031fe799db2ad44ffa8e77c13/include/rapidjson/document.h
@@ -1236,7 +1236,7 @@ public:
 
             // Use static buffer and placement-new to prevent destruction
             static char buffer[sizeof(GenericValue)];
-            return *new (buffer) GenericValue();
+            return *new (buffer) GenericValue();  // NOLINT(clang-analyzer-cplusplus.PlacementNew)
         }
     }
     template <typename SourceAllocator>