diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1424127 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,243 @@ +--- +name: CI + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + workflow_dispatch: + +permissions: + contents: read + +jobs: + codeql: + name: CodeQL Security Analysis + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: cpp + queries: security-and-quality + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + cmake \ + ninja-build \ + libudev-dev \ + libsystemd-dev \ + pkg-config \ + gcc-14 \ + g++-14 + + - name: Build for CodeQL + run: | + mkdir -p build + cd build + cmake .. -GNinja \ + -DCMAKE_BUILD_TYPE=Release + ninja + env: + CC: gcc-14 + CXX: g++-14 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:cpp" + + clang-format: + name: Code Formatting Check + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install clang-format + run: | + sudo apt-get update + sudo apt-get install -y clang-format + + - name: Run clang-format check + run: | + # Find all C++ source files and check formatting + find src -type f \( -name "*.cpp" -o -name "*.cc" \ + -o -name "*.h" -o -name "*.hpp" \) -print0 | \ + xargs -0 clang-format --dry-run --Werror + shell: bash + + clang-tidy: + name: Static Analysis (clang-tidy) + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + clang-tidy \ + gcc-14 \ + g++-14 \ + cmake \ + ninja-build \ + libudev-dev \ + libsystemd-dev \ + pkg-config + + - name: Cache clang-tidy results + uses: actions/cache@v4 + with: + path: .clang-tidy-cache + key: >- + clang-tidy-${{ runner.os }}-${{ + hashFiles('**/*.cpp', '**/*.cc', '**/*.h', '**/*.hpp', + '.clang-tidy') }} + restore-keys: | + clang-tidy-${{ runner.os }}- + + - name: Configure CMake for clang-tidy + run: | + mkdir -p build + cd build + cmake .. -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + env: + CC: gcc-14 + CXX: g++-14 + + - name: Run clang-tidy + run: | + # Create cache directory if it doesn't exist + mkdir -p .clang-tidy-cache + + # Find all C++ source files and run clang-tidy + # Exclude third_party directory from analysis + find src -type f \( -name "*.cpp" -o -name "*.cc" \) | \ + while read file; do + echo "Analyzing $file..." + clang-tidy "$file" \ + -p build \ + --warnings-as-errors='*' \ + --header-filter='^(?!.*third_party).*$' \ + --system-headers=false || exit 1 + done + shell: bash + + build: + name: Build and Publish Artifacts + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + matrix: + compiler: + - {cc: gcc-14, cxx: g++-14, name: gcc-14, stdlib: libstdc++} + - {cc: clang-19, cxx: clang++-19, name: llvm-19, stdlib: libc++} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + cmake \ + ninja-build \ + libudev-dev \ + libsystemd-dev \ + pkg-config + + - name: Install compiler toolchain + run: | + if [ "${{ matrix.compiler.name }}" = "gcc-14" ]; then + sudo apt-get install -y gcc-14 g++-14 + elif [ "${{ matrix.compiler.name }}" = "llvm-19" ]; then + # Install LLVM 19 with libc++ + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | \ + sudo tee /etc/apt/trusted.gpg.d/llvm.asc + sudo add-apt-repository -y \ + 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' + sudo apt-get update + sudo apt-get install -y \ + clang-19 \ + llvm-19 \ + llvm-19-dev \ + lld-19 \ + libc++-19-dev \ + libc++abi-19-dev + fi + + - name: Configure CMake + run: | + mkdir -p build + cd build + # Configure with C++23 support + if [ "${{ matrix.compiler.stdlib }}" = "libc++" ]; then + # For LLVM with libc++ + cmake .. -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_LTO=ON \ + -DCMAKE_CXX_FLAGS="-stdlib=libc++" \ + -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++ -lc++abi" \ + -DLLVM_CONFIG=/usr/bin/llvm-config-19 + else + # For GCC with libstdc++ + cmake .. -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_LTO=ON + fi + env: + CC: ${{ matrix.compiler.cc }} + CXX: ${{ matrix.compiler.cxx }} + + - name: Build + run: | + cd build + ninja -v + + - name: Collect executables + run: | + mkdir -p artifacts + # Find all executables in src directories + # (exclude CMake test artifacts and temporary files) + find build/src -type f -executable \ + -not -path "*/CMakeFiles/*" \ + -not -name "*.so*" \ + -not -name "*.a" \ + -exec cp {} artifacts/ \; + + # List what we collected + echo "Collected artifacts:" + ls -lh artifacts/ + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.compiler.name }} + path: artifacts/* + if-no-files-found: error + retention-days: 30 diff --git a/src/proxy/org/freedesktop/ModemManager1/ModemManager1_proxy.h b/src/proxy/org/freedesktop/ModemManager1/ModemManager1_proxy.h index 96b4ca2..d0f2857 100644 --- a/src/proxy/org/freedesktop/ModemManager1/ModemManager1_proxy.h +++ b/src/proxy/org/freedesktop/ModemManager1/ModemManager1_proxy.h @@ -13,59 +13,58 @@ namespace org { namespace freedesktop { -class ModemManager1_proxy -{ -public: - static constexpr const char* INTERFACE_NAME = "org.freedesktop.ModemManager1"; - -protected: - ModemManager1_proxy(sdbus::IProxy& proxy) - : m_proxy(proxy) - { - } - - ModemManager1_proxy(const ModemManager1_proxy&) = delete; - ModemManager1_proxy& operator=(const ModemManager1_proxy&) = delete; - ModemManager1_proxy(ModemManager1_proxy&&) = delete; - ModemManager1_proxy& operator=(ModemManager1_proxy&&) = delete; - - ~ModemManager1_proxy() = default; - - void registerProxy() - { - } - -public: - void ScanDevices() - { - m_proxy.callMethod("ScanDevices").onInterface(INTERFACE_NAME); - } - - void SetLogging(const std::string& level) - { - m_proxy.callMethod("SetLogging").onInterface(INTERFACE_NAME).withArguments(level); - } - - void ReportKernelEvent(const std::map& properties) - { - m_proxy.callMethod("ReportKernelEvent").onInterface(INTERFACE_NAME).withArguments(properties); - } - - void InhibitDevice(const std::string& uid, const bool& inhibit) - { - m_proxy.callMethod("InhibitDevice").onInterface(INTERFACE_NAME).withArguments(uid, inhibit); - } - -public: - std::string Version() - { - return m_proxy.getProperty("Version").onInterface(INTERFACE_NAME).get(); - } - -private: - sdbus::IProxy& m_proxy; +class ModemManager1_proxy { + public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.ModemManager1"; + + protected: + ModemManager1_proxy(sdbus::IProxy& proxy) : m_proxy(proxy) {} + + ModemManager1_proxy(const ModemManager1_proxy&) = delete; + ModemManager1_proxy& operator=(const ModemManager1_proxy&) = delete; + ModemManager1_proxy(ModemManager1_proxy&&) = delete; + ModemManager1_proxy& operator=(ModemManager1_proxy&&) = delete; + + ~ModemManager1_proxy() = default; + + void registerProxy() {} + + public: + void ScanDevices() { + m_proxy.callMethod("ScanDevices").onInterface(INTERFACE_NAME); + } + + void SetLogging(const std::string& level) { + m_proxy.callMethod("SetLogging") + .onInterface(INTERFACE_NAME) + .withArguments(level); + } + + void ReportKernelEvent( + const std::map& properties) { + m_proxy.callMethod("ReportKernelEvent") + .onInterface(INTERFACE_NAME) + .withArguments(properties); + } + + void InhibitDevice(const std::string& uid, const bool& inhibit) { + m_proxy.callMethod("InhibitDevice") + .onInterface(INTERFACE_NAME) + .withArguments(uid, inhibit); + } + + public: + std::string Version() { + return m_proxy.getProperty("Version") + .onInterface(INTERFACE_NAME) + .get(); + } + + private: + sdbus::IProxy& m_proxy; }; -}} // namespaces +} // namespace freedesktop +} // namespace org #endif diff --git a/src/utils/utils.cc b/src/utils/utils.cc index 04cf3da..c523e8e 100644 --- a/src/utils/utils.cc +++ b/src/utils/utils.cc @@ -476,10 +476,9 @@ std::string Utils::scalarToString(const glz::generic& val) { double d = val.get(); // Check if the number is an integer to preserve precision // Only convert to int64 if it's within a safe range - constexpr double kMaxSafeInt64 = 9007199254740992.0; // 2^53 - constexpr double kMinSafeInt64 = -9007199254740992.0; // -2^53 - if (d >= kMinSafeInt64 && d <= kMaxSafeInt64 && - d == std::floor(d)) { + constexpr double kMaxSafeInt64 = 9007199254740992.0; // 2^53 + constexpr double kMinSafeInt64 = -9007199254740992.0; // -2^53 + if (d >= kMinSafeInt64 && d <= kMaxSafeInt64 && d == std::floor(d)) { return std::to_string(static_cast(d)); } return std::to_string(d); @@ -490,8 +489,7 @@ std::string Utils::scalarToString(const glz::generic& val) { } // NOLINTNEXTLINE(clang-tidy) -std::string Utils::elementToLines(const glz::generic& el, - const int indent) { +std::string Utils::elementToLines(const glz::generic& el, const int indent) { std::string out; const std::string pad(indent * 2, ' '); @@ -532,12 +530,12 @@ std::string Utils::parseDescriptionJson(const std::string& json) { if (json.empty()) { return ""; } - + glz::generic doc; auto ec = glz::read_json(doc, json); if (ec) { return std::string("json_error: ") + glz::format_error(ec, json); } - + return elementToLines(doc, 0); } diff --git a/src/utils/utils.h b/src/utils/utils.h index 36049f2..32cb831 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -48,8 +48,7 @@ class Utils { static std::string scalarToString(const glz::generic& val); - static std::string elementToLines(const glz::generic& el, - int indent = 0); + static std::string elementToLines(const glz::generic& el, int indent = 0); static std::string parseDescriptionJson(const std::string& json); diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 86ec9de..a5e357d 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -15,12 +15,13 @@ install(TARGETS toolchain EXPORT sdbus-c++-targets) # # spdlog # -add_subdirectory(spdlog) -set(SPDLOG_INSTALL OFF CACHE BOOL "Do not install spdlog" FORCE) -if (ENABLE_LTO AND IPO_SUPPORT_RESULT) - set_property(TARGET spdlog PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) -endif () -target_link_libraries(spdlog PUBLIC toolchain::toolchain) +set(SPDLOG_NO_EXCEPTIONS ON) +set(SPDLOG_NO_THREAD_ID ON) +set(SPDLOG_BUILD_PIC ON) +set(SPDLOG_SANITIZE_ADDRESS ${SANITIZE_ADDRESS}) +add_library(spdlog INTERFACE) +add_library(spdlog::spdlog ALIAS spdlog) +target_compile_options(spdlog INTERFACE -isystem${CMAKE_CURRENT_SOURCE_DIR}/spdlog/include) # # glaze