diff --git a/ci/contexts/external.context b/ci/contexts/external.context
deleted file mode 100644
index 167ecff..0000000
--- a/ci/contexts/external.context
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-cloud.gov external conmon
-
- true
-
- https://account.fr.cloud.gov.*
- https://api.fr.cloud.gov.*
- https://cloud.gov.*
- https://dashboard.fr.cloud.gov.*
- https://idp.fr.cloud.gov.*
- https://login.fr.cloud.gov.*
- https://logs.fr.cloud.gov.*
- https://logs-beta.fr.cloud.gov.*
- mozilla\.com
- mozilla\.net
- mozilla\.org
- firefox\.com
- getpocket\.com
- cloudflare-dns\.com
- digitalgov\.gov
- elastic\.co
- grafana\.com
- jsdelivr\.net
- secureauth\.gsa\.gov
-
- Db.PostgreSQL
- Db.SQLite
- Language.JSP/Servlet
- Language.Java
- Language.JavaScript
- Language.Python
- Language.Ruby
- Language.XML
- OS.Linux
- SCM.Git
- WS.Tomcat
- Db
- Db.MySQL
- Db.CouchDB
- Db.Firebird
- Db.HypersonicSQL
- Db.IBM DB2
- Db.Microsoft Access
- Db.Microsoft SQL Server
- Db.MongoDB
- Db.Oracle
- Db.SAP MaxDB
- Db.Sybase
- Language
- Language.ASP
- Language.C
- Language.PHP
- OS
- OS.MacOS
- OS.Windows
- SCM
- SCM.SVN
- WS
- WS.Apache
- WS.IIS
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- 0
-
- -1
-
- 0
-
-
- 0
-
-
-
- AND
- -1
-
-
-
-
diff --git a/ci/contexts/internal.context b/ci/contexts/internal.context
deleted file mode 100644
index 53bf8af..0000000
--- a/ci/contexts/internal.context
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
- cloud.gov internal conmon
-
- true
-
- https://alertmanager.fr.cloud.gov.*
- https://ci.fr.cloud.gov.*
- https://grafana.fr.cloud.gov.*
- https://logs-platform.fr.cloud.gov.*
- https://opslogin.fr.cloud.gov.*
- https://prometheus.fr.cloud.gov.*
- https://doomsday.fr.cloud.gov.*
- mozilla\.com
- mozilla\.net
- mozilla\.org
- firefox\.com
- getpocket\.com
- cloudflare-dns\.com
- digitalgov\.gov
- elastic\.co
- grafana\.com
- jsdelivr\.net
- secureauth\.gsa\.gov
-
- Db.PostgreSQL
- Db.SQLite
- Language.JSP/Servlet
- Language.Java
- Language.JavaScript
- Language.Python
- Language.Ruby
- Language.XML
- OS.Linux
- SCM.Git
- WS.Tomcat
- Db
- Db.MySQL
- Db.CouchDB
- Db.Firebird
- Db.HypersonicSQL
- Db.IBM DB2
- Db.Microsoft Access
- Db.Microsoft SQL Server
- Db.MongoDB
- Db.Oracle
- Db.SAP MaxDB
- Db.Sybase
- Language
- Language.ASP
- Language.C
- Language.PHP
- OS
- OS.MacOS
- OS.Windows
- SCM
- SCM.SVN
- WS
- WS.Apache
- WS.IIS
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- 0
-
- -1
-
- 0
-
-
- 0
-
-
-
- AND
- -1
-
-
-
-
diff --git a/ci/contexts/pages.context b/ci/contexts/pages.context
deleted file mode 100644
index 17c2454..0000000
--- a/ci/contexts/pages.context
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
- cloud.gov pages conmon
-
-
- true
- https://pages-staging.cloud.gov.*
- https://pages.cloud.gov.*
- https://admin.pages-staging.cloud.gov.*
- https://admin.pages.cloud.gov.*
- mozilla\.com
- mozilla\.net
- mozilla\.org
- firefox\.com
- getpocket\.com
- cloudflare-dns\.com
- digitalgov\.gov
- elastic\.co
- grafana\.com
- jsdelivr\.net
- secureauth\.gsa\.gov
-
- Db.MySQL
- Db.PostgreSQL
- Db.SQLite
- Language.JSP/Servlet
- Language.Java
- Language.JavaScript
- Language.Python
- Language.Ruby
- Language.XML
- OS.Linux
- SCM.Git
- WS.Tomcat
- Db
- Db.CouchDB
- Db.Firebird
- Db.HypersonicSQL
- Db.IBM DB2
- Db.Microsoft Access
- Db.Microsoft SQL Server
- Db.MongoDB
- Db.Oracle
- Db.SAP MaxDB
- Db.Sybase
- Language
- Language.ASP
- Language.C
- Language.PHP
- OS
- OS.MacOS
- OS.Windows
- SCM
- SCM.SVN
- WS
- WS.Apache
- WS.IIS
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- 0
- EACH_RESP
-
-
-
- 60
- REQUESTS
-
- -1
-
- 0
-
-
- 0
-
-
-
- AND
- -1
-
-
-
-
diff --git a/ci/contexts/template.context.template b/ci/contexts/template.context.template
deleted file mode 100644
index 09f6c7c..0000000
--- a/ci/contexts/template.context.template
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
- cloud.gov {application_name} conmon
-
- true
- {app_url}
- mozilla\.com
- mozilla\.net
- mozilla\.org
- firefox\.com
- getpocket\.com
- cloudflare-dns\.com
- digitalgov\.gov
- elastic\.co
- grafana\.com
- jsdelivr\.net
- secureauth\.gsa\.gov
-
- Db.PostgreSQL
- Db.SQLite
- Language.JSP/Servlet
- Language.Java
- Language.JavaScript
- Language.Python
- Language.Ruby
- Language.XML
- OS.Linux
- SCM.Git
- WS.Tomcat
- Db
- Db.MySQL
- Db.CouchDB
- Db.Firebird
- Db.HypersonicSQL
- Db.IBM DB2
- Db.Microsoft Access
- Db.Microsoft SQL Server
- Db.MongoDB
- Db.Oracle
- Db.SAP MaxDB
- Db.Sybase
- Language
- Language.ASP
- Language.C
- Language.PHP
- OS
- OS.MacOS
- OS.Windows
- SCM
- SCM.SVN
- WS
- WS.Apache
- WS.IIS
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- 0
-
- -1
-
- 0
-
-
- 0
-
-
-
- AND
- -1
-
-
-
-
diff --git a/ci/contexts/unauthenticated.context b/ci/contexts/unauthenticated.context
deleted file mode 100644
index 776bc1f..0000000
--- a/ci/contexts/unauthenticated.context
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-Cloud.gov unauthenticated
-
- true
-
- https://idp.fr.cloud.gov.*
- mozilla\.com
- mozilla\.net
- mozilla\.org
- firefox\.com
- getpocket\.com
- cloudflare-dns\.com
- digitalgov\.gov
- elastic\.co
- grafana\.com
- jsdelivr\.net
- secureauth\.gsa\.gov
-
- Db.PostgreSQL
- Db.SQLite
- Language.JSP/Servlet
- Language.Java
- Language.JavaScript
- Language.Python
- Language.Ruby
- Language.XML
- OS.Linux
- SCM.Git
- WS.Tomcat
- Db
- Db.MySQL
- Db.CouchDB
- Db.Firebird
- Db.HypersonicSQL
- Db.IBM DB2
- Db.Microsoft Access
- Db.Microsoft SQL Server
- Db.MongoDB
- Db.Oracle
- Db.SAP MaxDB
- Db.Sybase
- Language
- Language.ASP
- Language.C
- Language.PHP
- OS
- OS.MacOS
- OS.Windows
- SCM
- SCM.SVN
- WS
- WS.Apache
- WS.IIS
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- org.zaproxy.zap.model.StandardParameterParser
- {"kvps":"&","kvs":"=","struct":[]}
-
-
- 0
-
- -1
-
- 0
-
-
- 0
-
-
-
- AND
- -1
-
-
-
-
diff --git a/ci/pipeline.yml b/ci/pipeline.yml
index 39a511d..ddbecef 100644
--- a/ci/pipeline.yml
+++ b/ci/pipeline.yml
@@ -13,20 +13,22 @@ jobs:
- name: scan-all-contexts
plan:
- - get: ((repo_name))
+ - get: zap-config
+ trigger: true
+
+ - get: zap-runner
trigger: true
passed: [set-self]
- across:
- var: mode
- values: ["unauthenticated"]
- # To scan all contexts in parallel, uncomment & adjust:
- # values: ["internal","external","pages","app","unauthenticated"]
- max_in_flight: all
+ # will loop 4 contexts, but scan only those URLs present
+ values: ["internal", "external", "pages", "unauthenticated"]
+ max_in_flight: all
fail_fast: false
do:
- task: zap-scan
- file: ((repo_name))/ci/tasks/zap-scan.yml
+ file: zap-runner/ci/tasks/zap-scan.yml
vars:
repo_name: ((repo_name))
runner_tag: ((runner_tag))
@@ -41,7 +43,7 @@ groups:
- scan-all-contexts
resources:
- - name: ((repo_name))
+ - name: zap-runner
type: git
source:
uri: https://github.com/cloud-gov/((repo_name))
@@ -49,6 +51,14 @@ resources:
commit_verification_keys: ((cloud-gov-pgp-keys))
ignore_paths: ["Dockerfile"]
+ - name: zap-config
+ type: git
+ source:
+ uri: https://github.com/cloud-gov/zap-runner
+ branch: main
+ paths:
+ - ci/zap-config/**
+
# - name: daily
# type: time
# source:
diff --git a/ci/tasks/zap-scan.yml b/ci/tasks/zap-scan.yml
index 6dbc1f3..df7df33 100644
--- a/ci/tasks/zap-scan.yml
+++ b/ci/tasks/zap-scan.yml
@@ -1,4 +1,3 @@
-# ci/tasks/zap-scan.yml
---
platform: linux
@@ -12,6 +11,7 @@ image_resource:
tag: ((runner_tag))
inputs:
+ - name: zap-config
- name: ((repo_name))
outputs:
@@ -20,41 +20,57 @@ outputs:
params:
SCAN_MODE:
CREDHB_CRED:
+ repo_name:
+ runner_tag:
run:
path: bash
args:
- - -ceu
+ - -ceux
- |
- echo "Starting scan in mode: $SCAN_MODE"
- CONTEXT_FILE="((repo_name))/ci/contexts/${SCAN_MODE}.context"
- if [[ ! -f "$CONTEXT_FILE" ]]; then
- echo "ERROR: context file not found: $CONTEXT_FILE" >&2
- exit 1
- fi
+ #!/usr/bin/env bash
+
+ echo "Scanning all URLs in context '${SCAN_MODE}' as a single batch"
+
+ # 1) Extract credentials
+ CLIENT_ID=$(jq -r .client_id <<<"$CREDHB_CRED")
+ CLIENT_SECRET=$(jq -r .client_secret <<<"$CREDHB_CRED")
+ TOKEN_URI=$(jq -r .token_uri <<<"$CREDHB_CRED")
- # extract first URL as the quick-start URL
- QUICK_URL=$(grep -m1 '' "$CONTEXT_FILE" \
- | sed -E 's/.*>([^<]+)<.*/\1/')
- echo "Using quick URL: $QUICK_URL"
-
- auth_header=""
- if [[ "$SCAN_MODE" != "unauthenticated" ]]; then
- client_id=$(jq -r .client_id <<<"$CREDHB_CRED")
- client_secret=$(jq -r .client_secret <<<"$CREDHB_CRED")
- token_uri=$(jq -r .token_uri <<<"$CREDHB_CRED")
- token=$(curl -s -u "$client_id:$client_secret" \
- -d 'grant_type=client_credentials' \
- "$token_uri" | jq -r .access_token)
- auth_header="-authheader \"Authorization: Bearer $token\""
+ # 2) Gather URLs for this context
+ mapfile -t URLS < <(
+ tail -n +2 zap-config/urls.csv | \
+ awk -F',' -v ctx="$SCAN_MODE" '$1==ctx { print $2 }'
+ )
+
+ if [ ${#URLS[@]} -eq 0 ]; then
+ echo "No URLs for context '$SCAN_MODE', skipping."
+ exit 0
fi
+ echo "URLs to scan: ${URLS[*]}"
+
+ # 3) Build zap-baseline.py target flags
+ TARGET_ARGS=()
+ for url in "${URLS[@]}"; do
+ TARGET_ARGS+=( -t "$url" )
+ done
+
+ # 4) Create output directory
mkdir -p zap-report
- zap.sh -cmd \
- -context "$CONTEXT_FILE" \
- -quickurl "$QUICK_URL" \
- $auth_header \
- -r zap-report/report-${SCAN_MODE}.html \
- -J zap-report/report-${SCAN_MODE}.json
-
- echo "Scan complete; reports in zap-report/"
+
+ # 5) Define output files
+ HTML_OUT="zap-report/${SCAN_MODE}.html"
+ JSON_OUT="zap-report/${SCAN_MODE}.json"
+ XML_OUT="zap-report/${SCAN_MODE}.xml"
+
+ # 6) Run ZAP baseline with HTML, JSON, and XML outputs
+ zap-baseline.py \
+ "${TARGET_ARGS[@]}" \
+ -c zap-config/zap.yaml \
+ -r "$HTML_OUT" \
+ -J "$JSON_OUT" \
+ -x "$XML_OUT" \
+ -t "${CLIENT_ID}:${CLIENT_SECRET}:${TOKEN_URI}"
+
+ echo "Context scan '${SCAN_MODE}' complete: $HTML_OUT, $JSON_OUT, $XML_OUT"
diff --git a/ci/zap-config/urls.csv b/ci/zap-config/urls.csv
new file mode 100644
index 0000000..4203295
--- /dev/null
+++ b/ci/zap-config/urls.csv
@@ -0,0 +1,8 @@
+context,url
+internal,https://internal1.cloud.gov
+internal,https://internal2.cloud.gov
+external,https://public-api.cloud.gov
+pages,https://pages-staging.cloud.gov
+pages,https://pages.cloud.gov
+unauthenticated,https://login.fr.cloud.gov
+unauthenticated,https://idp.fr.cloud.gov
diff --git a/ci/zap-config/zap.yaml b/ci/zap-config/zap.yaml
new file mode 100644
index 0000000..5a82f04
--- /dev/null
+++ b/ci/zap-config/zap.yaml
@@ -0,0 +1,101 @@
+name: "Juice Shop Full DAST"
+description: "Traditional & AJAX Spider, Passive & Active scanning with multi-format reports"
+
+progressToStdout: true # Stream progress to console
+
+name: "Context-Aware DAST"
+description: "Spider + Active/Passive scan per URL with multi-format reports"
+progressToStdout: true
+
+jobs:
+ - type: spider
+ parameters:
+ maxDepth: 5
+ threadCount: 2
+
+ - type: passiveScan-config
+ parameters:
+ maxAlertsPerRule: 10
+ scanOnlyInScope: true
+
+ - type: passiveScan-wait
+ parameters:
+ maxDuration: 60
+
+ - type: activeScan
+ parameters:
+ policy: "Default Policy"
+ maxScanDurationInMins: 0
+
+ - type: report
+ parameters:
+ template: "traditional-html"
+ reportDir: "/zap/wrk"
+ reportFile: "{{yyyy-MM-dd}}-[[site]]-html.html"
+ displayReport: false
+ risks:
+ - high
+ - medium
+ - low
+ # - info
+ confidences:
+ - high
+ - medium
+# - low
+# - falsepositive
+
+ - type: report
+ parameters:
+ template: "traditional-json"
+ reportDir: "/zap/wrk"
+ reportFile: "{{yyyy-MM-dd}}-[[site]]-json.json"
+ displayReport: false
+ risks:
+ - high
+ - medium
+ - low
+ # - info
+ confidences:
+ - high
+ - medium
+ # - low
+ # - falsepositive
+
+ - type: report
+ parameters:
+ template: "traditional-xml"
+ reportDir: "/zap/wrk"
+ reportFile: "{{yyyy-MM-dd}}-[[site]]-xml.xml"
+ displayReport: false
+ risks:
+ - high
+ - medium
+ - low
+ # - info
+ confidences:
+ - high
+ - medium
+ # - low
+ # - falsepositive
+
+ - type: report
+ parameters:
+ template: "sarif-json"
+ reportDir: "/zap/wrk"
+ reportFile: "{{yyyy-MM-dd}}-[[site]]-sarif.sarif.json"
+ displayReport: false
+ risks:
+ - high
+ - medium
+ - low
+ # - info
+ confidences:
+ - high
+ - medium
+ # - low
+ # - falsepositive
+
+ - type: exitStatus
+ parameters:
+ warnLevel: MEDIUM
+ errorLevel: HIGH