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