From 77c5acd442ec1e8cda3008cd1643555e20364e01 Mon Sep 17 00:00:00 2001 From: sandhi Date: Tue, 3 Mar 2026 13:09:39 +0530 Subject: [PATCH 01/16] Fixes for PR scans Signed-off-by: sandhi --- .github/workflows/trufflehog.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/trufflehog.yml b/.github/workflows/trufflehog.yml index 59547b5..ce2e4e6 100644 --- a/.github/workflows/trufflehog.yml +++ b/.github/workflows/trufflehog.yml @@ -31,6 +31,7 @@ jobs: uses: actions/checkout@v6 with: fetch-depth: 0 + ref: ${{ inputs.github-branch-name }} - name: Setup git refs for PR scan if: ${{ inputs.github-event-name == 'pull_request' }} From 1e3696ae0023e9d0c2bb34ce62c6d95d96c6dff9 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 16:52:05 +0530 Subject: [PATCH 02/16] test blackduck sca Signed-off-by: Vipin Yadav --- .github/workflows/ci-main-pull-request.yml | 3 ++- .github/workflows/sbom.yml | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-main-pull-request.yml b/.github/workflows/ci-main-pull-request.yml index 2e0f7c5..f8dd2e4 100644 --- a/.github/workflows/ci-main-pull-request.yml +++ b/.github/workflows/ci-main-pull-request.yml @@ -1460,10 +1460,11 @@ jobs: name: 'Generating SBOM' # Create software bill-of-materials (SBOM) using SPDX format if: ${{ inputs.generate-sbom == true }} - uses: chef/common-github-actions/.github/workflows/sbom.yml@main + uses: chef/common-github-actions/.github/workflows/sbom.yml@test-pipeline # TODO: revert to @main after merging needs: checkout # TODO: fix set-application-version secrets: inherit with: + github-event-name: ${{ inputs.github-event-name }} version: ${{ inputs.version }} export-github-sbom: ${{ inputs.export-github-sbom }} perform-blackduck-sca-scan: ${{ inputs.perform-blackduck-sca-scan }} diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 432be9f..9a3413c 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -29,6 +29,11 @@ name: Download SBOM from Insights and Convert to CSV on: workflow_call: inputs: + github-event-name: + description: 'GitHub event name (pass github.event_name from calling workflow)' + required: false + type: string + default: '' version: description: 'Version of the project' required: true @@ -212,7 +217,7 @@ jobs: steps: - name: 'Echo inputs' run: | - echo "Starting BlackDuck SCA scan" + echo "Starting BlackDuck SCA scan on branch: ${{ github.ref_name }} (event: ${{ inputs.github-event-name }})" echo "BlackDuck_SCA_URL: ${{ secrets.BLACKDUCK_SBOM_URL }}" echo "BLACKDUCK_SCA_TOKEN: ${{ secrets.BLACKDUCK_SCA_TOKEN }}" echo "DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }}" @@ -320,7 +325,7 @@ jobs: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} - blackducksca_scan_full: true # Force INTELLIGENT scan mode for all branches (uploads results to server) + blackducksca_scan_full: ${{ inputs.github-event-name != 'pull_request' }} # INTELLIGENT scan for main/release branches; RAPID (policy-check only) for PRs detect_args: ${{ env.DETECT_ARGS }} # ignore python per https://documentation.blackduck.com/bundle/detect/page/packagemgrs/python.html From 275511090596fc9620df82bcb2f2fa9ccb63c689 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 17:29:40 +0530 Subject: [PATCH 03/16] test-output Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 97 ++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 9 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 9a3413c..36b7b5a 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -333,26 +333,105 @@ jobs: if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | BRIDGE_LOG=".bridge/bridge.log" + BLOCKER_COUNT=0 + CRITICAL_COUNT=0 + MAJOR_COUNT=0 + SCAN_MODE="unknown" if [ ! -f "$BRIDGE_LOG" ]; then - echo "⚠️ Bridge log not found" + echo "⚠️ Bridge log not found at $BRIDGE_LOG" + echo "Files in .bridge/ directory (if any):" + find .bridge -type f 2>/dev/null || echo " (no .bridge directory found)" exit 0 fi + echo "--- Bridge log tail (last 60 lines) ---" + tail -60 "$BRIDGE_LOG" + echo "--- End of bridge log tail ---" + echo "" + + # ── Strategy 1: Full / INTELLIGENT scan ────────────────────────────── + # Full scan emits: "Policy Severity counts: X match(es) have a severity level of BLOCKER ..." SEVERITY_LINE=$(grep "Policy Severity counts:" "$BRIDGE_LOG" || true) - - if [ -z "$SEVERITY_LINE" ]; then - echo "⚠️ Policy Severity counts line not found in bridge.log" + if [ -n "$SEVERITY_LINE" ]; then + SCAN_MODE="full" + BLOCKER_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' | grep -oE '^[0-9]+' || echo "0") + CRITICAL_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' | grep -oE '^[0-9]+' || echo "0") + MAJOR_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' | grep -oE '^[0-9]+' || echo "0") + fi + + # ── Strategy 2: RAPID scan (PR mode) ───────────────────────────────── + # RAPID scan logs the API response JSON which contains per-severity counts. + # Pattern A: {"BLOCKER":{"count":N},"CRITICAL":{"count":N},"MAJOR":{"count":N}} + if [ "$SCAN_MODE" == "unknown" ]; then + BLOCKER_JSON=$(grep -oP '"BLOCKER"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) + CRITICAL_JSON=$(grep -oP '"CRITICAL"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) + MAJOR_JSON=$(grep -oP '"MAJOR"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) + if [ -n "$BLOCKER_JSON" ] || [ -n "$CRITICAL_JSON" ] || [ -n "$MAJOR_JSON" ]; then + SCAN_MODE="rapid-json-a" + BLOCKER_COUNT="${BLOCKER_JSON:-0}" + CRITICAL_COUNT="${CRITICAL_JSON:-0}" + MAJOR_COUNT="${MAJOR_JSON:-0}" + fi + fi + + # Pattern B: "violatedPolicies" JSON array – count entries by severity + if [ "$SCAN_MODE" == "unknown" ]; then + BLOCKER_COUNT=$(grep -o '"severity":"BLOCKER"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") + CRITICAL_COUNT=$(grep -o '"severity":"CRITICAL"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") + MAJOR_COUNT=$(grep -o '"severity":"MAJOR"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") + if [ "$BLOCKER_COUNT" -gt 0 ] || [ "$CRITICAL_COUNT" -gt 0 ] || [ "$MAJOR_COUNT" -gt 0 ]; then + SCAN_MODE="rapid-json-b" + fi + fi + + # Pattern C: "X BLOCKER policy violation(s)" plain-text summary lines + if [ "$SCAN_MODE" == "unknown" ]; then + BLOCKER_LINE=$(grep -iE '[0-9]+ BLOCKER' "$BRIDGE_LOG" | tail -1 || true) + CRITICAL_LINE=$(grep -iE '[0-9]+ CRITICAL' "$BRIDGE_LOG" | tail -1 || true) + MAJOR_LINE=$(grep -iE '[0-9]+ MAJOR' "$BRIDGE_LOG" | tail -1 || true) + BLOCKER_COUNT=$(echo "$BLOCKER_LINE" | grep -oE '^[0-9]+' || echo "0") + CRITICAL_COUNT=$(echo "$CRITICAL_LINE" | grep -oE '^[0-9]+' || echo "0") + MAJOR_COUNT=$(echo "$MAJOR_LINE" | grep -oE '^[0-9]+' || echo "0") + if [ -n "$BLOCKER_LINE" ] || [ -n "$CRITICAL_LINE" ] || [ -n "$MAJOR_LINE" ]; then + SCAN_MODE="rapid-text" + fi + fi + + # ── Strategy 3: JSON output files produced by Bridge in .bridge/ ───── + # RAPID scan results are sometimes written to .bridge/blackducksca/ as JSON + if [ "$SCAN_MODE" == "unknown" ]; then + RESULT_JSON=$(find .bridge -name "*.json" -not -name "input.json" 2>/dev/null | head -1 || true) + if [ -n "$RESULT_JSON" ]; then + echo "Found Bridge output JSON: $RESULT_JSON" + BLOCKER_COUNT=$(grep -oP '"BLOCKER"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") + CRITICAL_COUNT=$(grep -oP '"CRITICAL"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") + MAJOR_COUNT=$(grep -oP '"MAJOR"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") + [ -z "$BLOCKER_COUNT" ] && BLOCKER_COUNT="0" + [ -z "$CRITICAL_COUNT" ] && CRITICAL_COUNT="0" + [ -z "$MAJOR_COUNT" ] && MAJOR_COUNT="0" + SCAN_MODE="bridge-json-file" + fi + fi + + if [ "$SCAN_MODE" == "unknown" ]; then + echo "⚠️ Could not extract policy violation counts from bridge.log using any known pattern." + echo " Review the bridge log tail printed above to identify the correct format." + echo "" + echo "Files found in .bridge/ directory:" + find .bridge -type f 2>/dev/null || echo " (none)" exit 0 fi - - BLOCKER_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' | grep -oE '^[0-9]+' || echo "0") - + + # Ensure counts are numeric + BLOCKER_COUNT=$(echo "${BLOCKER_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") + CRITICAL_COUNT=$(echo "${CRITICAL_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") + MAJOR_COUNT=$(echo "${MAJOR_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") + echo "" echo "============================================" echo "BlackDuck SCA Policy Violation Summary" + echo "Scan mode: $SCAN_MODE" echo "============================================" echo "BLOCKER violations: $BLOCKER_COUNT" echo "CRITICAL violations: $CRITICAL_COUNT" From 54dbcb384b082e45fd905b771eba9419fc598d40 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 17:38:18 +0530 Subject: [PATCH 04/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 36b7b5a..5a04347 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -398,19 +398,34 @@ jobs: fi fi - # ── Strategy 3: JSON output files produced by Bridge in .bridge/ ───── - # RAPID scan results are sometimes written to .bridge/blackducksca/ as JSON + # ── Strategy 3: DeveloperMode (RAPID scan) JSON result file ───────── + # RAPID scan writes a *_BlackDuck_DeveloperMode_Result.json file. + # Structure: array of components, each with a "violatingPolicies" array + # where each entry has a "policySeverity" field (BLOCKER/CRITICAL/MAJOR/etc.) if [ "$SCAN_MODE" == "unknown" ]; then - RESULT_JSON=$(find .bridge -name "*.json" -not -name "input.json" 2>/dev/null | head -1 || true) + RESULT_JSON=$(find .bridge -name "*DeveloperMode_Result*.json" -o -name "*rapid*.json" 2>/dev/null | head -1 || true) + # Fallback: any non-input JSON in .bridge + if [ -z "$RESULT_JSON" ]; then + RESULT_JSON=$(find .bridge -name "*.json" -not -name "input.json" 2>/dev/null | head -1 || true) + fi if [ -n "$RESULT_JSON" ]; then echo "Found Bridge output JSON: $RESULT_JSON" - BLOCKER_COUNT=$(grep -oP '"BLOCKER"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") - CRITICAL_COUNT=$(grep -oP '"CRITICAL"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") - MAJOR_COUNT=$(grep -oP '"MAJOR"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$RESULT_JSON" | tail -1 || echo "0") + # Primary: use jq if available (accurate, handles nested arrays) + if command -v jq &>/dev/null; then + BLOCKER_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "BLOCKER")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") + CRITICAL_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "CRITICAL")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") + MAJOR_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "MAJOR")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") + SCAN_MODE="rapid-json-jq" + else + # Fallback: count "policySeverity":"SEVERITY" occurrences via grep + BLOCKER_COUNT=$(grep -o '"policySeverity"\s*:\s*"BLOCKER"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") + CRITICAL_COUNT=$(grep -o '"policySeverity"\s*:\s*"CRITICAL"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") + MAJOR_COUNT=$(grep -o '"policySeverity"\s*:\s*"MAJOR"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") + SCAN_MODE="rapid-json-grep" + fi [ -z "$BLOCKER_COUNT" ] && BLOCKER_COUNT="0" [ -z "$CRITICAL_COUNT" ] && CRITICAL_COUNT="0" [ -z "$MAJOR_COUNT" ] && MAJOR_COUNT="0" - SCAN_MODE="bridge-json-file" fi fi From c258d853cc46ed65807c8feddb3feb2316cd20f4 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 18:05:00 +0530 Subject: [PATCH 05/16] test Signed-off-by: Vipin Yadav --- .github/workflows/ci-main-pull-request.yml | 3 +- .github/workflows/sbom.yml | 121 ++------------------- .github/workflows/trufflehog.yml | 7 +- 3 files changed, 18 insertions(+), 113 deletions(-) diff --git a/.github/workflows/ci-main-pull-request.yml b/.github/workflows/ci-main-pull-request.yml index f8dd2e4..2e0f7c5 100644 --- a/.github/workflows/ci-main-pull-request.yml +++ b/.github/workflows/ci-main-pull-request.yml @@ -1460,11 +1460,10 @@ jobs: name: 'Generating SBOM' # Create software bill-of-materials (SBOM) using SPDX format if: ${{ inputs.generate-sbom == true }} - uses: chef/common-github-actions/.github/workflows/sbom.yml@test-pipeline # TODO: revert to @main after merging + uses: chef/common-github-actions/.github/workflows/sbom.yml@main needs: checkout # TODO: fix set-application-version secrets: inherit with: - github-event-name: ${{ inputs.github-event-name }} version: ${{ inputs.version }} export-github-sbom: ${{ inputs.export-github-sbom }} perform-blackduck-sca-scan: ${{ inputs.perform-blackduck-sca-scan }} diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 5a04347..432be9f 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -29,11 +29,6 @@ name: Download SBOM from Insights and Convert to CSV on: workflow_call: inputs: - github-event-name: - description: 'GitHub event name (pass github.event_name from calling workflow)' - required: false - type: string - default: '' version: description: 'Version of the project' required: true @@ -217,7 +212,7 @@ jobs: steps: - name: 'Echo inputs' run: | - echo "Starting BlackDuck SCA scan on branch: ${{ github.ref_name }} (event: ${{ inputs.github-event-name }})" + echo "Starting BlackDuck SCA scan" echo "BlackDuck_SCA_URL: ${{ secrets.BLACKDUCK_SBOM_URL }}" echo "BLACKDUCK_SCA_TOKEN: ${{ secrets.BLACKDUCK_SCA_TOKEN }}" echo "DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }}" @@ -325,7 +320,7 @@ jobs: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} - blackducksca_scan_full: ${{ inputs.github-event-name != 'pull_request' }} # INTELLIGENT scan for main/release branches; RAPID (policy-check only) for PRs + blackducksca_scan_full: true # Force INTELLIGENT scan mode for all branches (uploads results to server) detect_args: ${{ env.DETECT_ARGS }} # ignore python per https://documentation.blackduck.com/bundle/detect/page/packagemgrs/python.html @@ -333,120 +328,26 @@ jobs: if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | BRIDGE_LOG=".bridge/bridge.log" - BLOCKER_COUNT=0 - CRITICAL_COUNT=0 - MAJOR_COUNT=0 - SCAN_MODE="unknown" if [ ! -f "$BRIDGE_LOG" ]; then - echo "⚠️ Bridge log not found at $BRIDGE_LOG" - echo "Files in .bridge/ directory (if any):" - find .bridge -type f 2>/dev/null || echo " (no .bridge directory found)" + echo "⚠️ Bridge log not found" exit 0 fi - echo "--- Bridge log tail (last 60 lines) ---" - tail -60 "$BRIDGE_LOG" - echo "--- End of bridge log tail ---" - echo "" - - # ── Strategy 1: Full / INTELLIGENT scan ────────────────────────────── - # Full scan emits: "Policy Severity counts: X match(es) have a severity level of BLOCKER ..." SEVERITY_LINE=$(grep "Policy Severity counts:" "$BRIDGE_LOG" || true) - if [ -n "$SEVERITY_LINE" ]; then - SCAN_MODE="full" - BLOCKER_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' | grep -oE '^[0-9]+' || echo "0") - fi - - # ── Strategy 2: RAPID scan (PR mode) ───────────────────────────────── - # RAPID scan logs the API response JSON which contains per-severity counts. - # Pattern A: {"BLOCKER":{"count":N},"CRITICAL":{"count":N},"MAJOR":{"count":N}} - if [ "$SCAN_MODE" == "unknown" ]; then - BLOCKER_JSON=$(grep -oP '"BLOCKER"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) - CRITICAL_JSON=$(grep -oP '"CRITICAL"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) - MAJOR_JSON=$(grep -oP '"MAJOR"\s*:\s*\{\s*"count"\s*:\s*\K[0-9]+' "$BRIDGE_LOG" | tail -1 || true) - if [ -n "$BLOCKER_JSON" ] || [ -n "$CRITICAL_JSON" ] || [ -n "$MAJOR_JSON" ]; then - SCAN_MODE="rapid-json-a" - BLOCKER_COUNT="${BLOCKER_JSON:-0}" - CRITICAL_COUNT="${CRITICAL_JSON:-0}" - MAJOR_COUNT="${MAJOR_JSON:-0}" - fi - fi - - # Pattern B: "violatedPolicies" JSON array – count entries by severity - if [ "$SCAN_MODE" == "unknown" ]; then - BLOCKER_COUNT=$(grep -o '"severity":"BLOCKER"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") - CRITICAL_COUNT=$(grep -o '"severity":"CRITICAL"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") - MAJOR_COUNT=$(grep -o '"severity":"MAJOR"' "$BRIDGE_LOG" | wc -l | tr -d ' ' || echo "0") - if [ "$BLOCKER_COUNT" -gt 0 ] || [ "$CRITICAL_COUNT" -gt 0 ] || [ "$MAJOR_COUNT" -gt 0 ]; then - SCAN_MODE="rapid-json-b" - fi - fi - - # Pattern C: "X BLOCKER policy violation(s)" plain-text summary lines - if [ "$SCAN_MODE" == "unknown" ]; then - BLOCKER_LINE=$(grep -iE '[0-9]+ BLOCKER' "$BRIDGE_LOG" | tail -1 || true) - CRITICAL_LINE=$(grep -iE '[0-9]+ CRITICAL' "$BRIDGE_LOG" | tail -1 || true) - MAJOR_LINE=$(grep -iE '[0-9]+ MAJOR' "$BRIDGE_LOG" | tail -1 || true) - BLOCKER_COUNT=$(echo "$BLOCKER_LINE" | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "$CRITICAL_LINE" | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "$MAJOR_LINE" | grep -oE '^[0-9]+' || echo "0") - if [ -n "$BLOCKER_LINE" ] || [ -n "$CRITICAL_LINE" ] || [ -n "$MAJOR_LINE" ]; then - SCAN_MODE="rapid-text" - fi - fi - - # ── Strategy 3: DeveloperMode (RAPID scan) JSON result file ───────── - # RAPID scan writes a *_BlackDuck_DeveloperMode_Result.json file. - # Structure: array of components, each with a "violatingPolicies" array - # where each entry has a "policySeverity" field (BLOCKER/CRITICAL/MAJOR/etc.) - if [ "$SCAN_MODE" == "unknown" ]; then - RESULT_JSON=$(find .bridge -name "*DeveloperMode_Result*.json" -o -name "*rapid*.json" 2>/dev/null | head -1 || true) - # Fallback: any non-input JSON in .bridge - if [ -z "$RESULT_JSON" ]; then - RESULT_JSON=$(find .bridge -name "*.json" -not -name "input.json" 2>/dev/null | head -1 || true) - fi - if [ -n "$RESULT_JSON" ]; then - echo "Found Bridge output JSON: $RESULT_JSON" - # Primary: use jq if available (accurate, handles nested arrays) - if command -v jq &>/dev/null; then - BLOCKER_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "BLOCKER")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") - CRITICAL_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "CRITICAL")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") - MAJOR_COUNT=$(jq '[.. | objects | select(has("policySeverity")) | .policySeverity] | map(select(. == "MAJOR")) | length' "$RESULT_JSON" 2>/dev/null || echo "0") - SCAN_MODE="rapid-json-jq" - else - # Fallback: count "policySeverity":"SEVERITY" occurrences via grep - BLOCKER_COUNT=$(grep -o '"policySeverity"\s*:\s*"BLOCKER"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") - CRITICAL_COUNT=$(grep -o '"policySeverity"\s*:\s*"CRITICAL"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") - MAJOR_COUNT=$(grep -o '"policySeverity"\s*:\s*"MAJOR"' "$RESULT_JSON" | wc -l | tr -d ' ' || echo "0") - SCAN_MODE="rapid-json-grep" - fi - [ -z "$BLOCKER_COUNT" ] && BLOCKER_COUNT="0" - [ -z "$CRITICAL_COUNT" ] && CRITICAL_COUNT="0" - [ -z "$MAJOR_COUNT" ] && MAJOR_COUNT="0" - fi - fi - - if [ "$SCAN_MODE" == "unknown" ]; then - echo "⚠️ Could not extract policy violation counts from bridge.log using any known pattern." - echo " Review the bridge log tail printed above to identify the correct format." - echo "" - echo "Files found in .bridge/ directory:" - find .bridge -type f 2>/dev/null || echo " (none)" + + if [ -z "$SEVERITY_LINE" ]; then + echo "⚠️ Policy Severity counts line not found in bridge.log" exit 0 fi - - # Ensure counts are numeric - BLOCKER_COUNT=$(echo "${BLOCKER_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "${CRITICAL_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "${MAJOR_COUNT:-0}" | grep -oE '^[0-9]+' || echo "0") - + + BLOCKER_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' | grep -oE '^[0-9]+' || echo "0") + CRITICAL_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' | grep -oE '^[0-9]+' || echo "0") + MAJOR_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' | grep -oE '^[0-9]+' || echo "0") + echo "" echo "============================================" echo "BlackDuck SCA Policy Violation Summary" - echo "Scan mode: $SCAN_MODE" echo "============================================" echo "BLOCKER violations: $BLOCKER_COUNT" echo "CRITICAL violations: $CRITICAL_COUNT" diff --git a/.github/workflows/trufflehog.yml b/.github/workflows/trufflehog.yml index ce2e4e6..6e9901d 100644 --- a/.github/workflows/trufflehog.yml +++ b/.github/workflows/trufflehog.yml @@ -31,7 +31,12 @@ jobs: uses: actions/checkout@v6 with: fetch-depth: 0 - ref: ${{ inputs.github-branch-name }} + + - name: Setup git refs for PR scan + if: ${{ inputs.github-event-name == 'pull_request' }} + run: | + git fetch origin main + git branch main origin/main - name: Setup git refs for PR scan if: ${{ inputs.github-event-name == 'pull_request' }} From 4ea35e4b38279fa09479a110945d9a7257c6168a Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 18:11:21 +0530 Subject: [PATCH 06/16] test Signed-off-by: Vipin Yadav --- .github/workflows/ci-main-pull-request.yml | 3 +- .github/workflows/sbom.yml | 44 +++++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-main-pull-request.yml b/.github/workflows/ci-main-pull-request.yml index 2e0f7c5..94be0ca 100644 --- a/.github/workflows/ci-main-pull-request.yml +++ b/.github/workflows/ci-main-pull-request.yml @@ -1460,10 +1460,11 @@ jobs: name: 'Generating SBOM' # Create software bill-of-materials (SBOM) using SPDX format if: ${{ inputs.generate-sbom == true }} - uses: chef/common-github-actions/.github/workflows/sbom.yml@main + uses: chef/common-github-actions/.github/workflows/sbom.yml@test-pipeline needs: checkout # TODO: fix set-application-version secrets: inherit with: + github-event-name: ${{ github.event_name }} version: ${{ inputs.version }} export-github-sbom: ${{ inputs.export-github-sbom }} perform-blackduck-sca-scan: ${{ inputs.perform-blackduck-sca-scan }} diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 432be9f..28d651c 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -307,22 +307,46 @@ jobs: echo "FAILURE_SEVERITIES=${SEVERITIES}" >> $GITHUB_ENV echo "Enforcement policy: ${SEVERITIES}" - - name: BlackDuck SCA scan - id: blackduck-scan + # Full / INTELLIGENT scan — push to main, develop, release branches. + # Persists a baseline to the BlackDuck server so PR scans can diff against it. + - name: BlackDuck SCA Full Scan + id: blackduck-full-scan + if: ${{ inputs.github-event-name != 'pull_request' }} uses: blackduck-inc/black-duck-security-scan@v2.1.1 - continue-on-error: false # Allow pipeline to continue even with policy violations - env: + continue-on-error: false + env: + GOPRIVATE: ${{ inputs.go-private-modules }} + DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} + DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} + DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} + with: + blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} + blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} + blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} + blackducksca_scan_full: true + detect_args: ${{ env.DETECT_ARGS }} + + # RAPID scan — pull request events only. + # Diffs against the persisted baseline so only violations *new to this PR* are reported. + - name: BlackDuck SCA PR Scan + id: blackduck-pr-scan + if: ${{ inputs.github-event-name == 'pull_request' }} + uses: blackduck-inc/black-duck-security-scan@v2.1.1 + continue-on-error: false + env: GOPRIVATE: ${{ inputs.go-private-modules }} - DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name}} #'Chef-Agents' # , Chef, Chef-Agents, Chef-Automate, Chef-Chef360, Chef-Habitat, Chef-Infrastructure-Server, Chef-Shared-Services + DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} # + DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} with: - blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ - blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY + blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} + blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} - blackducksca_scan_full: true # Force INTELLIGENT scan mode for all branches (uploads results to server) + blackducksca_scan_full: false detect_args: ${{ env.DETECT_ARGS }} - # ignore python per https://documentation.blackduck.com/bundle/detect/page/packagemgrs/python.html + github_token: ${{ secrets.GITHUB_TOKEN }} + blackducksca_prComment_enabled: true + blackducksca_fixpr_enabled: true - name: Check BlackDuck SCA results and report violations if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} From 6825dbda7b8a25119cbc3864da33f16f1902fc0f Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 18:30:04 +0530 Subject: [PATCH 07/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 28d651c..c8140d8 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -29,6 +29,11 @@ name: Download SBOM from Insights and Convert to CSV on: workflow_call: inputs: + github-event-name: + description: 'GitHub event name (pass github.event_name from calling workflow to split full vs PR scan)' + required: false + type: string + default: '' version: description: 'Version of the project' required: true From 437c7e8d388ddbfff22be5922e3c9726e009842a Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 18:39:31 +0530 Subject: [PATCH 08/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index c8140d8..eab527d 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -213,7 +213,7 @@ jobs: generate-blackduck-sbom: name: Blackduck SCA Scan (PURPLE) runs-on: ubuntu-latest - if: ${{ inputs.perform-blackduck-sca-scan == true }} + if: ${{ inputs.perform-blackduck-sca-scan == true }} steps: - name: 'Echo inputs' run: | @@ -223,6 +223,8 @@ jobs: echo "DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }}" echo "DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }}" echo "DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }}" + echo "GitHub branch: ${{ github.ref_name }}" + echo "GitHub event name (input): ${{ inputs.github-event-name }}" - name: Checkout source uses: actions/checkout@v6 @@ -349,7 +351,7 @@ jobs: blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} blackducksca_scan_full: false detect_args: ${{ env.DETECT_ARGS }} - github_token: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} blackducksca_prComment_enabled: true blackducksca_fixpr_enabled: true From c319dca329afe2ca763e4a17132e124e25e9e70c Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 18:53:19 +0530 Subject: [PATCH 09/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 76 ++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index eab527d..9a5df2a 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -353,50 +353,78 @@ jobs: detect_args: ${{ env.DETECT_ARGS }} github_token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} blackducksca_prComment_enabled: true - blackducksca_fixpr_enabled: true - name: Check BlackDuck SCA results and report violations if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | BRIDGE_LOG=".bridge/bridge.log" - + BLOCKER_COUNT=0 + CRITICAL_COUNT=0 + MAJOR_COUNT=0 + if [ ! -f "$BRIDGE_LOG" ]; then - echo "⚠️ Bridge log not found" + echo "⚠️ Bridge log not found – skipping violation count check" exit 0 fi - - SEVERITY_LINE=$(grep "Policy Severity counts:" "$BRIDGE_LOG" || true) - - if [ -z "$SEVERITY_LINE" ]; then - echo "⚠️ Policy Severity counts line not found in bridge.log" - exit 0 + + if [[ "${{ inputs.github-event-name }}" == "pull_request" ]]; then + # ── RAPID / PR scan ────────────────────────────────────────────── + # Bridge captures detect output in bridge.log, including lines like: + # INFO: --- * Components: 0 + # after the "Critical and blocking policy violations" header. + extract_count() { + local val + val=$(grep -A6 "Critical and blocking policy violations" "$BRIDGE_LOG" \ + | grep "\* ${1}:" \ + | awk '{print $NF}') + echo "${val:-0}" + } + BLOCKER_COUNT=$(extract_count "Components") + CRITICAL_COUNT=$(extract_count "Security") + MAJOR_COUNT=$(extract_count "License") + OTHER_COUNT=$(extract_count "Other") + [ "${OTHER_COUNT:-0}" -gt 0 ] && CRITICAL_COUNT=$((CRITICAL_COUNT + OTHER_COUNT)) + + else + # ── Full / INTELLIGENT scan ─────────────────────────────────────── + SEVERITY_LINE=$(grep "Policy Severity counts:" "$BRIDGE_LOG" || true) + if [ -z "$SEVERITY_LINE" ]; then + echo "⚠️ Policy Severity counts line not found in bridge.log" + exit 0 + fi + BLOCKER_COUNT=$(echo "$SEVERITY_LINE" \ + | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' \ + | grep -oE '^[0-9]+' || echo "0") + CRITICAL_COUNT=$(echo "$SEVERITY_LINE" \ + | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' \ + | grep -oE '^[0-9]+' || echo "0") + MAJOR_COUNT=$(echo "$SEVERITY_LINE" \ + | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' \ + | grep -oE '^[0-9]+' || echo "0") fi - - BLOCKER_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "$SEVERITY_LINE" | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' | grep -oE '^[0-9]+' || echo "0") - + echo "" echo "============================================" echo "BlackDuck SCA Policy Violation Summary" + echo "Scan mode: ${{ inputs.github-event-name == 'pull_request' && 'RAPID (PR)' || 'INTELLIGENT (Full)' }}" echo "============================================" - echo "BLOCKER violations: $BLOCKER_COUNT" - echo "CRITICAL violations: $CRITICAL_COUNT" - echo "MAJOR violations: $MAJOR_COUNT" + echo "BLOCKER violations: ${BLOCKER_COUNT}" + echo "CRITICAL violations: ${CRITICAL_COUNT}" + echo "MAJOR violations: ${MAJOR_COUNT}" echo "============================================" - + VIOLATIONS="" - [ "${{ inputs.blackduck-fail-on-blocker }}" == "true" ] && [ "$BLOCKER_COUNT" -gt 0 ] && VIOLATIONS="${VIOLATIONS}$BLOCKER_COUNT BLOCKER, " - [ "${{ inputs.blackduck-fail-on-critical }}" == "true" ] && [ "$CRITICAL_COUNT" -gt 0 ] && VIOLATIONS="${VIOLATIONS}$CRITICAL_COUNT CRITICAL, " - [ "${{ inputs.blackduck-fail-on-major }}" == "true" ] && [ "$MAJOR_COUNT" -gt 0 ] && VIOLATIONS="${VIOLATIONS}$MAJOR_COUNT MAJOR, " - + [ "${{ inputs.blackduck-fail-on-blocker }}" == "true" ] && [ "${BLOCKER_COUNT}" -gt 0 ] && VIOLATIONS="${VIOLATIONS}${BLOCKER_COUNT} BLOCKER, " + [ "${{ inputs.blackduck-fail-on-critical }}" == "true" ] && [ "${CRITICAL_COUNT}" -gt 0 ] && VIOLATIONS="${VIOLATIONS}${CRITICAL_COUNT} CRITICAL, " + [ "${{ inputs.blackduck-fail-on-major }}" == "true" ] && [ "${MAJOR_COUNT}" -gt 0 ] && VIOLATIONS="${VIOLATIONS}${MAJOR_COUNT} MAJOR, " + if [ -n "$VIOLATIONS" ]; then echo "" - echo "❌ Vulnerabilities Found: ${VIOLATIONS%, }" + echo "❌ Violations found: ${VIOLATIONS%, }" exit 1 else echo "" - echo "✅ No policy-violating vulnerabilities found" + echo "✅ No blocking policy violations found" fi # original from https://github.com/progress-platform-services/common-github-actions/blob/main/.github/workflows/examples/ci-all-sbom-main.yml From f82ed9c785d77703b73d8c9b0d1609bc25f1c7ae Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 19:22:00 +0530 Subject: [PATCH 10/16] debug: dump bridge.log to actions output before violation check --- .github/workflows/sbom.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 9a5df2a..c57faeb 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -354,6 +354,20 @@ jobs: github_token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} blackducksca_prComment_enabled: true + - name: Debug – dump bridge.log + if: always() + run: | + BRIDGE_LOG=".bridge/bridge.log" + if [ -f "$BRIDGE_LOG" ]; then + echo "========== bridge.log START ==========" + cat "$BRIDGE_LOG" + echo "========== bridge.log END ==========" + else + echo "bridge.log not found" + echo "Contents of .bridge/:" + ls -la .bridge/ || true + fi + - name: Check BlackDuck SCA results and report violations if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | From 756cc5000ba2dbb3cfc22e64ad2a79969a0cebcf Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Tue, 3 Mar 2026 19:28:02 +0530 Subject: [PATCH 11/16] chore: remove debug bridge.log dump step --- .github/workflows/sbom.yml | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index c57faeb..0296b8e 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -342,32 +342,18 @@ jobs: continue-on-error: false env: GOPRIVATE: ${{ inputs.go-private-modules }} - DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} + DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} #'Chef-Agents' # , Chef, Chef-Agents, Chef-Automate, Chef-Chef360, Chef-Habitat, Chef-Infrastructure-Server, Chef-Shared-Services DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} + DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} # with: - blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} - blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} + blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ + blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY blackducksca_scan_failure_severities: ${{ env.FAILURE_SEVERITIES }} blackducksca_scan_full: false detect_args: ${{ env.DETECT_ARGS }} github_token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} blackducksca_prComment_enabled: true - - name: Debug – dump bridge.log - if: always() - run: | - BRIDGE_LOG=".bridge/bridge.log" - if [ -f "$BRIDGE_LOG" ]; then - echo "========== bridge.log START ==========" - cat "$BRIDGE_LOG" - echo "========== bridge.log END ==========" - else - echo "bridge.log not found" - echo "Contents of .bridge/:" - ls -la .bridge/ || true - fi - - name: Check BlackDuck SCA results and report violations if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | @@ -377,7 +363,7 @@ jobs: MAJOR_COUNT=0 if [ ! -f "$BRIDGE_LOG" ]; then - echo "⚠️ Bridge log not found – skipping violation count check" + echo "⚠️ Bridge log not found - skipping violation count check" exit 0 fi @@ -434,11 +420,11 @@ jobs: if [ -n "$VIOLATIONS" ]; then echo "" - echo "❌ Violations found: ${VIOLATIONS%, }" + echo "❌ Vulnerabilities Found: ${VIOLATIONS%, }" exit 1 else echo "" - echo "✅ No blocking policy violations found" + echo "✅ No policy-violating vulnerabilities found" fi # original from https://github.com/progress-platform-services/common-github-actions/blob/main/.github/workflows/examples/ci-all-sbom-main.yml From 4efe2bd6bd41c5e0a2b25bbbafd17ea1ca1d540e Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Wed, 4 Mar 2026 12:43:09 +0530 Subject: [PATCH 12/16] test Signed-off-by: Vipin Yadav --- .github/workflows/ci-main-pull-request.yml | 3 ++- .github/workflows/sbom.yml | 24 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-main-pull-request.yml b/.github/workflows/ci-main-pull-request.yml index 94be0ca..0028a59 100644 --- a/.github/workflows/ci-main-pull-request.yml +++ b/.github/workflows/ci-main-pull-request.yml @@ -1464,7 +1464,8 @@ jobs: needs: checkout # TODO: fix set-application-version secrets: inherit with: - github-event-name: ${{ github.event_name }} + github-event-name: ${{ inputs.github-event-name }} + github-branch-name: ${{ inputs.github-branch-name }} version: ${{ inputs.version }} export-github-sbom: ${{ inputs.export-github-sbom }} perform-blackduck-sca-scan: ${{ inputs.perform-blackduck-sca-scan }} diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 0296b8e..c105726 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -30,7 +30,12 @@ on: workflow_call: inputs: github-event-name: - description: 'GitHub event name (pass github.event_name from calling workflow to split full vs PR scan)' + description: 'GitHub event name (pass github.event_name from calling workflow for PR comment detection)' + required: false + type: string + default: '' + github-branch-name: + description: 'GitHub branch name (pass github.ref_name from calling workflow for branch-specific logic)' required: false type: string default: '' @@ -223,8 +228,7 @@ jobs: echo "DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }}" echo "DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }}" echo "DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }}" - echo "GitHub branch: ${{ github.ref_name }}" - echo "GitHub event name (input): ${{ inputs.github-event-name }}" + echo "GitHub branch: ${{ inputs.github-branch-name }}" - name: Checkout source uses: actions/checkout@v6 @@ -354,6 +358,20 @@ jobs: github_token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} blackducksca_prComment_enabled: true + - name: Debug - dump bridge.log + if: always() + run: | + BRIDGE_LOG=".bridge/bridge.log" + if [ -f "$BRIDGE_LOG" ]; then + echo "========== bridge.log START ==========" + cat "$BRIDGE_LOG" + echo "========== bridge.log END ==========" + else + echo "bridge.log not found" + echo "Contents of .bridge/:" + ls -la .bridge/ || true + fi + - name: Check BlackDuck SCA results and report violations if: ${{ always() && (inputs.blackduck-fail-on-blocker == true || inputs.blackduck-fail-on-critical == true || inputs.blackduck-fail-on-major == true) }} run: | From d18ff2257496f964e290579ceca67ea9fc88133c Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Wed, 4 Mar 2026 13:01:25 +0530 Subject: [PATCH 13/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index c105726..98fef6d 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -329,7 +329,7 @@ jobs: GOPRIVATE: ${{ inputs.go-private-modules }} DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} + DETECT_PROJECT_VERSION_NAME: "pr-test" with: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} From ec9e4de45f2a70ca36e3c92cce0d7863999bb812 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Wed, 4 Mar 2026 13:09:10 +0530 Subject: [PATCH 14/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 98fef6d..36e5e53 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -286,6 +286,10 @@ jobs: if [[ -n "${{ inputs.ruby-app-directory }}" ]]; then DETECT_ARGS="${DETECT_ARGS} --detect.source.path=${{ inputs.ruby-app-directory }}" fi + + if [[ "${{ inputs.github-event-name }}" == "pull_request" ]]; then + DETECT_ARGS="${DETECT_ARGS} --detect.blackduck.scan.mode=RAPID" + fi echo "DETECT_ARGS=${DETECT_ARGS}" >> $GITHUB_ENV echo "Constructed detect_args: ${DETECT_ARGS}" @@ -329,7 +333,7 @@ jobs: GOPRIVATE: ${{ inputs.go-private-modules }} DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - DETECT_PROJECT_VERSION_NAME: "pr-test" + DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} with: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} @@ -346,9 +350,10 @@ jobs: continue-on-error: false env: GOPRIVATE: ${{ inputs.go-private-modules }} - DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} #'Chef-Agents' # , Chef, Chef-Agents, Chef-Automate, Chef-Chef360, Chef-Habitat, Chef-Infrastructure-Server, Chef-Shared-Services - DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} # + # DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} #'Chef-Agents' # , Chef, Chef-Agents, Chef-Automate, Chef-Chef360, Chef-Habitat, Chef-Infrastructure-Server, Chef-Shared-Services + # DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} + # DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} # + DETECT_BLACKDUCK_SCAN_MODE: RAPID with: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY From 0e08907990ca98398ad3d32225ce96d743664a13 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Wed, 4 Mar 2026 13:54:27 +0530 Subject: [PATCH 15/16] test Signed-off-by: Vipin Yadav --- .github/workflows/sbom.yml | 63 ++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 36e5e53..b9aae3a 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -277,6 +277,9 @@ jobs: # Start with base arguments (always exclude PIP detector) DETECT_ARGS="--detect.excluded.detector.types=PIP" + # Add timeout configurations to prevent FAILURE_TIMEOUT errors + DETECT_ARGS="${DETECT_ARGS} --detect.timeout=1800" + # Add low accuracy mode if requested if [[ "${{ inputs.blackduck-force-low-accuracy-mode }}" == "true" ]]; then DETECT_ARGS="${DETECT_ARGS} --detect.accuracy.required=NONE" @@ -288,6 +291,7 @@ jobs: fi if [[ "${{ inputs.github-event-name }}" == "pull_request" ]]; then + # RAPID scan for PRs - automatically compares against baseline from target branch DETECT_ARGS="${DETECT_ARGS} --detect.blackduck.scan.mode=RAPID" fi @@ -350,10 +354,10 @@ jobs: continue-on-error: false env: GOPRIVATE: ${{ inputs.go-private-modules }} - # DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} #'Chef-Agents' # , Chef, Chef-Agents, Chef-Automate, Chef-Chef360, Chef-Habitat, Chef-Infrastructure-Server, Chef-Shared-Services - # DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} - # DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} # - DETECT_BLACKDUCK_SCAN_MODE: RAPID + DETECT_PROJECT_GROUP_NAME: ${{ inputs.blackduck-project-group-name }} + DETECT_PROJECT_NAME: ${{ inputs.blackduck-project-name }} + DETECT_PROJECT_VERSION_NAME: ${{ inputs.version }} + DETECT_BLACKDUCK_RAPID_COMPARE_MODE: BOM_COMPARE with: blackducksca_url: ${{ secrets.BLACKDUCK_SBOM_URL }} # BLACKDUCK_URL, should be https://progresssoftware.app.blackduck.com/ blackducksca_token: ${{ secrets.BLACKDUCK_SCA_TOKEN }} # was BLACKDUCK_API_KEY @@ -390,46 +394,31 @@ jobs: exit 0 fi - if [[ "${{ inputs.github-event-name }}" == "pull_request" ]]; then - # ── RAPID / PR scan ────────────────────────────────────────────── - # Bridge captures detect output in bridge.log, including lines like: - # INFO: --- * Components: 0 - # after the "Critical and blocking policy violations" header. - extract_count() { - local val - val=$(grep -A6 "Critical and blocking policy violations" "$BRIDGE_LOG" \ - | grep "\* ${1}:" \ - | awk '{print $NF}') - echo "${val:-0}" - } - BLOCKER_COUNT=$(extract_count "Components") - CRITICAL_COUNT=$(extract_count "Security") - MAJOR_COUNT=$(extract_count "License") - OTHER_COUNT=$(extract_count "Other") + # Works for both RAPID and Full scans: + # - RAPID log has: "Critical and blocking policy violations" → "* Components: N", "* Security: N", etc. + # - Full log has: "Policy Severity counts:" → "N matches have a severity level of BLOCKER", etc. + extract() { grep "$1" "$BRIDGE_LOG" | awk '{print $NF}' | head -1; } + + if grep -q "Critical and blocking policy violations" "$BRIDGE_LOG"; then + # RAPID scan — map categories to severity levels + BLOCKER_COUNT=$(extract "\* Components:" || echo 0) + CRITICAL_COUNT=$(extract "\* Security:" || echo 0) + MAJOR_COUNT=$(extract "\* License:" || echo 0) + OTHER_COUNT=$(extract "\* Other:" || echo 0) [ "${OTHER_COUNT:-0}" -gt 0 ] && CRITICAL_COUNT=$((CRITICAL_COUNT + OTHER_COUNT)) - + elif grep -q "Policy Severity counts:" "$BRIDGE_LOG"; then + # Full scan + BLOCKER_COUNT=$(grep "severity level of BLOCKER" "$BRIDGE_LOG" | grep -oE '^[0-9]+' || echo 0) + CRITICAL_COUNT=$(grep "severity level of CRITICAL" "$BRIDGE_LOG" | grep -oE '^[0-9]+' || echo 0) + MAJOR_COUNT=$(grep "severity level of MAJOR" "$BRIDGE_LOG" | grep -oE '^[0-9]+' || echo 0) else - # ── Full / INTELLIGENT scan ─────────────────────────────────────── - SEVERITY_LINE=$(grep "Policy Severity counts:" "$BRIDGE_LOG" || true) - if [ -z "$SEVERITY_LINE" ]; then - echo "⚠️ Policy Severity counts line not found in bridge.log" - exit 0 - fi - BLOCKER_COUNT=$(echo "$SEVERITY_LINE" \ - | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of BLOCKER' \ - | grep -oE '^[0-9]+' || echo "0") - CRITICAL_COUNT=$(echo "$SEVERITY_LINE" \ - | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of CRITICAL' \ - | grep -oE '^[0-9]+' || echo "0") - MAJOR_COUNT=$(echo "$SEVERITY_LINE" \ - | grep -oE '[0-9]+ match(es)? ha(s|ve) a severity level of MAJOR' \ - | grep -oE '^[0-9]+' || echo "0") + echo "⚠️ No policy violation summary found in bridge.log" + exit 0 fi echo "" echo "============================================" echo "BlackDuck SCA Policy Violation Summary" - echo "Scan mode: ${{ inputs.github-event-name == 'pull_request' && 'RAPID (PR)' || 'INTELLIGENT (Full)' }}" echo "============================================" echo "BLOCKER violations: ${BLOCKER_COUNT}" echo "CRITICAL violations: ${CRITICAL_COUNT}" From 6bef7757431f950fca8d1019482ac37991266b60 Mon Sep 17 00:00:00 2001 From: Vipin Yadav Date: Thu, 5 Mar 2026 14:55:32 +0530 Subject: [PATCH 16/16] test wiz cli Signed-off-by: Vipin Yadav --- .github/workflows/ci-main-pull-request.yml | 25 +++++ .github/workflows/wiz.yml | 116 +++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 .github/workflows/wiz.yml diff --git a/.github/workflows/ci-main-pull-request.yml b/.github/workflows/ci-main-pull-request.yml index 0028a59..fa09278 100644 --- a/.github/workflows/ci-main-pull-request.yml +++ b/.github/workflows/ci-main-pull-request.yml @@ -161,6 +161,21 @@ on: required: false type: boolean default: false + perform-wiz-scan: + description: 'Perform Wiz CLI scan on Docker image' + required: false + type: boolean + default: false + wiz-fail-build: + description: 'Fail the build on Wiz policy violations' + required: false + type: boolean + default: true + wiz-image-skip-aws: + description: 'Skip AWS ECR login for Wiz image scan' + required: false + type: boolean + default: false build: description: 'CI Build (language-specific)' required: false @@ -908,6 +923,16 @@ jobs: fail-grype-on-high: ${{ inputs.grype-image-fail-on-high }} fail-grype-on-critical: ${{ inputs.grype-image-fail-on-critical }} grype-image-skip-aws: ${{ inputs.grype-image-skip-aws }} + + run-wiz-image: + name: 'Wiz CLI Docker image scan' + if: ${{ inputs.perform-wiz-scan }} + uses: chef/common-github-actions/.github/workflows/wiz.yml@test-pipeline + needs: checkout + secrets: inherit + with: + fail-build: ${{ inputs.wiz-fail-build }} + wiz-image-skip-aws: ${{ inputs.wiz-image-skip-aws }} # run-srcclr: # if: ${{ inputs.perform-srcclr-scan == true }} diff --git a/.github/workflows/wiz.yml b/.github/workflows/wiz.yml new file mode 100644 index 0000000..d3cbd92 --- /dev/null +++ b/.github/workflows/wiz.yml @@ -0,0 +1,116 @@ +# wiz.yml +# Wiz CLI security scan for Docker image vulnerabilities and policy violations +# Uses the prgs-community/githubactions-reusableworkflows/actions/wizcli composite action +# which handles Wiz CLI install, AKeyless auth, scanning, and job summary automatically. +# https://docs.wiz.io/wiz-docs/docs/wiz-cli-overview + +name: Wiz CLI security scan + +on: + workflow_call: + inputs: + fail-build: + description: 'Fail the build on Wiz policy violations' + required: false + type: boolean + default: true + wiz-image-skip-aws: + description: 'Skip AWS ECR login (assumes images are scanned elsewhere)' + required: false + type: boolean + default: false + +jobs: + wiz-scan: + name: Wiz CLI container image scan + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Configure git for private repos + run: git config --global url."https://${{ secrets.GH_TOKEN }}@github.com/".insteadOf "https://github.com/" + + # - name: Configure AWS credentials + # uses: aws-actions/configure-aws-credentials@v4 + # if: ${{ !inputs.wiz-image-skip-aws }} + # with: + # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }} + # aws-region: us-east-2 + + # - name: Login to Amazon ECR + # id: login-ecr + # if: ${{ !inputs.wiz-image-skip-aws }} + # uses: aws-actions/amazon-ecr-login@v2 + + - name: Build Docker image + id: build-image + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + run: | + REPO_NAME=$(basename $(pwd)) + + if [ ! -f "Dockerfile" ]; then + echo "❌ No Dockerfile found - this workflow requires a Dockerfile to scan Docker image" + exit 1 + fi + + echo "Building Docker image..." + + # Strategy 1: Check for build-docker.sh script (e.g., dsm-erchef) + if [ -f "build-docker.sh" ]; then + echo "Found build-docker.sh script - using it to build images" + chmod +x build-docker.sh + GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" ./build-docker.sh + + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -E "^${REPO_NAME}" | grep -v "^" | head -1) + + if [ -z "$IMAGE" ]; then + echo "⚠️ No image found with prefix ${REPO_NAME} after build-docker.sh" + echo "Checking for any recently built images..." + IMAGE=$(docker images --format "{{.CreatedAt}}\t{{.Repository}}:{{.Tag}}" | sort -r | head -1 | cut -f2) + fi + # Strategy 2: Check for Makefile with compose-build target + elif [ -f "Makefile" ] && grep -q "^compose-build:" Makefile; then + echo "Using Makefile compose-build target with GITHUB_TOKEN" + export GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" + make compose-build + + echo "Detecting built image..." + docker compose images + + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${REPO_NAME}" | grep -v "^" | head -1) + + if [ -z "$IMAGE" ]; then + echo "No image found with prefix ${REPO_NAME}, using most recent image" + IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "^" | head -1) + fi + # Strategy 3: Fallback to standard docker build + else + echo "Using standard docker build with GITHUB_TOKEN build arg" + docker build --build-arg GITHUB_TOKEN="${{ secrets.GH_TOKEN }}" -t "${REPO_NAME}:latest" . + IMAGE="${REPO_NAME}:latest" + fi + + if [ -z "$IMAGE" ]; then + echo "❌ No Docker image found after build" + exit 1 + fi + + echo "Image to scan: $IMAGE" + echo "IMAGE=$IMAGE" >> "$GITHUB_OUTPUT" + + - name: Wiz CLI container image scan + id: wiz-scan + uses: prgs-community/githubactions-reusableworkflows/actions/wizcli@latest + with: + scan-type: 'container-image' + scan-target: ${{ steps.build-image.outputs.IMAGE }} + fail-build: ${{ inputs.fail-build }}