diff --git a/.github/workflows/test_clang_scan_build.yml b/.github/workflows/test_clang_scan_build.yml
new file mode 100644
index 00000000000000..80a10449a041e0
--- /dev/null
+++ b/.github/workflows/test_clang_scan_build.yml
@@ -0,0 +1,196 @@
+name: test clang-scan-build
+
+on:
+  push:
+    paths-ignore:
+      # remove non SITL HAL
+      - 'libraries/AP_HAL_ChibiOS/**'
+      - 'libraries/AP_HAL_ESP32/**'
+      - 'libraries/AP_HAL_Linux/**'
+      - 'libraries/AP_HAL_QURT/**'
+      # remove non SITL directories
+      - 'Tools/AP_Bootloader/**'
+      - 'Tools/AP_Periph/**'
+      - 'Tools/bootloaders/**'
+      - 'Tools/CHDK-Script/**'
+      - 'Tools/CodeStyle/**'
+      - 'Tools/completion/**'
+      - 'Tools/CPUInfo/**'
+      - 'Tools/debug/**'
+      - 'Tools/environment_install/**'
+      - 'Tools/FilterTestTool/**'
+      - 'Tools/Frame_params/**'
+      - 'Tools/geotag/**'
+      - 'Tools/GIT_Test/**'
+      - 'Tools/gittools/**'
+      - 'Tools/Hello/**'
+      - 'Tools/IO_Firmware/**'
+      - 'Tools/Linux_HAL_Essentials/**'
+      - 'Tools/Pozyx/**'
+      - 'Tools/PrintVersion.py'
+      - 'Tools/Replay/**'
+      - 'Tools/simulink/**'
+      - 'Tools/UDP_Proxy/**'
+      - 'Tools/vagrant/**'
+      - 'Tools/Vicon/**'
+      # Discard python file from Tools/scripts as not used
+      - 'Tools/scripts/build_sizes/**'
+      - 'Tools/scripts/build_tests/**'
+      - 'Tools/scripts/CAN/**'
+      - 'Tools/scripts/signing/**'
+      # Remove  autotest
+      - 'Tools/autotest/antennatracker.py'
+      - 'Tools/autotest/arducopter.py'
+      - 'Tools/autotest/arduplane.py'
+      - 'Tools/autotest/ardusub.py'
+      - 'Tools/autotest/helicopter.py'
+      - 'Tools/autotest/rover.py'
+      - 'Tools/autotest/location.txt'
+      - 'Tools/autotest/quadplane.py'
+      - 'Tools/autotest/swarminit.txt'
+      # Remove markdown files as irrelevant
+      - '**.md'
+      # Remove dotfile at root directory
+      - './.dir-locals.el'
+      - './.dockerignore'
+      - './.editorconfig'
+      - './.flake8'
+      - './.gitattributes'
+      - './.github'
+      - './.gitignore'
+      - './.pre-commit-config.yaml'
+      - './.pydevproject'
+      - './.valgrind-suppressions'
+      - './.valgrindrc'
+      - 'Dockerfile'
+      - 'Vagrantfile'
+      - 'Makefile'
+      # Remove some directories check
+      - '.vscode/**'
+      - '.github/ISSUE_TEMPLATE/**'
+      # Remove change on other workflows
+      - '.github/workflows/test_environment.yml'
+
+
+  pull_request:
+    paths-ignore:
+      # remove non SITL HAL
+      - 'libraries/AP_HAL_QURT/**'
+      - 'libraries/AP_HAL_Linux/**'
+      - 'libraries/AP_HAL_ChibiOS/**'
+      - 'libraries/AP_HAL_ESP32/**'
+      # remove non SITL directories
+      - 'Tools/AP_Bootloader/**'
+      - 'Tools/AP_Periph/**'
+      - 'Tools/bootloaders/**'
+      - 'Tools/CHDK-Script/**'
+      - 'Tools/CodeStyle/**'
+      - 'Tools/completion/**'
+      - 'Tools/CPUInfo/**'
+      - 'Tools/debug/**'
+      - 'Tools/environment_install/**'
+      - 'Tools/FilterTestTool/**'
+      - 'Tools/Frame_params/**'
+      - 'Tools/geotag/**'
+      - 'Tools/GIT_Test/**'
+      - 'Tools/gittools/**'
+      - 'Tools/Hello/**'
+      - 'Tools/IO_Firmware/**'
+      - 'Tools/Linux_HAL_Essentials/**'
+      - 'Tools/LogAnalyzer/**'
+      - 'Tools/Pozyx/**'
+      - 'Tools/PrintVersion.py'
+      - 'Tools/Replay/**'
+      - 'Tools/simulink/**'
+      - 'Tools/UDP_Proxy/**'
+      - 'Tools/vagrant/**'
+      - 'Tools/Vicon/**'
+      # Discard python file from Tools/scripts as not used
+      - 'Tools/scripts/build_sizes/**'
+      - 'Tools/scripts/build_tests/**'
+      - 'Tools/scripts/CAN/**'
+      - 'Tools/scripts/signing/**'
+      # Remove other vehicles autotest
+      - 'Tools/autotest/antennatracker.py'
+      - 'Tools/autotest/arducopter.py'
+      - 'Tools/autotest/arduplane.py'
+      - 'Tools/autotest/ardusub.py'
+      - 'Tools/autotest/helicopter.py'
+      - 'Tools/autotest/location.txt'
+      - 'Tools/autotest/quadplane.py'
+      - 'Tools/autotest/rover.py'
+      - 'Tools/autotest/swarminit.txt'
+      # Remove markdown files as irrelevant
+      - '**.md'
+      # Remove dotfile at root directory
+      - './.dir-locals.el'
+      - './.dockerignore'
+      - './.editorconfig'
+      - './.flake8'
+      - './.gitattributes'
+      - './.github'
+      - './.gitignore'
+      - './.pre-commit-config.yaml'
+      - './.pydevproject'
+      - './.valgrind-suppressions'
+      - './.valgrindrc'
+      - 'Dockerfile'
+      - 'Vagrantfile'
+      - 'Makefile'
+      # Remove some directories check
+      - '.vscode/**'
+      - '.github/ISSUE_TEMPLATE/**'
+      # Remove change on other workflows
+      - '.github/workflows/test_environment.yml'
+
+  workflow_dispatch:
+
+concurrency:
+  group: ci-${{github.workflow}}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  build:
+    runs-on: ubuntu-22.04
+    container: ardupilot/ardupilot-dev-${{ matrix.toolchain }}:v0.1.3
+    steps:
+      # git checkout the PR
+      - uses: actions/checkout@v4
+        with:
+          submodules: 'recursive'
+      # Put ccache into github cache for faster build
+      - name: Prepare ccache timestamp
+        id: ccache_cache_timestamp
+        run: |
+          NOW=$(date -u +"%F-%T")
+          echo "timestamp=${NOW}" >> $GITHUB_OUTPUT
+      - name: ccache cache files
+        uses: actions/cache@v4
+        with:
+          path: ~/.ccache
+          key: ${{github.workflow}}-ccache-clang-scan-build-${{steps.ccache_cache_timestamp.outputs.timestamp}}
+          restore-keys: ${{github.workflow}}-ccache-clang-scan-build-  # restore ccache from either previous build on this branch or on master
+      - name: setup ccache
+        run: |
+          . .github/workflows/ccache.env
+      - name: run clang-scan-build
+        shell: bash
+        run: |
+          git config --global --add safe.directory ${GITHUB_WORKSPACE}
+          PATH="/github/home/.local/bin:$PATH"
+          ./Tools/autotest/autotest.py clang-scan-build >/tmp/scan-build-stdout.txt
+          
+          ccache -s
+          ccache -z
+
+          # this renames the scan-build output directory to a fixed
+          #          name so we can archive it
+          ./Tools/autotest/process_scan_build_output.py /tmp/scan-build-stdout.txt
+
+      - name: Archive artifacts
+        uses: actions/upload-artifact@v4
+        with:
+           name: clang-scan-build
+           path: /__w/ardupilot/ardupilot/tmp/scan-build
+           retention-days: 7
+
diff --git a/Tools/autotest/process_scan_build_output.py b/Tools/autotest/process_scan_build_output.py
new file mode 100755
index 00000000000000..6b3dcf352a9805
--- /dev/null
+++ b/Tools/autotest/process_scan_build_output.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+
+'''
+Tool to process stdout from clang_scan_build, and manipulate files for archiving
+
+AP_FLAKE8_CLEAN
+'''
+
+import os
+import pathlib
+import re
+import sys
+
+
+class ProcessScanBuildOutput():
+    def __init__(self, stdout_filepath):
+        self.stdout_filepath = stdout_filepath
+
+    def progress(self, msg):
+        print(f"pscbo: {msg}")
+
+    def run(self):
+        t = pathlib.Path(self.stdout_filepath).read_text()
+        m_scan_build_dir = None
+        m_bug_count = None
+        for line in t.split("\n"):
+            # extract scan-build-dir
+            m = re.match(r".*Run 'scan-view ([^ ]+)", line)
+            if m is not None:
+                m_scan_build_dir = m
+            # extract count of bugs
+            m = re.match(r".*?(\d+) bugs found", line)
+            if m is not None:
+                m_bug_count = m
+        if m_scan_build_dir is None:
+            raise ValueError("Did not find scan-build output directory in output")
+        if m_bug_count is None:
+            raise ValueError("Did not find bug count in output")
+        scan_build_dir = m_scan_build_dir.group(1)
+        bug_count = int(m_bug_count.group(1))
+
+        dest = "/__w/ardupilot/ardupilot/scan-build"
+        self.progress(f"Renaming {scan_build_dir} to {dest}")
+        os.rename(scan_build_dir, dest)
+
+        new_stdout_filepath = os.path.join(dest, self.stdout_filepath)
+        self.progress(f"Renaming {self.stdout_filepath} to {new_stdout_filepath}")
+        os.rename(self.stdout_filepath, new_stdout_filepath)
+
+        self.progress(f"Extracted Bug count is {bug_count}")
+
+        if bug_count != self.expected_bug_count:
+            self.progress(f"Bug count incorrect (want={self.expected_bug_count()} got={bug_count})")
+            if bug_count < self.expected_bug_count():
+                self.progress("You have fixed bugs, please modify Tools/autotest/process_scan_build_output.py to reduce expected count")  # noqa: E501
+            else:
+                self.progress("clang-scan-build has found problems being introduced; see artifacts")
+            sys.exit(1)
+
+    def expected_bug_count(self):
+        return 87
+
+
+if __name__ == '__main__':
+    import argparse
+    parser = argparse.ArgumentParser(description='tool to post-process output from clang-scan-build in CI')
+    parser.add_argument('clang_scan_build_stdout', default=None, help='file containing stdout from clang-scan-build process')
+
+    args = parser.parse_args()
+
+    p = ProcessScanBuildOutput(args.clang_scan_build_stdout)
+    p.run()