Skip to content

Commit f8e010f

Browse files
authored
feat: add analyze_code job (#12)
The job to run static code analysis to detect vulnerabilities using the Semgrep scan command. Ability to run a full scan or diff scan, e.g. pull request.
1 parent bae8bbd commit f8e010f

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed

.circleci/test-deploy.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ workflows:
5757
name: detect_secrets_git_no_revision
5858
base_branch: <<pipeline.git.branch>>
5959
filters: *filters
60+
- security/analyze_code:
61+
name: analyze_code_diff
62+
path: ~/project/sample
63+
filters: *filters
64+
- security/analyze_code:
65+
name: analyze_code_full
66+
full_scan: true
67+
rules: p/cwe-top-25
68+
filters: *filters
6069
- orb-tools/pack:
6170
filters: *release-filters
6271
- orb-tools/publish:
@@ -70,5 +79,7 @@ workflows:
7079
- scan_dependencies_command
7180
- detect_secrets_dir
7281
- detect_secrets_git_base_revision
82+
- analyze_code_diff
83+
- analyze_code_full
7384
context: orb-publishing
7485
filters: *release-filters

src/examples/sast.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
description: |
2+
The "analyze_code" job runs a static analysis tool to scan the codebase for vulnerabilities.
3+
By default, a diff-aware scanning is performed meaning only file changes in the last commit
4+
are scanned, or files scoped to the pull request if a short-lived branch is in question.
5+
There is an option to scan all files inside a repository, change a base branch,
6+
and enforce a different set of scan rules.
7+
usage:
8+
version: 2.1
9+
orbs:
10+
security: studion/security@x.y.z
11+
workflows:
12+
test_codebase:
13+
jobs:
14+
- security/analyze_code:
15+
path: ~/workspace
16+
full_scan: true
17+
base_branch: prod

src/executors/semgrep.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
description: >
2+
A Docker executor using official Semgrep image based on Alpine Linux.
3+
4+
parameters:
5+
tag:
6+
type: string
7+
default: latest
8+
description: >
9+
Choose a specific semgrep/semgrep image tag:
10+
https://hub.docker.com/r/semgrep/semgrep/tags
11+
resource_class:
12+
type: enum
13+
enum: ['small', 'medium', 'medium+', 'large', 'xlarge', '2xlarge', '2xlarge+']
14+
default: 'medium'
15+
description: Choose the executor resource class
16+
17+
docker:
18+
- image: semgrep/semgrep:<<parameters.tag>>
19+
resource_class: <<parameters.resource_class>>

src/jobs/analyze_code.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
description: >
2+
Run static analysis, or SAST, to find vulnerabilities in the codebase. Utilizes the Semgrep "scan"
3+
command to do the analysis, for details hot it works see https://semgrep.dev/docs/cli-reference.
4+
5+
executor: semgrep
6+
7+
parameters:
8+
path:
9+
type: string
10+
default: '.'
11+
description: The path to the directory to scan.
12+
full_scan:
13+
type: boolean
14+
default: false
15+
description: >
16+
The flag indicating whether to scan the full directory vs just files changed from the last commit,
17+
or the whole branch if it is a short-lived branch, i.e. pull request.
18+
verbose:
19+
type: boolean
20+
default: false
21+
description: The flag indicates whether to show more details about rules, files, etc.
22+
rules:
23+
type: string
24+
default: p/default p/owasp-top-ten p/r2c-security-audit p/eslint
25+
description: >
26+
The space-separated list of Semgrep rules, e.g. YAML configuration file, URL of the configuration
27+
file, or Semgrep registry entry name.
28+
base_branch:
29+
type: string
30+
default: ''
31+
description: >
32+
The name of the base branch for this scan. Usually some long-lived branch, e.g. default branch.
33+
34+
steps:
35+
- checkout
36+
- run:
37+
name: Analyze code
38+
working_directory: <<parameters.path>>
39+
environment:
40+
DIR_PATH: <<parameters.path>>
41+
FULL_SCAN: <<parameters.full_scan>>
42+
VERBOSE: <<parameters.verbose>>
43+
RULES: <<parameters.rules>>
44+
BASE_BRANCH_OVERRIDE: <<parameters.base_branch>>
45+
command: <<include(scripts/analyze-code.sh)>>

src/scripts/analyze-code.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/bash
2+
3+
########### DEFAULTS ###########
4+
5+
ARGS="--experimental --error --strict --metrics off"
6+
7+
########### VERBOSE ###########
8+
9+
if [ "$VERBOSE" -eq 1 ]; then
10+
ARGS="$ARGS --verbose"
11+
fi
12+
13+
########### CONFIG ###########
14+
15+
function join() {
16+
local separator="$1"
17+
shift
18+
local first="$1"
19+
shift
20+
printf "%s" "$first" "${@/#/$separator}"
21+
}
22+
23+
IFS=' ' read -ra RULE_ARRAY <<< "$RULES"
24+
25+
ARGS="$ARGS --config $(join ' --config ' "${RULE_ARRAY[@]}")"
26+
27+
########### BASELINE COMMIT ###########
28+
29+
BASE_BRANCH=$(git rev-parse --abbrev-ref origin/HEAD | cut -c8-)
30+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
31+
32+
if [[ -n $BASE_BRANCH_OVERRIDE ]]; then
33+
BASE_BRANCH=$BASE_BRANCH_OVERRIDE
34+
fi
35+
36+
if [[ -n $CIRCLE_BRANCH ]]; then
37+
CURRENT_BRANCH=$CIRCLE_BRANCH
38+
fi
39+
40+
BASELINE_COMMIT=""
41+
42+
if [ "$FULL_SCAN" -eq 0 ] && [[ "$BASE_BRANCH" = "$CURRENT_BRANCH" ]]; then
43+
# Usually when changes are merged back into a long-lived branch, e.g. trunk
44+
BASELINE_COMMIT=$(git rev-parse HEAD~1)
45+
elif [ "$FULL_SCAN" -eq 0 ] && [[ "$BASE_BRANCH" != "$CURRENT_BRANCH" ]]; then
46+
# Usually a short-lived branch, in other words a pull request
47+
BASELINE_COMMIT="$(git rev-parse "$BASE_BRANCH")"
48+
fi
49+
50+
if [[ -n $BASELINE_COMMIT ]]; then
51+
ARGS="$ARGS --baseline-commit $BASELINE_COMMIT"
52+
fi
53+
54+
########### COMMAND ###########
55+
56+
echo "Running Semgrep scan, at path '$DIR_PATH', with following arguments:"
57+
echo "$ARGS"
58+
59+
eval semgrep "$ARGS"

0 commit comments

Comments
 (0)