Skip to content

Commit 42ca3d0

Browse files
committed
Add startup script
Add precompilation step to docker and setup script Added Readme content Refactored functionality into modules
1 parent e79ce76 commit 42ca3d0

File tree

7 files changed

+186
-35
lines changed

7 files changed

+186
-35
lines changed

Dockerfile

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,18 @@ RUN apt-get update && \
2929
rsync \
3030
file \
3131
gettext && \
32-
apt-get clean
32+
apt-get clean && \
33+
ln -s /usr/bin/python3.8 /usr/bin/python && \
34+
ln -s /usr/bin/pip3 /usr/bin/pip
35+
36+
# Install .NET Core for tools/builds
37+
RUN cd /tmp && \
38+
wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \
39+
dpkg -i packages-microsoft-prod.deb && \
40+
add-apt-repository universe && \
41+
apt-get update && \
42+
rm packages-microsoft-prod.deb
43+
RUN apt-get install -y dotnet-sdk-3.1
3344

3445
# Clone our setup and run scripts
3546
#RUN git clone https://github.com/microsoft/codeql-container /usr/local/startup_scripts
@@ -44,14 +55,13 @@ ENV CODEQL_HOME /usr/local/codeql-home
4455
# record the latest version of the codeql-cli
4556
RUN python3 /usr/local/startup_scripts/get-latest-codeql-version.py > /tmp/codeql_version
4657
RUN mkdir -p ${CODEQL_HOME} \
47-
${CODEQL_HOME}/codeql-cli \
4858
${CODEQL_HOME}/codeql-repo \
4959
${CODEQL_HOME}/codeql-go-repo \
5060
/opt/codeql
5161

5262
RUN CODEQL_VERSION=$(cat /tmp/codeql_version) && \
5363
wget -q https://github.com/github/codeql-cli-binaries/releases/download/${CODEQL_VERSION}/codeql-linux64.zip -O /tmp/codeql_linux.zip && \
54-
unzip /tmp/codeql_linux.zip -d ${CODEQL_HOME}/codeql-cli && \
64+
unzip /tmp/codeql_linux.zip -d ${CODEQL_HOME} && \
5565
rm /tmp/codeql_linux.zip
5666

5767
# get the latest codeql queries and record the HEAD
@@ -60,9 +70,9 @@ RUN git clone https://github.com/github/codeql ${CODEQL_HOME}/codeql-repo && \
6070
RUN git clone https://github.com/github/codeql-go ${CODEQL_HOME}/codeql-go-repo && \
6171
git --git-dir ${CODEQL_HOME}/codeql-go-repo/.git log --pretty=reference -1 > /opt/codeql/codeql-go-repo-last-commit
6272

63-
ENV PATH="${CODEQL_HOME}/codeql-cli/codeql:${PATH}"
73+
ENV PATH="${CODEQL_HOME}/codeql:${PATH}"
6474

6575
# Pre-compile our queries to save time later
6676
#RUN codeql query compile --threads=0 ${CODEQL_HOME}/codelq-repo/*/ql/src/codeql-suites/*-.qls
6777
#RUN codeql query compile --threads=0 ${CODEQL_HOME}/codelq-go-repo/ql/src/codeql-suites/*-.qls
68-
#ENTRYPOINT ["python3", "/usr/local/startup_scripts/setup.py"]
78+
ENTRYPOINT ["python3", "/usr/local/startup_scripts/startup.py"]

