chapter 02
Setting Up
Setting up the vulnerable target, the two GitHub Actions workflows, and the SonarCloud account β everything that needs to exist before any gate can block anything.
1. Forking the vulnerable target
Juice Shop enters the repository as a fork + git submodule, not a direct copy β this preserves the original history and makes it clear the vulnerable code isn't ours, it's the target.
gh repo fork juice-shop/juice-shop --clone=false
git submodule add https://github.com/<your-username>/juice-shop.git target-app
git commit -m "Add OWASP Juice Shop fork as submodule (target-app)"
git push
2. Validate locally with Docker, before automating anything
Before writing any workflow, confirm the target boots and responds:
docker run --rm -p 3000:3000 bkimminich/juice-shop
Open http://localhost:3000 and confirm the Juice Shop login screen loads.
If port 3000 is already taken on your machine by another service, just use a different local port (-p 3001:3000) β this has zero effect on the real pipeline, since GitHub Actions runners are isolated and don't have that conflict.
3. Gitleaks: pre-commit + config
Two pieces: the local hook (runs before every commit on your machine) and the configuration/allowlist file.
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.2
hooks:
- id: gitleaks
pipx install pre-commit
pre-commit install
.gitleaks.toml extends Gitleaks' default rules and documents any needed exception β see chapter 04 for a real, justified exception case.
4. SonarCloud: account, project, and token
- Log in at sonarcloud.io via Log in β With GitHub.
- + (Analyze new project) β select the repository.
- Under My Account β Security, generate a token.
- In the GitHub repo: Settings β Secrets and variables β Actions β new secret
SONAR_TOKEN. - Under Project Settings β New Code, choose Number of days (30) as the new-code criterion β not "Previous version," since this repository has no formal release/tag process.
sonar.projectKey=<org>_secure-pipeline-poc
sonar.organization=<org>
sonar.exclusions=target-app/**
target-app/
Juice Shop already has known vulnerabilities on purpose and isn't "our" code β the gate should evaluate what we write in the pipeline, not the target.
5. OWASP ZAP: rules
The rules file controls what escalates to FAIL, what stays at WARN, and what gets ignored β more on how this actually behaves in chapter 04.
# Format: <rule id> <threshold> (description)
# IGNORE = don't report | WARN = report but don't fail | FAIL = report and fail the job
10038 FAIL (CSP Header Not Set)
6. The two workflows
With the target, Gitleaks, SonarCloud, and ZAP configured, all that's left is the workflows that connect them to the code lifecycle β pre-merge-gates.yml (Gitleaks + SonarCloud, on every PR) and pre-deploy-dast.yml (ZAP, manually triggered). The full content of each, and the reasoning behind every choice inside them, is in chapter 03.