diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..ad585473b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,66 @@ +name: CodeQL workflow for analyzing QL queries + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + security-events: write + +env: + NIXPKGS_ALLOW_UNFREE: 1 + +jobs: + analyze-ql-files: + name: Analyze QL files + runs-on: ubuntu-latest + steps: + + - name: Install Nix + uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 + + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache Nix store + uses: actions/cache@v4 + id: cache + with: + path: ${{ runner.temp }}/nix/store + key: ${{ runner.os }}-${{ hashFiles('tooling/**', '.github/workflows/codeql.yml') }} + + - name: Copy Nix store from cache + if: steps.cache.outputs.cache-hit == 'true' + run: | + nix copy --all --from "file://$RUNNER_TEMP/nix/store" + + - name: Prepare Nix store + if: steps.cache.outputs.cache-hit != 'true' + run: | + nix-shell --pure --command "codeql version" tooling/shell.nix + + - name: Copy Nix store to cache location + if: steps.cache.outputs.cache-hit != 'true' + run: | + nix copy --all --to "file://$RUNNER_TEMP/nix/store" + + - name: Create database + run: | + nix-shell --pure --command "codeql database create --language=ql --source-root=. $RUNNER_TEMP/ql-db" tooling/shell.nix + + - name: Analyze database + run: | + nix-shell --pure --command "codeql database analyze --output=$RUNNER_TEMP/ql.sarif --format=sarif-latest --sarif-category=ql4ql -- $RUNNER_TEMP/ql-db codeql/ql" tooling/shell.nix + + - name: Upload results + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + nix-shell --pure --keep GITHUB_TOKEN --command "codeql github upload-results --sarif=$RUNNER_TEMP/ql.sarif --repository=$GITHUB_REPOSITORY --ref=$GITHUB_REF --commit=$GITHUB_SHA" tooling/shell.nix + + + + diff --git a/tooling/all-tools.nix b/tooling/all-tools.nix new file mode 100644 index 000000000..4d395cc36 --- /dev/null +++ b/tooling/all-tools.nix @@ -0,0 +1,4 @@ +let + codeql = import codeql/default.nix; +in +codeql \ No newline at end of file diff --git a/tooling/codeql/codeql-cli/2.16.0.nix b/tooling/codeql/codeql-cli/2.16.0.nix new file mode 100644 index 000000000..fb260e639 --- /dev/null +++ b/tooling/codeql/codeql-cli/2.16.0.nix @@ -0,0 +1,61 @@ +{ lib, stdenv, fetchzip, jdk17, withExtractors ? [], withPacks ? [] }: + +stdenv.mkDerivation rec { + pname = "codeql-cli"; + version = "2.16.0"; + platform = if stdenv.isDarwin then "osx64" else "linux64"; + + dontConfigure = true; + dontBuild = true; + dontStrip = true; + + src = fetchzip { + url = "https://github.com/github/codeql-cli-binaries/releases/download/v${version}/codeql-${platform}.zip"; + hash = if platform == "osx64" then "sha256-trWUSMOT7h7J5ejjp9PzhGgBS3DYsJxzcv6aYKuk8TI=" else "sha256-ztvKlNbqWcH93AB/Mum9jM81ssxiGcbkBROEANFGXis="; + }; + + buildInputs = if (lib.length withExtractors) == 0 then [ ] else withExtractors; + inherit withExtractors withPacks; + + nativeBuildInputs = [ jdk17 ]; + + installPhase = '' + # codeql directory should not be top-level, otherwise, + # it'll include /nix/store to resolve extractors. + mkdir -p $out/{codeql/qlpacks,bin} + cp -R * $out/codeql/ + + + if [ "$platform" == "linux64" ]; then + ln -sf $out/codeql/tools/linux64/lib64trace.so $out/codeql/tools/linux64/libtrace.so + fi + + # many of the codeql extractors use CODEQL_DIST + CODEQL_PLATFORM to + # resolve java home, so to be able to create databases, we want to make + # sure that they point somewhere sane/usable since we can not autopatch + # the codeql packaged java dist, but we DO want to patch the extractors + # as well as the builders which are ELF binaries for the most part + rm -rf $out/codeql/tools/$platform/java + ln -s ${jdk17} $out/codeql/tools/$platform/java + + ln -s $out/codeql/codeql $out/bin/ + + for extractor in $withExtractors; do + # Copy the extractor, because CodeQL doesn't follow symlinks. + cp -R $extractor $out/codeql/ql + done + + for pack in $withPacks ; do + # Copy the pack, because CodeQL doesn't follow symlinks. + cp -R $pack/* $out/codeql/qlpacks/ + done + ''; + + + meta = with lib; { + description = "Semantic code analysis engine"; + homepage = "https://codeql.github.com"; + platforms = lib.platforms.linux ++ lib.platforms.darwin; + license = licenses.unfree; + }; +} \ No newline at end of file diff --git a/tooling/codeql/codeql-cli/default.nix b/tooling/codeql/codeql-cli/default.nix new file mode 100644 index 000000000..291c526b9 --- /dev/null +++ b/tooling/codeql/codeql-cli/default.nix @@ -0,0 +1,7 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }); +in +{ + codeql-cli_2_16_0 = pkgs.callPackage ./2.16.0.nix {}; +} \ No newline at end of file diff --git a/tooling/codeql/codeql-cli/shell.nix b/tooling/codeql/codeql-cli/shell.nix new file mode 100644 index 000000000..4332715ea --- /dev/null +++ b/tooling/codeql/codeql-cli/shell.nix @@ -0,0 +1,11 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }); + codeql = import ./default.nix; +in + +pkgs.mkShell { + packages = with codeql; [ + codeql-cli_2_16_0 + ]; +} diff --git a/tooling/codeql/codeql-ql/0.0.1-dev.nix b/tooling/codeql/codeql-ql/0.0.1-dev.nix new file mode 100644 index 000000000..178a3dfd8 --- /dev/null +++ b/tooling/codeql/codeql-ql/0.0.1-dev.nix @@ -0,0 +1,29 @@ +{ stdenv, lib, fetchFromGitHub, rustPlatform, gh, libiconv, which, jq, withCodeQlCli }: + +stdenv.mkDerivation rec { + pname = "codeql-ql"; + version = "0.1.0-dev"; + + dontConfigure = true; + dontStrip = true; + dontInstall = true; + dontFixup = true; + + src = fetchFromGitHub { + owner = "github"; + repo = "codeql"; + rev = "codeql-cli/v2.16.0"; + sha256 = "x2EFoOt1MZRXxIZt6hF86Z1Qu/hVUoOVla562TApVwo="; + }; + + nativeBuildInputs = [ gh libiconv which withCodeQlCli jq]; + + platform = if stdenv.isLinux then "linux64" else "osx64"; + + buildPhase = '' + runHook preBuild + mkdir -p $out + codeql pack create --threads=0 --output=$out --no-default-compilation-cache --compilation-cache=$TMP_DIR ql/ql/src + runHook postBuild + ''; +} \ No newline at end of file diff --git a/tooling/codeql/codeql-ql/default.nix b/tooling/codeql/codeql-ql/default.nix new file mode 100644 index 000000000..232804473 --- /dev/null +++ b/tooling/codeql/codeql-ql/default.nix @@ -0,0 +1,7 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }); +in +{ + codeql-ql-0_1_0-dev = pkgs.callPackage ./0.0.1-dev.nix {}; +} \ No newline at end of file diff --git a/tooling/codeql/default.nix b/tooling/codeql/default.nix new file mode 100644 index 000000000..aab80d48e --- /dev/null +++ b/tooling/codeql/default.nix @@ -0,0 +1,10 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }); +in +rec { + ql-extractor-0_0_1 = pkgs.callPackage ./ql-extractor/0.0.1.nix {}; + codeql-cli-2_16_0 = pkgs.callPackage ./codeql-cli/2.16.0.nix {}; + codeql-ql-0_0_1-dev = pkgs.callPackage ./codeql-ql/0.0.1-dev.nix { withCodeQlCli = codeql-cli-2_16_0; }; + codeql-cli-2_16_0-with-ql = pkgs.callPackage ./codeql-cli/2.16.0.nix { withExtractors = [ql-extractor-0_0_1]; withPacks = [codeql-ql-0_0_1-dev];}; +} \ No newline at end of file diff --git a/tooling/codeql/ql-extractor/0.0.1.nix b/tooling/codeql/ql-extractor/0.0.1.nix new file mode 100644 index 000000000..ad37c583b --- /dev/null +++ b/tooling/codeql/ql-extractor/0.0.1.nix @@ -0,0 +1,42 @@ +{ stdenv, lib, fetchFromGitHub, rustPlatform, gh, libiconv, which, jq}: + +rustPlatform.buildRustPackage rec { + pname = "codeql-ql-extractor"; + version = "0.0.1"; + + dontConfigure = true; + dontStrip = true; + + src = fetchFromGitHub { + owner = "github"; + repo = "codeql"; + rev = "codeql-cli/v2.16.0"; + sha256 = "x2EFoOt1MZRXxIZt6hF86Z1Qu/hVUoOVla562TApVwo="; + }; + + sourceRoot = "${src.name}/ql"; + + cargoLock = { + lockFile = "${src.outPath}/ql/Cargo.lock"; + outputHashes = { + "tree-sitter-json-0.20.0" = "sha256-fIh/bKxHMnok8D+xQlyyp5GaO2Ra/U2Y/5IjQ+t4+xY="; + "tree-sitter-ql-0.19.0" = "sha256-2QOtNguYAIhIhGuVqyx/33gFu3OqcxAPBZOk85Q226M="; + "tree-sitter-ql-dbscheme-0.0.1" = "sha256-wp0LtcbkP2lxbmE9rppO9cK+RATTjZxOb0EWfdKT884="; + }; + }; + + nativeBuildInputs = [ gh libiconv which jq]; + + platform = if stdenv.isLinux then "linux64" else "osx64"; + + installPhase = '' + runHook preInstall + mkdir -p $out/tools/$platform + cargo run --profile release --bin codeql-extractor-ql -- generate --dbscheme ql/src/ql.dbscheme --library ql/src/codeql_ql/ast/internal/TreeSitter.qll + # For some reason the fixupPhase isn't working, so we do it manually + patchShebangs tools/ + cp -r codeql-extractor.yml tools ql/src/ql.dbscheme ql/src/ql.dbscheme.stats $out/ + cp $(cargo metadata --format-version 1 | jq -r '.target_directory')/release/codeql-extractor-ql $out/tools/$platform/extractor + runHook postInstall + ''; +} \ No newline at end of file diff --git a/tooling/codeql/ql-extractor/default.nix b/tooling/codeql/ql-extractor/default.nix new file mode 100644 index 000000000..675f05edd --- /dev/null +++ b/tooling/codeql/ql-extractor/default.nix @@ -0,0 +1,7 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }); +in +{ + ql-extractor-0_0_1 = pkgs.callPackage ./0.0.1.nix {}; +} \ No newline at end of file diff --git a/tooling/shell.nix b/tooling/shell.nix new file mode 100644 index 000000000..573ffe1be --- /dev/null +++ b/tooling/shell.nix @@ -0,0 +1,15 @@ +let + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0e148322b344eab7c8d52f6e59b0d95ba73fb62e.tar.gz"; + pkgs = (import nixpkgs { config = {}; overlays = []; }) // (import ./all-tools.nix); +in + +pkgs.mkShell { + packages = with pkgs; [ + clang-tools_14 + python39 + git + gh + jq + codeql-cli-2_16_0-with-ql + ]; +} \ No newline at end of file