Skip to content

Commit

Permalink
[CodeQL] Local run script (#194272)
Browse files Browse the repository at this point in the history
## Summary

This PR introduces a script that allows developers to run CodeQL
analysis locally. It uses a Docker container with prebuilt CodeQL
queries to facilitate easy setup and execution.
The script has the following key steps:
- Creating a CodeQL database from the source code. The database is
essentially a representation of the codebase that CodeQL uses to analyze
for potential issues.
- Running the analysis on the created database,
`javascript-security-and-quality` suit is used.

### Usage
```
bash scripts/codeql/quick_check.sh -s path/to/your-source-dir
```
For example
```
bash scripts/codeql/quick_check.sh -s ./x-pack/plugins/security_solution/public/common/components/ml/conditional_links
```

The `-s` option allows you to specify the path to the source code
directory that you wish to analyze.

### Why custom Docker file?
Checked the ability to use MSFT image for local run
https://github.com/microsoft/codeql-container. Turned out it has several
problems:
1. The published one has an error with [execute
permissions](microsoft/codeql-container#53).
2. Container has outdated nodejs version, so it didn't parse our syntax
(like `??`) and failed.
3. The technique used in the repository to download the CodeQL binaries
and precompile the queries is outdated in the sense that GitHub now
offers pre-compiled queries you can just download. Follow this
[comment](microsoft/codeql-container#53 (comment)).

Taking this into consideration I have created a lightweight docker image
without extraneous dependencies for go/.net/java.

## Context and interdependencies issues
There are issues sometimes when analyze run returns no results,
particularly when analyzing a single folder.
It might be due to the missing context for the data flow graph CodeQL
generates or context for interdependencies. This is actually a trade off
of running it locally for a subset of source directories. We need to
explicitly state that in the documentation and advise to expand the
scope of source code directories involved for local scan.

Documentation for triaging issues will be updated separately.

__Closes: https://github.com/elastic/kibana/issues/195740__
  • Loading branch information
elena-shostak authored Oct 28, 2024
1 parent 00f34d9 commit 9dd4205
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,5 @@ x-pack/test/security_solution_playwright/playwright-report/
x-pack/test/security_solution_playwright/blob-report/
x-pack/test/security_solution_playwright/playwright/.cache/
x-pack/test/security_solution_playwright/.auth/
x-pack/test/security_solution_playwright/.env
x-pack/test/security_solution_playwright/.env
.codeql
39 changes: 39 additions & 0 deletions scripts/codeql/codeql.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM ubuntu:latest

ENV DEBIAN_FRONTEND=noninteractive

ARG USERNAME=codeql
ARG CODEQL_VERSION="v2.19.0"
ENV CODEQL_HOME /usr/local/codeql-home

RUN apt-get update && \
apt-get install -y --no-install-recommends \
passwd \
adduser \
bash \
curl \
git \
unzip \
nodejs \
jq

RUN adduser --home ${CODEQL_HOME} ${USERNAME}

RUN curl -Lk "https://github.com/github/codeql-action/releases/download/codeql-bundle-${CODEQL_VERSION}/codeql-bundle-linux64.tar.gz" -o codeql.tar.gz \
&& mkdir -p ${CODEQL_HOME} \
&& tar -xvzf codeql.tar.gz -C ${CODEQL_HOME} \
&& rm codeql.tar.gz

RUN chmod +x ${CODEQL_HOME}/codeql/codeql

RUN chown -R ${USERNAME}:${USERNAME} ${CODEQL_HOME}

USER ${USERNAME}

ENV PATH="${CODEQL_HOME}/codeql:${PATH}"

RUN echo $PATH && codeql --version

WORKDIR /workspace

ENTRYPOINT ["/bin/bash", "-c"]
126 changes: 126 additions & 0 deletions scripts/codeql/quick_check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/bin/bash

LANGUAGE="javascript"
CODEQL_DIR=".codeql"
DATABASE_PATH="$CODEQL_DIR/database"
QUERY_OUTPUT="$DATABASE_PATH/results.sarif"
OUTPUT_FORMAT="sarif-latest"
DOCKER_IMAGE="codeql-env"
BASE_DIR="$(cd "$(dirname "$0")"; pwd)"

# Colors
bold=$(tput bold)
reset=$(tput sgr0)
red=$(tput setaf 1)
green=$(tput setaf 2)
blue=$(tput setaf 4)
yellow=$(tput setaf 3)

while getopts ":s:r:" opt; do
case $opt in
s) SRC_DIR="$OPTARG" ;;
r) CODEQL_DIR="$OPTARG"; DATABASE_PATH="$CODEQL_DIR/database"; QUERY_OUTPUT="$DATABASE_PATH/results.sarif" ;;
\?) echo "Invalid option -$OPTARG" >&2; exit 1 ;;
:) echo "Option -$OPTARG requires an argument." >&2; exit 1 ;;
esac
done

