Skip to content

Commit 962d24a

Browse files
authored
Merge pull request #12 from nvsecurity/NV-4412-gitlab-export-pipeline
NV-4412 Emit the GitLab DAST report via nightvision export gitlab
2 parents 8834214 + 3f2e6cc commit 962d24a

1 file changed

Lines changed: 61 additions & 52 deletions

File tree

.gitlab-ci.yml

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,95 @@
1+
# NightVision DAST in GitLab CI.
2+
#
3+
# Extracts an OpenAPI spec from the Spring source, runs an authenticated DAST scan,
4+
# and emits a GitLab DAST report directly with the NightVision CLI's native
5+
# `nightvision export gitlab` command. No external converter and no Python toolchain:
6+
# the report is produced by the CLI and uploaded as a GitLab `dast` report.
7+
#
8+
# Requires a masked CI/CD variable NIGHTVISION_TOKEN (the demo setup script sets it).
9+
110
stages:
2-
- sast_scan
3-
- dast_scan
4-
- convert_sarif_to_gitlab
11+
- extract
12+
- scan
513

614
variables:
715
NIGHTVISION_TARGET: javaspringvulny-api-gitlab
816
NIGHTVISION_APP: javaspringvulny-api-gitlab
917
NIGHTVISION_AUTH: javaspringvulny-api-gitlab
10-
DOCKER_HOST: tcp://docker:2375/
18+
# Secure docker-in-docker: TLS on 2376 with generated client certs, not the
19+
# unauthenticated tcp://docker:2375 socket.
20+
DOCKER_HOST: tcp://docker:2376
21+
DOCKER_TLS_CERTDIR: "/certs"
22+
DOCKER_TLS_VERIFY: "1"
23+
DOCKER_CERT_PATH: "/certs/client"
1124
DOCKER_DRIVER: overlay2
12-
FF_NETWORK_PER_BUILD: "true" # activate container-to-container networking
25+
FF_NETWORK_PER_BUILD: "true" # container-to-container networking for the scan
1326

14-
services:
15-
- docker:dind
27+
# Run the full DAST scan only on the default branch or a manual ("Run pipeline")
28+
# trigger, so routine feature pushes do not each launch a scan.
29+
workflow:
30+
rules:
31+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
32+
- if: $CI_PIPELINE_SOURCE == "web"
1633

17-
sast_scan:
18-
stage: sast_scan
34+
extract_spec:
35+
stage: extract
1936
image: ubuntu:latest
20-
services:
21-
- docker:dind
2237
before_script:
23-
- apt-get update && apt-get install -y wget python3-venv python3-docker python3-pip python3 docker-compose curl gcc musl-dev libffi-dev
24-
- python3 -m venv venv
25-
- source venv/bin/activate
26-
- pip3 install requests urllib3 semgrep
38+
- apt-get update && apt-get install -y wget ca-certificates
2739
- wget -c https://downloads.nightvision.net/binaries/latest/nightvision_latest_linux_amd64.tar.gz -O - | tar -xz
2840
- mv nightvision /usr/local/bin/
2941
script:
30-
# "Extract API documentation from code"
31-
- nightvision swagger extract ./ --lang spring -t ${NIGHTVISION_APP} || true
32-
- if [ ! -e openapi-spec.yml ]; then cp backup-openapi-spec.yml openapi-spec.yml; fi
42+
# Extract the OpenAPI spec from the source. On failure, fall back to the
43+
# committed backup spec but log loudly so a real extraction failure is visible
44+
# (it is not silently masked the way `|| true` did).
45+
- |
46+
if nightvision swagger extract ./ --lang spring -t "${NIGHTVISION_APP}"; then
47+
echo "Spec extracted from source."
48+
else
49+
echo "WARNING: 'nightvision swagger extract' failed; using committed backup-openapi-spec.yml." >&2
50+
cp backup-openapi-spec.yml openapi-spec.yml
51+
fi
52+
# Guard on the artifact as well: a zero exit that wrote no spec (e.g. no
53+
# routes extracted) still falls back to the committed backup.
54+
[ -s openapi-spec.yml ] || cp backup-openapi-spec.yml openapi-spec.yml
3355
artifacts:
3456
paths:
3557
- openapi-spec.yml
3658
expire_in: 30 days
3759