README.md

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,67 @@
1+
## CodeQL Container
2+
3+
> **Note:** CodeQL container is currently in **public preview**. Please report any bugs to https://github.com/microsoft/codeql-container/issues.
4+
> Current version of CodeQL only works for interpreted languages. We will add compiled languages support on future versions.
5+
6+
CodeQL Container is a project aimed at making it easier to start using CodeQL (https://github.com/github/codeql). This project
7+
contains a Docker file which builds a container with the latest version of codeql-cli and codeql queries precompiled.
8+
It also contains scripts to keep the toolchain in the container updated. You can use this container to:
9+
10+
* Start using codeql-cli and run queries on your projects without installing it on your local machine.
11+
* Use is as an environment to develop codeql queries and test them.
12+
* Test how the queries perform in windows and linux environments.
13+
14+
We shall continue to add more features and would be happy to accept contributions from the community.
15+
16+
### Basic Usage
17+
18+
#### Downloading a pre-built container
19+
We keep updating the docker image periodically and uploading it to the Microsoft Container Registry at: mcr.microsoft.com/codeql/codeql-container.
20+
You can run the image by running the command:
21+
```
22+
$ docker run --rm mcr.microsoft.com/codeql/codeql-container
23+
```
24+
25+
If you want to analyze a particular source directory with codeql, run the container as:
26+
```
27+
$ docker run --rm --name codeql-container mcr.microsoft.com/codeql/codeql-container -v /dir/to/analyze:/opt/src -v /dir/for/results:/opt/results -e CODEQL_CLI_ARGS=<query run...>
28+
```
29+
where /dir/to/analyze contains the source files that have to be analyzed, and /dir/for/results is where the result output
30+
needs to be stored, and you can specify QL_PACKS environment variable for specific QL packs to be run on the provided code.
31+
For more information on CodeQL and QL packs, please visit https://www.github.com/github/codeql.
32+
CODEQL_CLI_ARGS are the arguments that will be directly passed on to the codeql-cli. Some examples of CODEQL_CLI_ARGS are:
33+
```
34+
CODEQL_CLI_ARGS = database create /opt/src/source_db
35+
```
36+
**Note:** If you map your source volume to some other mountpoint other than /opt/src, you will have to make the corresponding changes
37+
in the CODEQL_CLI_ARGS.
38+
39+
There are some additional docker environment variables that you can specify to control the execution of the container:
40+
* CHECK_LATEST_CODEQL_CLI - If there is a newer version of codeql-cli, download and install it
41+
* CHECK_LATEST_QUERIES - if there is are updates to the codeql queries repo, download and use it
42+
* PRECOMPILE_QUERIES - If we downloaded new queries, precompile all new query packs (query execution will be faster)
43+
WARNING: Precompiling query packs might take a few hours, depending on speed of your machine and the CPU/Memory limits (if any)
44+
you have placed on the container.
45+
46+
Since codeql first creates a database of the code representation, and then analyzes the db for issues, we need a few commands to
47+
analyze a source code repo.
48+
For example, if you want to analyze a python project source code placed in /dir/to/analyze (or C:\dir\to\analyze for example, in windows),
49+
to analyze and get a sarif result file, you will have to run:
50+
$ docker run --rm --name codeql-container mcr.microsoft.com/codeql/codeql-container -v /dir/to/analyze:/opt/src -v /dir/for/results:/opt/results -e CODEQL_CLI_ARGS="database create --language=python /opt/src/source_db"
51+
$ docker run --rm --name codeql-container mcr.microsoft.com/codeql/codeql-container -v /dir/to/analyze:/opt/src -v /dir/for/results:/opt/results -e CODEQL_CLI_ARGS="database analyze --format=sarifv2 --output=/opt/results/issues.sarif /opt/src/source_db
52+
53+
```
54+
This command will run all the ql packs related to security and output the results to the results folder.
55+
56+
#### Building the container
57+
Building the container should be pretty straightforward.
58+
git clone ...
59+
cd src
60+
docker build . -f Dockerfile -t codeql-container
161
262
# Contributing
363
4-
This project welcomes contributions and suggestions. Most contributions require you to agree to a
64+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
565
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
666
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
767

container/get-latest-codeql-version.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import os
55
import sys
6-
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
76

87
from libs.github import get_latest_github_repo_version
98

container/libs/codeql.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class CodeQL:
2020
TEMP_DIR ='/tmp'
2121

2222
# Error codes
23-
ERROR_EXECUTING_COMMAND = 1
2423
ERROR_EXECUTING_CODEQL = 2
2524
ERROR_UNKNOWN_OS = 3
2625
ERROR_GIT_COMMAND = 4
@@ -65,7 +64,7 @@ def download_and_install_latest_codeql_queries(self):
6564
exit(ERROR_GIT_COMMAND)
6665

6766
def get_current_local_version(self):
68-
ret_string = check_output_wrapper(f'{self.CODEQL_HOME}/codeql-cli/codeql/codeql version', shell=True).decode("utf-8")
67+
ret_string = check_output_wrapper(f'{self.CODEQL_HOME}/codeql/codeql version', shell=True).decode("utf-8")
6968
if ret_string is CalledProcessError:
7069
logger.error("Could not run codeql command")
7170
exit(ERROR_EXECUTING_CODEQL)
@@ -84,3 +83,13 @@ def install_codeql_cli(self, download_path):
8483
codeql_dir = f'{self.CODEQL_HOME}/codeql-cli'
8584
wipe_and_create_dir(codeql_dir)
8685
ret1 = check_output_wrapper(f'unzip {download_path} -d {codeql_dir}', shell=True)
86+
87+
def precompile_queries(self):
88+
execute_codeql_command(f' query compile --search-path {self.CODEQL_HOME} {self.CODEQL_HOME}/codeql-repo/*/ql/src/codeql-suites/*.qls')
89+
90+
def execute_codeql_command(self, args):
91+
ret_string = check_output_wrapper(f'{self.CODEQL_HOME}/codeql/codeql {args}', shell=True).decode("utf-8")
92+
if ret_string is CalledProcessError:
93+
logger.error("Could not run codeql command")
94+
exit(ERROR_EXECUTING_CODEQL)
95+
return ret_string

container/libs/utils.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
from sys import exit
1+
import sys
22
from shutil import rmtree
33
from os import environ, mkdir, name as os_name
44
from subprocess import check_output, CalledProcessError
5-
from logging import getLogger
5+
from logging import Logger, getLogger, INFO, StreamHandler, Formatter
66

77
logger = getLogger('codeql-container')
8+
ERROR_EXECUTING_COMMAND = 1
89

910
# get secrets from the env
10-
def get_env_variable(self, var_name, optional=False):
11+
def get_env_variable(var_name, optional=False):
1112
"""
1213
Retrieve an environment variable. Any failures will cause an exception
1314
to be thrown.
@@ -37,3 +38,18 @@ def check_output_wrapper(*args, **kwargs):
3738
def wipe_and_create_dir(dirname):
3839
rmtree(dirname)
3940
mkdir(dirname)
41+
42+
def get_logger(log_level=INFO):
43+
try:
44+
logger = getLogger(sys._getframe(1).f_code.co_name)
45+
logger.setLevel(log_level)
46+
if not logger.handlers:
47+
log_handler = StreamHandler(sys.stdout)
48+
log_handler.setLevel(log_level)
49+
log_handler.setFormatter(Formatter('[%(asctime)s] %(levelname)s: %(message)s'))
50+
51+
logger = getLogger(sys._getframe(1).f_code.co_name)
52+
logger.addHandler(log_handler)
53+
return logger
54+
except Exception as ex:
55+
print(str(ex))

container/setup.py

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,65 @@
22

33
import os
44
import sys
5-
from logging import Logger, getLogger, INFO
5+
import argparse
66
from sys import path as syspath
77
from libs.utils import *
88
from libs.github import *
99
from libs.codeql import *
1010

11-
# get the parent directory of the script, to link libs
12-
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
11+
CODEQL_HOME = get_env_variable('CODEQL_HOME')
1312

14-
CODEQL_HOME = environ['CODEQL_HOME']
13+
# should we update the local copy of codeql-cli if a new version is available?
14+
CHECK_LATEST_CODEQL_CLI = get_env_variable('CHECK_LATEST_CODEQL_CLI', True)
1515

16-
logger = getLogger('codeql-container')
16+
# should we update the local copy of codeql queries if a new version is available?
17+
CHECK_LATEST_QUERIES = get_env_variable('CHECK_LATEST_QUERIES', True)
18+
19+
# if we are downloading new queries, should we precompile them
20+
PRECOMPILE_QUERIES = get_env_variable('PRECOMPILE_QUERIES', True)
21+
22+
23+
logger = getLogger('codeql-container-setup')
1724
logger.setLevel(INFO)
1825

26+
def parse_arguments():
27+
28+
parser = argparse.ArgumentParser(description='Setup codeql components.')
29+
parser.add_argument("-c", "--check-latest-cli", help="check the latest codeql-cli package available and install it",
30+
default=False, action="store_true")
31+
parser.add_argument("-q", "--check-latest-queries", help="check the latest codeql queries available and install it",
32+
default=False, action="store_true")
33+
#(makes query execution faster, but building the container build slower).
34+
parser.add_argument("-p", "--precompile-latest-queries", help="if new queries were downloaded, precompile it",
35+
default=False, action="store_true")
36+
args = parser.parse_args()
37+
38+
return args
39+
1940
def setup():
2041
"""
2142
Download and install the latest codeql cli
2243
Download and install the latest codeql queries
2344
"""
24-
45+
args = parse_arguments()
2546
# check version and download the latest version
26-
get_latest_codeql()
27-
# install vscode?
28-
# clone codeql libs
29-
# setup vscode + codeql
30-
# wait for user
31-
47+
get_latest_codeql(args)
3248

33-
def get_latest_codeql():
49+
def get_latest_codeql(args):
3450
# what version do we have?
3551
codeql = CodeQL(CODEQL_HOME)
3652
current_installed_version = codeql.get_current_local_version()
3753
logger.info(f'Current codeql version: {current_installed_version}')
3854
latest_online_version = codeql.get_latest_codeql_github_version()
39-
if current_installed_version != latest_online_version.title:
55+
if current_installed_version != latest_online_version.title and args.check_latest_cli:
4056
# we got a newer version online, download and install it
4157
codeql.download_and_install_latest_codeql(latest_online_version)
4258
# get the latest queries regardless (TODO: Optimize by storing and checking the last commit hash?)
43-
codeql.download_and_install_latest_codeql_queries()
59+
if args.check_latest_queries:
60+
codeql.download_and_install_latest_codeql_queries()
61+
if args.precompile_latest_queries:
62+
codeql.precompile_queries()
4463

64+
logger = get_logger()
4565
setup()
4666

container/startup.py

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,55 @@
11
import os
2+
import sys
3+
from time import sleep
4+
from libs.utils import get_env_variable, check_output_wrapper, get_logger
5+
from libs.codeql import *
6+
7+
CODEQL_HOME = get_env_variable('CODEQL_HOME')
28

39
# should we update the local copy of codeql-cli if a new version is available?
4-
CHECK_LATEST_CODEQL_CLI = False
10+
CHECK_LATEST_CODEQL_CLI = get_env_variable('CHECK_LATEST_CODEQL_CLI', True)
511

612
# should we update the local copy of codeql queries if a new version is available?
7-
CHECK_LATEST_QUERIES = False
8-
13+
CHECK_LATEST_QUERIES = get_env_variable('CHECK_LATEST_QUERIES', True)
914

1015
# if we are downloading new queries, should we precompile them
1116
#(makes query execution faster, but building the container build slower).
12-
PRECOMPILE_QUERIES = False
17+
PRECOMPILE_QUERIES = get_env_variable('PRECOMPILE_QUERIES', True)
18+
19+
# ql packs, requested to run, if any
20+
CODEQL_CLI_ARGS = get_env_variable('CODEQL_CLI_ARGS', True)
21+
22+
# should we just exit after execution, or should we wait for user to stop container?
23+
WAIT_AFTER_EXEC = get_env_variable('WAIT_AFTER_EXEC', True)
1324

1425
def main():
15-
# get all the command-line args/envs required
16-
# check if the latest codeql cli need to be downloaded
17-
# check if the latest codeql queries need to be downloaded
18-
# check if we need to precompile the new queries
26+
# do the setup, if requested
27+
scripts_dir = os.path.dirname(os.path.realpath(__file__)) # get the parent directory of the script
28+
setup_script_args = ''
29+
if CHECK_LATEST_CODEQL_CLI:
30+
setup_script_args += ' --check-latest-cli'
31+
if CHECK_LATEST_QUERIES:
32+
setup_script_args += ' --check-latest-queries'
33+
if PRECOMPILE_QUERIES:
34+
setup_script_args += ' --precompile-latest-queries'
35+
36+
run_result = check_output_wrapper(
37+
f"{scripts_dir}/setup.py {setup_script_args}",
38+
shell=True).decode("utf-8")
39+
40+
# what command did the user ask to run?
41+
if CODEQL_CLI_ARGS == False or CODEQL_CLI_ARGS == None or CODEQL_CLI_ARGS == ' ':
42+
# nothing to do
43+
logger.info("No argument passed in for codeql-cli, nothing to do. To perform some task, please set the CODEQL_CLI_ARGS environment variable to a valid argument..")
44+
else:
45+
codeql = CodeQL(CODEQL_HOME)
46+
run_result = codeql.execute_codeql_command(CODEQL_CLI_ARGS)
47+
print(run_result)
48+
49+
if WAIT_AFTER_EXEC:
50+
logger.info("Wait forever specified, waiting...")
51+
while True:
52+
sleep(10)
53+
54+
logger = get_logger()
55+
main()

0 commit comments

Comments
 (0)