if [ -z "$SRC_DIR" ]; then
echo "Usage: $0 -s <source_dir> [-r <results_dir>]"
exit 1
fi

mkdir -p "$CODEQL_DIR"

# Check the architecture
ARCH=$(uname -m)
PLATFORM_FLAG=""

# CodeQL CLI binary does not support arm64 architecture, setting the platform to linux/amd64
if [[ "$ARCH" == "arm64" ]]; then
PLATFORM_FLAG="--platform linux/amd64"
fi

if [[ "$(docker images -q $DOCKER_IMAGE 2> /dev/null)" == "" ]]; then
echo "Docker image $DOCKER_IMAGE not found. Building locally..."
docker build $PLATFORM_FLAG -t "$DOCKER_IMAGE" -f "$BASE_DIR/codeql.dockerfile" "$BASE_DIR"
if [ $? -ne 0 ]; then
echo "${red}Docker image build failed.${reset}"
exit 1
fi
fi

cleanup_database() {
echo "Deleting contents of $CODEQL_DIR."
rm -rf "$CODEQL_DIR"/*
}

SRC_DIR="$(cd "$(dirname "$SRC_DIR")"; pwd)/$(basename "$SRC_DIR")"
CODEQL_DIR="$(cd "$(dirname "$CODEQL_DIR")"; pwd)/$(basename "$CODEQL_DIR")"
DATABASE_PATH="$(cd "$(dirname "$DATABASE_PATH")"; pwd)/$(basename "$DATABASE_PATH")"

# Step 1: Run the Docker container to create a CodeQL database from the source code.
echo "Creating a CodeQL database from the source code: $SRC_DIR"
docker run $PLATFORM_FLAG --rm -v "$SRC_DIR":/workspace/source-code \
-v "${DATABASE_PATH}":/workspace/shared $DOCKER_IMAGE \
"codeql database create /workspace/shared/codeql-db --language=javascript --source-root=/workspace/source-code --overwrite"

if [ $? -ne 0 ]; then
echo "CodeQL database creation failed."
cleanup_database
exit 1
fi

echo "Analyzing a CodeQL database: $DATABASE_PATH"
# Step 2: Run the Docker container to analyze the CodeQL database.
docker run $PLATFORM_FLAG --rm -v "${DATABASE_PATH}":/workspace/shared $DOCKER_IMAGE \
"codeql database analyze --format=${OUTPUT_FORMAT} --output=/workspace/shared/results.sarif /workspace/shared/codeql-db javascript-security-and-quality.qls"

if [ $? -ne 0 ]; then
echo "CodeQL database analysis failed."
cleanup_database
exit 1
fi

# Step 3: Print summary of SARIF results
echo "Analysis complete. Results saved to $QUERY_OUTPUT"
if command -v jq &> /dev/null; then
vulnerabilities=$(jq -r '.runs[] | select(.results | length > 0)' "$QUERY_OUTPUT")

if [[ -z "$vulnerabilities" ]]; then
echo "${blue}${bold}No vulnerabilities found in the SARIF results.${reset}"
else
echo "${yellow}${bold}Summary of SARIF results:${reset}"
jq -r '
.runs[] |
.results[] as $result |
.tool.driver.rules[] as $rule |
select($rule.id == $result.ruleId) |
"Rule: \($result.ruleId)\nMessage: \($result.message.text)\nFile: \($result.locations[].physicalLocation.artifactLocation.uri)\nLine: \($result.locations[].physicalLocation.region.startLine)\nSecurity Severity: \($rule.properties."security-severity" // "N/A")\n"' "$QUERY_OUTPUT" |
while IFS= read -r line; do
case "$line" in
Rule:*)
echo "${red}${bold}$line${reset}"
;;
Message:*)
echo "${green}$line${reset}"
;;
File:*)
echo "${blue}$line${reset}"
;;
Line:*)
echo "${yellow}$line${reset}"
;;
Security\ Severity:*)
echo "${yellow}$line${reset}"
;;
*)
echo "$line"
;;
esac
done
fi
else
echo "${red}${bold}Please install jq to display a summary of the SARIF results.${reset}"
echo "${bold}You can view the full results in the SARIF file using a SARIF viewer.${reset}"
fi

0 comments on commit 9dd4205

Please sign in to comment.