[Techworld with Nana] DevSecOps Bootcamp [2024, ENG]: Application Vulnerability Scanning
Делаю:
2026.01.14
01 - Build a Continuous Integration Pipeline (3 - Application Vulnerability Scanning)
package.json
в devDependencies
Добавить
"@types/minimatch": "^5.1.2",
karma.conf.js
// 1. Указываем использовать новый лаунчер по умолчанию
browsers: ['ChromeHeadlessNoSandbox'],
// 2. Определяем настройки для работы в Docker (без песочницы)
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox', '--disable-setuid-sandbox']
}
},
Settings -> CI/CD -> Variables
DOCKER_USER
DOCKER_PASS
.gitlab-ci.yml
variables:
IMAGE_NAME: webmakaka/demo-app
IMAGE_TAG: juice-shop-1.1
stages:
- test
- build
yarn_test:
stage: test
image: node:22-bullseye
before_script:
- apt-get update && apt-get install -y wget curl
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- apt-get install -y ./google-chrome-stable_current_amd64.deb
- export CHROME_BIN=/usr/bin/google-chrome
script:
- yarn install
- yarn test
build_image:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
# Принудительно запускаем без TLS на порту 2375
command: ['--tls=false']
variables:
# В K8s контейнеры внутри одного пода всегда видят друг друга на localhost
DOCKER_HOST: tcp://localhost:2375
DOCKER_TLS_CERTDIR: ''
before_script:
# КРИТИЧНО: Ждем, пока Docker поднимется, прежде чем слать команды
- |
for i in $(seq 1 30); do
if nc -z localhost 2375; then
echo "Docker is up and running!"
break
fi
echo "Waiting for Docker daemon..."
sleep 1
done
- echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
Вариант с кешированием
variables:
IMAGE_NAME: webmakaka/demo-app
IMAGE_TAG: juice-shop-1.1
stages:
- cache
- test
- build
create_cache:
image: node:22-bullseye
stage: cache
script:
- yarn install
cache:
key:
files:
- yarn.lock
paths:
- node_modules/
- yarn.lock
- .yarn
policy: pull-push
yarn_test:
stage: test
image: node:22-bullseye
before_script:
- apt-get update && apt-get install -y wget curl
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- apt-get install -y ./google-chrome-stable_current_amd64.deb
- export CHROME_BIN=/usr/bin/google-chrome
script:
- yarn install
- yarn test
cache:
key:
files:
- yarn.lock
paths:
- node_modules/
- yarn.lock
- .yarn
policy: pull
build_image:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
# Принудительно запускаем без TLS на порту 2375
command: ['--tls=false']
variables:
# В K8s контейнеры внутри одного пода всегда видят друг друга на localhost
DOCKER_HOST: tcp://localhost:2375
DOCKER_TLS_CERTDIR: ''
before_script:
# КРИТИЧНО: Ждем, пока Docker поднимется, прежде чем слать команды
- |
for i in $(seq 1 30); do
if nc -z localhost 2375; then
echo "Docker is up and running!"
break
fi
echo "Waiting for Docker daemon..."
sleep 1
done
- echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
04 - Pre-commit Hook for Secret Scanning & Integrating GitLeaks in CI Pipeline
.gitlab-ci.yml
variables:
IMAGE_NAME: webmakaka/demo-app
IMAGE_TAG: juice-shop-1.1
stages:
- test
- build
yarn_test:
stage: test
image: node:22-bullseye
before_script:
- apt-get update && apt-get install -y wget curl
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- apt-get install -y ./google-chrome-stable_current_amd64.deb
- export CHROME_BIN=/usr/bin/google-chrome
script:
- yarn install
- yarn test
gitleaks:
stage: test
image:
name: zricethezav/gitleaks
entrypoint: ['']
script:
- gitleaks detect --verbose --source .
allow_failure: true
build_image:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
# Принудительно запускаем без TLS на порту 2375
command: ['--tls=false']
variables:
# В K8s контейнеры внутри одного пода всегда видят друг друга на localhost
DOCKER_HOST: tcp://localhost:2375
DOCKER_TLS_CERTDIR: ''
before_script:
# КРИТИЧНО: Ждем, пока Docker поднимется, прежде чем слать команды
- |
for i in $(seq 1 30); do
if nc -z localhost 2375; then
echo "Docker is up and running!"
break
fi
echo "Waiting for Docker daemon..."
sleep 1
done
- echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
Запуск локально, чтобы пофиксить ошибки
$ cd ~/tmp/
$ git clone https://github.com/juice-shop/juice-shop
$ cd juice-shop
$ vi .git/hooks/pre-commit
docker pull zricethezav/gitleaks:latest
export path_to_host_folder_to_scan=/home/marley/tmp/juice-shop
docker run -v ${path_to_host_folder_to_scan}:/path zricethezav/gitleaks:latest detect --source="/path" --verbose
$ chmod +x .git/hooks/pre-commit
В файле .gitleaks.toml можно добавить правила.
[extend]
useDefault = true
[allowlist]
paths = ['test', '.*\/test\/.*']
06 - Integrate SAST Scans in Release Pipeline
.gitlab-ci.yml
variables:
IMAGE_NAME: webmakaka/demo-app
IMAGE_TAG: juice-shop-1.1
stages:
- test
- build
yarn_test:
stage: test
image: node:22-bullseye
before_script:
- apt-get update && apt-get install -y wget curl
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- apt-get install -y ./google-chrome-stable_current_amd64.deb
- export CHROME_BIN=/usr/bin/google-chrome
script:
- yarn install
- yarn test
gitleaks:
stage: test
image:
name: zricethezav/gitleaks
entrypoint: ['']
script:
- gitleaks detect --verbose --source .
allow_failure: true
njsscan:
stage: test
image: python:3.12
before_script:
- pip3 install --upgrade njsscan
script:
- njsscan --exit-warning .
allow_failure: true
semgrep:
stage: test
image: semgrep/semgrep
variables:
SEMGREP_RULES: p/javascript
script:
- semgrep ci
allow_failure: true
build_image:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
# Принудительно запускаем без TLS на порту 2375
command: ['--tls=false']
variables:
# В K8s контейнеры внутри одного пода всегда видят друг друга на localhost
DOCKER_HOST: tcp://localhost:2375
DOCKER_TLS_CERTDIR: ''
before_script:
# КРИТИЧНО: Ждем, пока Docker поднимется, прежде чем слать команды
- |
for i in $(seq 1 30); do
if nc -z localhost 2375; then
echo "Docker is up and running!"
break
fi
echo "Waiting for Docker daemon..."
sleep 1
done
- echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
Для semgrep, чтобы исключить файлы, можно использовать .semgrepignore