diff --git a/.bazelrc b/.bazelrc index dbb041679..dbc004077 100644 --- a/.bazelrc +++ b/.bazelrc @@ -128,6 +128,9 @@ build:clang_tidy --@score_bazel_tools_cc//quality:quality_clang_tidy_config=//:c build:clang_tidy --aspects=@score_bazel_tools_cc//quality:defs.bzl%quality_clang_tidy_aspect build:clang_tidy --build_tag_filters="-tidy_suite" build:clang_tidy --force_pic + +# CodeQL static analysis evaluation (eclipse-score/baselibs#317) +import %workspace%/score/quality/static_analysis/static_analysis.bazelrc build:clang_tidy --incompatible_enable_cc_toolchain_resolution build:clang_tidy --output_groups=clang_tidy_output build:clang_tidy --verbose_failures diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..95eedcd68 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,70 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# CodeQL MISRA C++ static analysis evaluation for baselibs (eclipse-score/baselibs#317). +name: CodeQL static analysis (evaluation) +permissions: + contents: read + actions: write + security-events: write +on: + pull_request: + types: [opened, reopened, synchronize] +jobs: + codeql: + runs-on: ubuntu-24.04 + env: + CODEQL_TARGET_SCOPE: //score/bitmanipulation/... + steps: + - uses: eclipse-score/more-disk-space@6a3b48901846bf7f8cc985925157d71a8973e61f # v1 + with: + level: 3 + - name: Checkout Repository + uses: actions/checkout@v6 + - name: Allow linux-sandbox + uses: eclipse-score/cicd-actions/unblock-user-namespace-for-linux-sandbox@f89865691445b60e9229c36adb1c37b675e1ca85 + - name: Setup Bazel Cache + uses: eclipse-score/cicd-actions/setup-bazel-cache@659dcbed63f6b7fbde88c7850125ea0a0a92f939 + with: + unique-cache-name: ${{ github.workflow }}-${{ github.job }} + - name: Resolve production (non-test) targets + id: resolve-targets + run: | + # Exclude cc_test targets (and testonly helpers/mocks) so CodeQL only + # analyzes production code, not test/GTest framework noise + # (eclipse-score/baselibs#317 finding: GTest's TEST() macro alone + # triggers dozens of unrelated MISRA findings per test file). + bazel query "${CODEQL_TARGET_SCOPE} except kind(cc_test, ${CODEQL_TARGET_SCOPE}) except attr(testonly, 1, ${CODEQL_TARGET_SCOPE})" \ + --output=label > /tmp/codeql-targets.txt + echo "Resolved $(wc -l < /tmp/codeql-targets.txt) production target(s):" + cat /tmp/codeql-targets.txt + - name: Run CodeQL analysis + id: run-codeql + run: | + bazel run //score/quality/static_analysis:codeql_lint -- \ + --output-dir /tmp/codeql-results \ + --output-prefix codeql-baselibs \ + --target $(cat /tmp/codeql-targets.txt) + #- name: Upload SARIF to GitHub Code Scanning + # if: always() && steps.run-codeql.outcome == 'success' + # uses: github/codeql-action/upload-sarif@v4 + # with: + # sarif_file: /tmp/codeql-results/codeql-baselibs.sarif + # category: codeql-baselibs + - name: Upload CSV results + if: always() && steps.run-codeql.outcome == 'success' + uses: actions/upload-artifact@v4 + with: + name: codeql-csv-results + path: /tmp/codeql-results/codeql-baselibs.csv + retention-days: 30 diff --git a/MODULE.bazel b/MODULE.bazel index d748465fe..2671396db 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -171,6 +171,35 @@ register_toolchains( dev_dependency = True, ) +## Configure CodeQL static analysis (evaluation, see eclipse-score/baselibs#317) +## Ported from eclipse-score/communication's quality/static_analysis approach. + +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) +pip.parse( + hub_name = "codeql_coding_standards_pip_hub", + python_version = PYTHON_VERSION, + requirements_lock = "//third_party/codeql:requirements_lock.txt", +) +use_repo(pip, "codeql_coding_standards_pip_hub") + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "codeql_bundle", + build_file = "//third_party/codeql:codeql.BUILD", + sha256 = "a94f674bb3c23ea5e9a2ad06b64847dd0277b15014d2517ecd9c41c88e6caa65", + url = "https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.21.4/codeql-bundle-linux64.tar.gz", +) + +git_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "codeql_coding_standards", + build_file = "//third_party/codeql:codeql_coding_standards.BUILD", + commit = "06dc6bc32b05152fbe94dbf341a3e854574c9df5", # v2.61.0 + remote = "https://github.com/github/codeql-coding-standards.git", +) + deb = use_repo_rule("@download_utils//download/deb:defs.bzl", "download_deb") deb( diff --git a/coding-standards.yaml b/coding-standards.yaml new file mode 100644 index 000000000..df86a18d2 --- /dev/null +++ b/coding-standards.yaml @@ -0,0 +1,16 @@ +deviations: + - rule-id: "RULE-18-5-2" + query-id: "cpp/misra/avoid-program-terminating-functions" + justification: "Evaluation of the CodeQL coding-standards justification mechanism for + baselibs (eclipse-score/baselibs#317). This deviation mirrors the one already + accepted in eclipse-score/communication and is scoped to the score/ tree only." + paths: + - "score" + - rule-id: "RULE-21-6-1" + query-id: "cpp/misra/dynamic-memory-should-not-be-used" + justification: "Evaluation of the CodeQL coding-standards path-scoped justification + mechanism for baselibs (eclipse-score/baselibs#317). score/language/futurecpp + intentionally manages dynamic memory as part of its allocator/memory_resource + implementation; scoped narrowly to that component to demonstrate suppression." + paths: + - "score/language/futurecpp" diff --git a/score/bitmanipulation/bit_manipulation.h b/score/bitmanipulation/bit_manipulation.h index 6716969b9..fda771a04 100644 --- a/score/bitmanipulation/bit_manipulation.h +++ b/score/bitmanipulation/bit_manipulation.h @@ -29,7 +29,7 @@ class HalfByte { public: /// \brief Construct a HalfByte from a uint8, only the last 4 bits are considered - constexpr explicit HalfByte(const std::uint8_t value) : repr{static_cast(value & mask)} {} + constexpr explicit HalfByte(const std::uint8_t value) : repr1{static_cast(value & mask)} {} // NOLINTBEGIN(google-explicit-constructor): No potentially dangerous type conversion // AUTOSAR Rule A13-5-2 prohibits implicit user defined conversion operators to avoid potential errors in type // conversion. But we do not convert underlying type (repr_ is std::uint8_t and return type is std::uint8_t). @@ -37,12 +37,12 @@ class HalfByte // coverity[autosar_cpp14_a13_5_2_violation] constexpr operator std::uint8_t() const { - return repr; + return repr1; } // NOLINTEND(google-explicit-constructor): see above for detailed explanation private: static constexpr std::uint8_t mask{0b0000'1111U}; - std::uint8_t repr; + std::uint8_t repr1; }; // Change to std::byte in C++17 diff --git a/score/bitmanipulation/bit_manipulation_test.cpp b/score/bitmanipulation/bit_manipulation_test.cpp index 1e49ae458..ee139c795 100644 --- a/score/bitmanipulation/bit_manipulation_test.cpp +++ b/score/bitmanipulation/bit_manipulation_test.cpp @@ -28,9 +28,9 @@ using ::testing::Eq; TEST(HalfByte, CanBeConstructedFromUInt8) { - constexpr HalfByte value{std::uint8_t{4u}}; + constexpr HalfByte value1{std::uint8_t{4u}}; - EXPECT_THAT(value, Eq(4u)); + EXPECT_THAT(value1, Eq(4u)); } TEST(HalfByte, CanBeConstructedFromUInt16IfInRange) @@ -49,16 +49,16 @@ TEST(HalfByte, CanBeConstructedFromBigUInt8ButUpperHalfIsDropped) TEST(Byte, CanBeConstructedFromUInt8) { - constexpr Byte value{std::uint8_t{4u}}; + constexpr Byte value1{std::uint8_t{4u}}; - EXPECT_THAT(value, Eq(4u)); + EXPECT_THAT(value1, Eq(4u)); } TEST(Byte, CanBeConstructedFromUInt16IfInRange) { - constexpr Byte value{std::uint16_t{4u}}; + constexpr Byte value1{std::uint16_t{4u}}; - EXPECT_THAT(value, Eq(4u)); + EXPECT_THAT(value1, Eq(4u)); } TEST(Byte, CanBeConstructedFromTwoHalfBytes) diff --git a/score/bitmanipulation/bitmask_operators.h b/score/bitmanipulation/bitmask_operators.h index cd662bad8..2a9cbb0fb 100644 --- a/score/bitmanipulation/bitmask_operators.h +++ b/score/bitmanipulation/bitmask_operators.h @@ -117,12 +117,12 @@ constexpr typename std::enable_if::value && score::enable_bitmas // coverity[autosar_cpp14_m7_3_1_violation] operator&(const T & lhs, const T & rhs) { - using U = std::underlying_type_t; + using U1 = std::underlying_type_t; // Suppress "AUTOSAR C++14 A4-7-1" rule finding. This rule states: "An integer expression shall not lead to data // loss." In this context, there is no data loss because lhs/rhs is promoted to std::uint64_t for the bitwise // operation. The result is then checked for non-zero, ensuring the integrity of the original data. // coverity[autosar_cpp14_a4_7_1_violation] - return (static_cast(static_cast(lhs)) & static_cast(static_cast(rhs))) != 0U; + return (static_cast(static_cast(lhs)) & static_cast(static_cast(rhs))) != 0U; } /// @brief Provides the bitwise XOR operator for scoped enums. diff --git a/score/bitmanipulation/bitmask_operators_test.cpp b/score/bitmanipulation/bitmask_operators_test.cpp index a9e96a6a9..8a732f00e 100644 --- a/score/bitmanipulation/bitmask_operators_test.cpp +++ b/score/bitmanipulation/bitmask_operators_test.cpp @@ -69,10 +69,10 @@ TEST(MyBitmask, SupportsOperatorAnd) TEST(MyBitmask, SupportsOperatorXor) { - MyBitmask bitmask{MyBitmask::a ^ MyBitmask::b}; - EXPECT_EQ(static_cast(bitmask), 3); - bitmask = bitmask ^ MyBitmask::b; - EXPECT_EQ(static_cast(bitmask), 1); + MyBitmask abc{MyBitmask::a ^ MyBitmask::b}; + EXPECT_EQ(static_cast(abc), 3); + abc = abc ^ MyBitmask::b; + EXPECT_EQ(static_cast(abc), 1); } TEST(MyBitmask, SupportsOperatorNot) diff --git a/score/quality/static_analysis/BUILD b/score/quality/static_analysis/BUILD new file mode 100644 index 000000000..feda6ff1b --- /dev/null +++ b/score/quality/static_analysis/BUILD @@ -0,0 +1,37 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +py_binary( + name = "codeql_lint", + srcs = ["codeql_lint.py"], + args = [ + "--codeql_path=$(location @codeql_bundle//:codeql_cli)", + "--config_path=$(location :config)", + "--analysis_report_path=$(location @codeql_coding_standards//:analysis_report)", + ], + data = [ + ":config", + "@codeql_bundle//:codeql_cli", + "@codeql_coding_standards//:analysis_report", + "@codeql_coding_standards//:process_coding_standards_config", + ], + main = "codeql_lint.py", + tags = ["local", "manual"], + target_compatible_with = ["@platforms//os:linux"], +) + +filegroup( + name = "config", + srcs = ["config.yaml"], + visibility = ["//visibility:public"], +) diff --git a/score/quality/static_analysis/codeql_lint.py b/score/quality/static_analysis/codeql_lint.py new file mode 100644 index 000000000..cc77e0865 --- /dev/null +++ b/score/quality/static_analysis/codeql_lint.py @@ -0,0 +1,247 @@ +#******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +#******************************************************************************* +"""Drive a CodeQL MISRA C++ analysis of Bazel-built C++ targets. + +Ported from eclipse-score/communication's quality/static_analysis/codeql_lint.py +as part of the CodeQL evaluation for baselibs (eclipse-score/baselibs#317). + +Two phases are supported, plus an "all" phase that runs both in sequence: + - create-database: init a CodeQL database and populate it by tracing a + `bazel build --config=codeql` of the given target(s). + - analyze-database: run the MISRA C++ coding-standards queries against an + existing database and emit SARIF + CSV reports. +""" +import argparse +import os +import tempfile +import json +import subprocess +import datetime +import shutil +import time +import glob + + +def create_database(code_ql_path, config_path, target, source_root, database_path): + """Create the CodeQL database: init, build with tracing, finalize.""" + # Note: the `--` before database_path is required to mark the end of options so + # CodeQL treats the path as the positional argument, not a flag value. + subprocess.run( + f"{code_ql_path} database init --overwrite --begin-tracing --language=cpp " + f"--codescanning-config={config_path} --source-root={source_root} -- {database_path}", + shell=True, check=True) + + env_file = os.path.join(database_path, "temp/tracingEnvironment/start-tracing.json") + with open(env_file) as f: + codeql_env = json.load(f) + env = _get_merged_environment(codeql_env) + + # Process coding standards config + subprocess.run( + f"bazel run @codeql_coding_standards//:process_coding_standards_config -- " + f"--working-dir={source_root}", + shell=True, env=env, cwd=source_root, check=True) + + # Build with CodeQL tracing + timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f') + bazel_cmd = f"bazel build --config=codeql --stamp --action_env=CODEQL_SEED_FORCE_RECOMPILE={timestamp}" + bazel_cmd += _get_action_env_extension(codeql_env) + subprocess.run(f"{bazel_cmd} {target}", shell=True, env=env, cwd=source_root, check=True) + + # Finalize database + subprocess.run(f"{code_ql_path} database finalize -j=0 -- {database_path}", shell=True, check=True) + + +def analyze_database(code_ql_path, database_path, source_root, analysis_report_path=None, + query_spec=None, output_prefix="codeql", output_dir=None): + """Run CodeQL analysis and generate MISRA C++ compliance reports.""" + output_base = output_dir or _get_bazel_info(source_root).get('output_path') + os.makedirs(output_base, exist_ok=True) + + query_arg = f" {query_spec}" if query_spec else "" + sarif_path = f"{output_base}/{output_prefix}.sarif" + csv_path = f"{output_base}/{output_prefix}.csv" + + # Run CodeQL analysis (generates SARIF) + print("\n Running CodeQL analysis...") + subprocess.run( + f"{code_ql_path} database analyze -j=0 {database_path}{query_arg} " + f"--format=sarifv2.1.0 --output={sarif_path}", + shell=True, check=True) + + # Generate CSV results + subprocess.run( + f"{code_ql_path} database analyze -j=0 {database_path}{query_arg} " + f"--format=csv --output={csv_path}", + shell=True, check=True) + + # Generate reports using CodeQL analysis_report tool + if analysis_report_path and os.path.exists(analysis_report_path): + print(" Generating MISRA C++ compliance reports...") + try: + # Make analysis_report executable and run it + os.chmod(analysis_report_path, 0o755) + print(f" Using database: {database_path}") + print(f" Using SARIF: {sarif_path}") + print(f" Output directory: {output_base}") + + # Prepare environment with CodeQL binary path + env = os.environ.copy() + # codeql_cli is a symlink to the actual codeql binary + # Resolve the symlink to get the real directory + try: + real_codeql_path = os.path.realpath(code_ql_path) + codeql_bin_dir = os.path.dirname(real_codeql_path) + except Exception: + codeql_bin_dir = os.path.dirname(os.path.abspath(code_ql_path)) + + # Prepend codeql directory to PATH + env["PATH"] = f"{codeql_bin_dir}:{env.get('PATH', '')}" + + # analysis_report's deviations/diagnostics/recategorizations reports run CodeQL + # queries from the `codeql/common-cpp-coding-standards` qlpack (cpp/common/src), + # which depends on `advanced-security/qtil`. Unlike a plain git clone of + # codeql-coding-standards, our git_repository fetch does not pre-resolve qlpack + # dependencies, so the first run fails with "Pack ... was not found in the pack + # download cache" (eclipse-score/baselibs#317 finding). Install it explicitly. + runfiles_dir = f"{analysis_report_path}.runfiles" + for qlpack_dir in glob.glob(os.path.join(runfiles_dir, "*", "cpp", "common", "src")): + subprocess.run([code_ql_path, "pack", "install", qlpack_dir], env=env, check=False) + + # analysis_report expects positional args: database-dir sarif-file output-dir + reports_output_dir = os.path.join(output_base, "analysis_reports") + + # Remove existing reports directory if it exists + if os.path.exists(reports_output_dir): + shutil.rmtree(reports_output_dir) + + result = subprocess.run( + [analysis_report_path, database_path, sarif_path, reports_output_dir], + capture_output=True, text=True, env=env) + + # Check if reports were generated even if there was an error + # (analysis_report writes files before failing on some post-processing). + # NOTE: previously this only checked "any file exists", which silently + # hid partial failures (e.g. only database_integrity_report.md written + # while deviations_report.md etc. were missing due to a crash) - see + # eclipse-score/baselibs#317 findings. Compare against the expected set. + expected_report_files = { + "database_integrity_report.md", "deviations_report.md", + "guideline_compliance_summary.md", "guideline_recategorizations_report.md", + } + if os.path.exists(reports_output_dir): + report_files = glob.glob(os.path.join(reports_output_dir, "*")) + found_names = {os.path.basename(f) for f in report_files} + missing = expected_report_files - found_names + if report_files: + print(f"Reports generated successfully" if not missing + else f"Reports partially generated (missing: {', '.join(sorted(missing))})") + print(f"\n Generated Report Files:") + for f in sorted(report_files): + file_size = os.path.getsize(f) / 1024 # KB + print(f" {os.path.basename(f)} ({file_size:.1f} KB)") + if missing: + print(f" analysis_report stderr: {result.stderr}") + else: + # If no files, raise the error + result.check_returncode() + else: + result.check_returncode() + except subprocess.CalledProcessError as e: + print(f"Report generation warning: {e.stderr if e.stderr else e}") + else: + print(" Report generation skipped (analysis_report tool not available)") + + +def main(): + parser = argparse.ArgumentParser(description="Run CodeQL linting operations") + parser.add_argument("--codeql_path", help="Path to CodeQL binary") + parser.add_argument("--config_path", help="CodeQL config file") + parser.add_argument("--analysis_report_path", help="Path to analysis_report binary") + parser.add_argument("--target", nargs="+", help="Bazel targets to build") + parser.add_argument("--phase", choices=["create-database", "analyze-database", "all"], + default="all", help="Execution phase") + parser.add_argument("--database-path", help="CodeQL database path") + parser.add_argument("--query-spec", help="CodeQL query spec") + parser.add_argument("--output-prefix", default="codeql", help="Output prefix") + parser.add_argument("--output-dir", help="Output directory") + + args = parser.parse_args() + target = " ".join(args.target) if args.target else "" + source_root = os.environ["BUILD_WORKING_DIRECTORY"] + + # Make codeql_path absolute + codeql_path = os.path.abspath(args.codeql_path) if args.codeql_path else None + + if args.phase == "create-database": + os.makedirs(os.path.dirname(args.database_path), exist_ok=True) + create_database(codeql_path, args.config_path, target, source_root, args.database_path) + + elif args.phase == "analyze-database": + analyze_database(codeql_path, args.database_path, source_root, + analysis_report_path=args.analysis_report_path, + query_spec=args.query_spec, output_prefix=args.output_prefix, + output_dir=args.output_dir) + + else: # all + # Use standard Bazel output directory for database + bazel_info = _get_bazel_info(source_root) + output_path = args.output_dir or bazel_info.get('output_path') + # Ensure the output directory exists before CodeQL tries to create the + # database inside it (codeql database init does not create parents). + os.makedirs(output_path, exist_ok=True) + db_loc = os.path.join(output_path, "codeql_database") + + create_database(codeql_path, args.config_path, target, source_root, db_loc) + analyze_database(codeql_path, db_loc, source_root, + analysis_report_path=args.analysis_report_path, + query_spec=args.query_spec, output_prefix=args.output_prefix, + output_dir=args.output_dir) + print(f" Use this database for future report generation") + + +def _get_action_env_extension(codeql_env): + action_env_extension = "" + for env_var in codeql_env: + action_env_extension += f" --action_env={env_var}" + return action_env_extension + + +def _get_merged_environment(codeql_env): + env = os.environ.copy() + for var in codeql_env: + env[var] = f"{codeql_env[var]}:{env.get(var, '')}" if var in env else codeql_env[var] + return env + + +def _get_bazel_info(source_root): + result = subprocess.run( + "bazel info", + shell=True, + cwd=source_root, + capture_output=True, + text=True, + check=True + ) + + # Parse the output into a dictionary + bazel_info = {} + for line in result.stdout.strip().split('\n'): + if ':' in line: + key, value = line.split(':', 1) + bazel_info[key.strip()] = value.strip() + return bazel_info + + +if __name__ == "__main__": + main() diff --git a/score/quality/static_analysis/config.yaml b/score/quality/static_analysis/config.yaml new file mode 100644 index 000000000..b6d627e72 --- /dev/null +++ b/score/quality/static_analysis/config.yaml @@ -0,0 +1,5 @@ +packs: + - codeql/misra-cpp-coding-standards@2.61.0 +query-filters: + - exclude: + tags: exclude-from-incremental diff --git a/score/quality/static_analysis/static_analysis.bazelrc b/score/quality/static_analysis/static_analysis.bazelrc new file mode 100644 index 000000000..8fb220843 --- /dev/null +++ b/score/quality/static_analysis/static_analysis.bazelrc @@ -0,0 +1,40 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# CodeQL evaluation config (eclipse-score/baselibs#317), ported from +# eclipse-score/communication's quality/static_analysis/static_analysis.bazelrc. +# +# Run with: bazel run //score/quality/static_analysis:codeql_lint -- --target //score/... +# +# baselibs-specific adaptations vs. the communication repo: +# - inherits --config=_bl_stub so the traced build resolves baselibs feature flags +# (json backend, shared-memory typedshmd flag, warning features) the same way the +# default bl-x86_64-linux config does. +# - traces the @llvm_toolchain (LLVM 19.1.1) compiler, which is already registered in +# MODULE.bazel, rather than the default gcc 12.2.0 host toolchain used by +# bl-x86_64-linux. Tracing the production gcc toolchain instead is a possible +# follow-up if this becomes a permanent check. +common:codeql --config=_bl_stub +common:codeql --platform_suffix=codeql +common:codeql --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux +common:codeql --sandbox_writable_path=/var/tmp +common:codeql --nouse_action_cache +common:codeql --noremote_accept_cached +common:codeql --noremote_upload_local_results +common:codeql --disk_cache= +# CodeQL's `--begin-tracing` intercepts compiler invocations via an LD_PRELOAD-based +# trace agent (env vars merged in codeql_lint.py). Bazel's linux-sandbox strategy runs +# each action in its own mount namespace, which hides that agent from the compiler +# subprocess, so nothing gets extracted. Forcing local (non-sandboxed) execution lets +# the trace agent see and record the compiler invocations. +build:codeql --spawn_strategy=local diff --git a/third_party/codeql/BUILD b/third_party/codeql/BUILD new file mode 100644 index 000000000..ca5de742e --- /dev/null +++ b/third_party/codeql/BUILD @@ -0,0 +1,12 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* diff --git a/third_party/codeql/codeql.BUILD b/third_party/codeql/codeql.BUILD new file mode 100644 index 000000000..a476950f9 --- /dev/null +++ b/third_party/codeql/codeql.BUILD @@ -0,0 +1,25 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +filegroup( + name = "codeql", + srcs = glob(["**"]), + visibility = ["//visibility:public"], +) + +sh_binary( + name = "codeql_cli", + srcs = ["codeql/codeql"], + data = glob(["codeql/**"]), + visibility = ["//visibility:public"], +) diff --git a/third_party/codeql/codeql_coding_standards.BUILD b/third_party/codeql/codeql_coding_standards.BUILD new file mode 100644 index 000000000..d7e3a0714 --- /dev/null +++ b/third_party/codeql/codeql_coding_standards.BUILD @@ -0,0 +1,42 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@codeql_coding_standards_pip_hub//:requirements.bzl", "requirement") + +py_binary( + name = "process_coding_standards_config", + srcs = ["scripts/configuration/process_coding_standards_config.py"], + deps = [requirement("pyyaml")], + visibility = ["//visibility:public"], +) + +py_binary( + name = "analysis_report", + srcs = [ + "scripts/reports/analysis_report.py", + "scripts/reports/codeqlvalidation.py", + "scripts/reports/deviations.py", + "scripts/reports/diagnostics.py", + "scripts/reports/error.py", + "scripts/reports/guideline_recategorizations.py", + "scripts/reports/utils.py", + "scripts/shared/codeql.py", + ], + data = ["supported_codeql_configs.json"] + glob(["cpp/**"]), + imports = [ + "scripts/reports", + "scripts/shared", + ], + deps = [requirement("pyyaml")], + visibility = ["//visibility:public"], +) diff --git a/third_party/codeql/requirements_lock.txt b/third_party/codeql/requirements_lock.txt new file mode 100644 index 000000000..6e87bb381 --- /dev/null +++ b/third_party/codeql/requirements_lock.txt @@ -0,0 +1,4 @@ +# Requirements for the CodeQL coding-standards tooling (process_coding_standards_config, +# analysis_report). Kept unhashed since this is a CodeQL evaluation (issue #317); hashes +# should be added with `pip-compile --generate-hashes` if this is promoted to a permanent tool. +pyyaml==6.0.2