3860
dast_scan:
39-
stage: dast_scan
61+
stage: scan
4062
image: ubuntu:latest
4163
services:
4264
- docker:dind
4365
before_script:
44-
- apt-get update && apt-get install -y wget python3-venv python3-docker python3-pip python3 docker-compose curl gcc musl-dev libffi-dev
45-
- python3 -m venv venv
46-
- source venv/bin/activate
47-
- pip3 install requests urllib3 semgrep
66+
- apt-get update && apt-get install -y wget ca-certificates docker.io docker-compose
4867
- wget -c https://downloads.nightvision.net/binaries/latest/nightvision_latest_linux_amd64.tar.gz -O - | tar -xz
4968
- mv nightvision /usr/local/bin/
5069
script:
51-
# "Starting the app"
70+
# Fail the job on a scan error even though the scan output is piped to tee:
71+
# without pipefail the pipeline's exit status would be tee's (always 0).
72+
- set -o pipefail
73+
# Start the target application.
5274
- docker-compose up -d
5375
- sleep 15
54-
# "Scanning the API"
55-
- nightvision scan ${NIGHTVISION_TARGET} -a ${NIGHTVISION_APP} --auth ${NIGHTVISION_AUTH} > scan-results.txt
56-
- nightvision export sarif -s "$(head -n 1 scan-results.txt)" --swagger-file openapi-spec.yml
57-
# "Getting logs"
58-
- for pod in $(docker ps | grep -v 'CONTAINER ID' | grep -v IMAGE | awk '{print $1}'); do docker logs $pod >> test.pod.logs 2>&1; done
76+
# Run the scan and capture its id robustly: extract the scan UUID from the
77+
# output (rather than assuming it is the first line) and fail loudly if none
78+
# is produced, instead of feeding an empty -s to the export.
79+
- nightvision scan "${NIGHTVISION_TARGET}" -a "${NIGHTVISION_APP}" --auth "${NIGHTVISION_AUTH}" | tee scan-results.txt
80+
- SCAN_ID=$(grep -oiE '[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}' scan-results.txt | head -n1)
81+
- 'test -n "${SCAN_ID}" || { echo "ERROR no scan id found in scan output" >&2; exit 1; }'
82+
# Native GitLab DAST report (replaces the former fetch-and-run Python converter).
83+
- nightvision export gitlab -s "${SCAN_ID}" --swagger-file openapi-spec.yml -o gl-dast-report.json
84+
after_script:
85+
# Best-effort container logs for debugging; never fail the job on log capture.
86+
- for pod in $(docker ps -q); do docker logs "$pod" >> test.pod.logs 2>&1 || true; done
5987
artifacts:
88+
reports:
89+
dast: gl-dast-report.json
6090
paths:
91+
- gl-dast-report.json
6192
- test.pod.logs
62-
- results.sarif
6393
expire_in: 30 days
6494
dependencies:
65-
- sast_scan
66-
67-
convert_sarif_to_gitlab:
68-
stage: convert_sarif_to_gitlab
69-
image: python:3.9
70-
script:
71-
# Fetch the converter from its single canonical location so this pipeline is
72-
# self-contained: a repo that copy-pastes only this YAML (without bundling the
73-
# Python script) still produces the report on this final stage. (NV-4418.)
74-
# -f makes curl fail loudly on an HTTP error so a missing/moved converter does not
75-
# silently produce an empty report.
76-
# POC limitation: this pins to the mutable 'main' branch (no tag/SHA or checksum),
77-
# so a converter change is picked up automatically. Pin to a tag/commit SHA before
78-
# promoting this pattern past the POC.
79-
# Phase 1 (NV-4412) replaces this fetch + script with `nightvision export gitlab`.
80-
- curl -sSfL https://raw.githubusercontent.com/nvsecurity/nv-public-reference/main/sarif/convert_sarif_to_gitlab.py -o convert_sarif_to_gitlab.py
81-
- python3 convert_sarif_to_gitlab.py
82-
artifacts:
83-
reports:
84-
sast: gitlab_security_report.json
85-
dependencies:
86-
- dast_scan
95+
- extract_spec

0 commit comments

Comments
 (0)